printf and creating custom stdout and stdin routines.

Discussion about other targets
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

Neuxsone1984 wrote:Maybe one other thing I am missing, I sort of expected the code to be set for 32 Characters X 16 Rows for my terminal to be the whole display. I understand about having a virtual screen to work in. But to start do I need to make a call to set the display to 32 X 16? If so where to I set the Window width and height?
It happens in the terminal instantiation.

This instantiation macros are included into the crt when the example is built:
https://github.com/z88dk/z88dk/blob/mas ... ion.asm.m4

The macros statically create the data structures required by the drivers and build up the file descriptor table as demanded. In the instantiation of your driver:

Code: Select all

   ;# fd=1, stdout

   include(`terminal/term_01_output_char.m4')dnl
   m4_term_01_output_char(_stdout, 0x2370, 0, 0, 0, 32, 0, 16, 0)dnl

   ;# m4_term_01_output_char(file, flags, cursor.x, cursor.y, window.x, window.width, window.y, window.height, scroll limit)
   ;#   flags:
   ;#   bit 13 = (page mode) 1 = clear on full screen, 0 = wrap on full screen
   ;#   bit  9 = enable signal bell
   ;#   bit  8 = enable bell
   ;#   bit  7 = page mode (1) or scroll mode (0)
   ;#   bit  6 = enable pause on full screen
   ;#   bit  5 = cook output chars
   ;#   bit 4 = enable crlf conversion (c side \n -> \r\n)
you can pass in the default settings as arguments. So here you can see the terminal window is initially 32x16. This can be changed at runtime with an ioct. You can also create multiple windows on screen assigned to different file descriptors / FILE* by instantiating the same macro a few more times.
Neuxsone1984
Member
Posts: 30
Joined: Fri Feb 10, 2017 3:36 pm

Post by Neuxsone1984 »

It's the weekend got your code in and works, except for one thing is happening.

The scroll only moves the bottom line up to the next line. 16 to 15, 14-1 stays the same when printing at the bottom.

Here is the code maybe I missed something when I copied your code.

SECTION code_driver
SECTION code_driver_terminal_output

PUBLIC term_01_output_char_oterm_msg_scroll

EXTERN _mybuffer
EXTERN term_01_output_char_oterm_msg_cls

term_01_output_char_oterm_msg_scroll:

; * OTERM_MSG_SCROLL
;
; enter : c = number of rows to scroll
; can use: af, bc, de, hl
;
; Scroll the window upward 'c' character rows.

; At this point:
;
; ix+16 = window.x
; ix+17 = window.width
; ix+18 = window.y
; ix+19 = window.height
;
; Note that for an SDCC_IY compile, ix and iy have been swapped.

ld a,c ; a = scroll_amount

IF __SDCC_IY
cp (iy+19)
ELSE
cp (ix+19) ; compare with max height of terminal
ENDIF
jp nc, term_01_output_char_oterm_msg_cls

add a,a
add a,a
add a,a
add a,a ; max 16*(lcd_height-1=15) = 240
ld l,a
ld h,0
add hl,hl
ex de,hl ; de = 32 * scroll_amount

IF __SDCC_IY
ld a,(iy+18)
add a,(iy+19)
ELSE
ld a,(ix+18) ; window.y
add a,(ix+19) ; + window.height
ENDIF
sub c ; - scroll_amount
add a,a
add a,a
add a,a
add a,a ; max 16*(lcd_height-1=15) = 240
ld b,a
ld hl,_mybuffer
add a,l
ld l,a
adc a,h
sub l
ld h,a
ld a,b
IF __SDCC_IY
add a,(iy+16)
ELSE
add a,(ix+16) ; + window.x
ENDIF
add a,l
ld l,a
adc a,h
sub l
ld h,a ; hl = mybuffer + (window.y + window.height
; - scroll_amount)*32 + window.x

push hl

xor a
sbc hl,de
ex de,hl

pop hl

ld a,32
IF __SDCC_IY
sub (iy+17)
ELSE
sub (ix+17) ; - window.width
ENDIF
ld b,a
ld a,c ; a = scroll_amount
ld c,b
ld b,0 ; bc = 32 - window.width

; a = scroll_amount
; bc = 32 - window.width
; hl = mybuffer + (window.y + window.height - scroll_amount)*32 + window.x (source)
; de = hl - scroll_amount*32 (destination)

loop_y:

push bc
IF __SDCC_IY
ld c,(iy+17)
ELSE
ld c,(ix+17) ; bc = window.width
ENDIF

loop_x:

ldi ; copy one byte
dec hl
ld (hl),32 ; print space at source byte
inc hl
jp pe, loop_x

pop bc ; bc = 32 - window.width

ex de,hl
add hl,bc ; adjust downward one row

ex de,hl
add hl,bc ; adjust downward one row

dec a ; scroll_amount--
jr nz, loop_y

; now output buffer to the lcd sending the address to put each character on the display.
ld bc, 0x0200 ; characters to move
ld de, 0x0000 ; display start address
ld hl,_mybuffer
send_buffer:
ld a, 0x46 ; command that Character data address is being sent
out (0x21), a
ld a,e
out (0x20), a
ld a,d
out (0x20), a
ld a, 0x42 ; command that Character data is being sent
out (0x21), a
ld a, (hl)
out (0x20), a
inc hl
inc de
dec bc
ld a, b
or c
jp NZ, send_buffer
ret
Neuxsone1984
Member
Posts: 30
Joined: Fri Feb 10, 2017 3:36 pm

Post by Neuxsone1984 »

Just to let you know, while yours is not working correctly, did finally get mine right, and scrolls up one correctly
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

Nice you got it to work. It will work with one window covering the full screen.
The code I wrote above is wrong.. I do have some partially written that I will post when it is finished that will allow multiple windows.

What sort of keyboard device are you using? Maybe we can get stdin done for some interaction.
Neuxsone1984
Member
Posts: 30
Joined: Fri Feb 10, 2017 3:36 pm

Post by Neuxsone1984 »

Right now working on code to read PS/2 Keyboard, first trying to decode it software only. I am using two pins of the Z80 PIO, the interrupt is triggered when both Clock and data go low to indicate the start of a byte transfer. I am running a 4Mhz, need to do a timing check, on time of interrupt trigger to time entering the routine, that it is fast enough to catch the start of the bit. Other option is looking at using a shift register and some logic to read in the keyboard.

The other option is since I have only a Z80 PIO is to use it's handshake transfer mode(which I like to test out for my Z80 PIO library functions, via my programming board do a byte or bit transfer, that way don't have worry about timing. I can write a routine to send keyboard presses to the board from a shell window.
Neuxsone1984
Member
Posts: 30
Joined: Fri Feb 10, 2017 3:36 pm

Post by Neuxsone1984 »

Since my last post, have the beginnings of a PS/2 Keyboard interface, a 74LS74 and a 74LS595 shift register, with parallel out of the shift register going to a port on my Z80 PIO. Right now getting good results on reading the codes from the keyboard, I using the 74LS74 as a two bit shift register that strips the parity and stop bits off. So only left in the 595 is the data portion of the data sent. I next would be to use a few bits of the other port to trip the interrupt when the keyboard sends a character.

Here is some thoughts, maybe is how you would do it. Is just grab the character data, push it into a buffer to make the service routine fast. Then on getc do the PS/2 key map conversion to ASCII and strip control characters. I need to create a conversion table in a include file next.

And thanks for all the Help.
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

Neuxsone1984 wrote:Here is some thoughts, maybe is how you would do it. Is just grab the character data, push it into a buffer to make the service routine fast. Then on getc do the PS/2 key map conversion to ASCII and strip control characters. I need to create a conversion table in a include file next.
Yes sounds ok, although I would keep it outside stdio as it could be used generally. For example, there is an input.h library in z88dk that is meant to be able to test the instantaneous state of the keyboad (for games, amongst other things) so it implements things like in_inkey(), in_keyPressed() etc. These could look at the current ps2 map button state (currently pressed / not pressed) to find out the state of the keyboard.

But anyway first thing is to get some kind of keyboard input working. There are two kinds of ways keys are read by the library driver. One is some code or device simply supplies a stream of ascii codes. The other is a primitive key source where the library code looks at button state (up/down) and to find key press and implements things like autorepeat.

I'll add the ascii code driver skeleton to the example later today.
Neuxsone1984
Member
Posts: 30
Joined: Fri Feb 10, 2017 3:36 pm

Post by Neuxsone1984 »

I got the interrupt driven routine working, grabs a character puts it into a buffer raw from the keyboard.

I made routine and a map to covert the basic keyboard codes to ascii codes, I just ignore the key make/break codes. So if I had just the starting frame work for getc from stdin, can supply the basic ascii codes, and could map some control codes if needed.

One of the questions some ideas on how to handle key pressed and released, and if multiple keys have been pressed, shift, etc.

Should this be a diver thing? Not sure if we care if right or left shift key pressed, maybe a bit state.
Shift_state(one or the other is down or both) , Cap_lock_state, ctrl_state, alt_state, etc,
Then I thinking you would have down so long repeat character and rate of repeating the character while pressed.

I may work on a map to hold the state of the keys, did they get pressed or released state.

Could thing would be once we have the stdin working at the asccii level, a basic screen Terminal, type Characters, scroll next line with Enter key. Later add advance stuff like using arrow keys. Again thanks for help, I had created a FB group when I started this project, just got up to 248 members talking all things Z80, hope that this will help a few others who want to build from scratch. Besides a Terminal screen, get something like Tiny Basic to run on this generic setup.

I been working on and off this weekend as time permits on the project.
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

I've added the input terminal instantiation to the example code here:
https://github.com/z88dk/z88dk/tree/mas ... /z80/stdio

As before some subroutines have to be provided to customize for your hardware, all in the terminal/term_01_input_char directory:
https://github.com/z88dk/z88dk/tree/mas ... input_char
One of the questions some ideas on how to handle key pressed and released, and if multiple keys have been pressed, shift, etc.

Should this be a diver thing? Not sure if we care if right or left shift key pressed, maybe a bit state.
Shift_state(one or the other is down or both) , Cap_lock_state, ctrl_state, alt_state, etc,
Then I thinking you would have down so long repeat character and rate of repeating the character while pressed.
There are actually two interfaces to the keyboard in z88dk. One interface is in input.h and this deals with the instantaneous state of the keyboard. So it has functions like in_key_pressed() that can tell if a specific key is pressed even if many are pressed simultaneously. This would fit in with a keymap. There is also a keyboard joystick that tests the state of four keys and a fire button using a similar idea and there are functions testing if any key is pressed or if no key is pressed. There is also an in_inkey() in this library that looks at the instantaneous state of the keyboard and returns a single ascii code if exactly one key is pressed (and indicating no keys pressed otherwise).

The terminal driver I gave above is for something like a serial connection where there's a pc keyboard at the other end sending ascii codes and it is already implementing key repeat and all that at its end. However, there is another terminal driver in the library that uses in_inkey() to look at keyboard state and it will do key repeat, etc as well. If you want to go this route I can pull out that driver too if you implement in_inkey() from input.h. in_inkey() would look at the key state of modifiers like shift and ctrl to change the ascii code it returns.
Could thing would be once we have the stdin working at the asccii level, a basic screen Terminal, type Characters, scroll next line with Enter key. Later add advance stuff like using arrow keys. Again thanks for help, I had created a FB group when I started this project, just got up to 248 members talking all things Z80, hope that this will help a few others who want to build from scratch. Besides a Terminal screen, get something like Tiny Basic to run on this generic setup.
It should be close now. There is a tty layer you can put on top of the basic output terminal you have now that can do cursor movements, etc, from codes in the output stream. If you can address pixels on the lcd there's also an output terminal that can do proportional text.
Neuxsone1984
Member
Posts: 30
Joined: Fri Feb 10, 2017 3:36 pm

Post by Neuxsone1984 »

Thanks for your help, still working on the PS2 Keyboard routine. Let you know when I have it going.

Just a side question, I am building a I/O library for say Z80 PIO, future SIO, CTC, DUART, SOUND chip, etc is there some recommended format to allow it to be open.

example: be it a Z80 PIO or the 8255, or similar device setup in a way that you have some universal commands from C.
Maybe have Arduino style commands. PIO_pin_D0_on or PIO_pin_D0_off. That one need only system define file which device one is using.

The same with a terminal library for SIO serial device, that you need only supply address of device and type. Then in the program the low level stuff is transparent to the programmer. That way you could have things like for supported devices a Baud command, send and receive would be standard I/O.

That is my goal is someone says, I have a Z80 system, with X ROM, X RAM, the following devices at X location. They can build a working system with very little of having to build new libraries themselves.

Which I think you could do most of it now is copy the _DEVELOPMENT/Z80 directory to a new named one of your project. Go in plug in a the information of what you have in your system.

Here is my Z80 PIO library not 100% complete but gives an idea of what I doing.

/* Z80_IO.h */
/* Z80 IO DEF */


/* define logic mask */

#define Bit_mask0 0b00000001
#define Bit_mask1 0b00000010
#define Bit_mask2 0b00000100
#define Bit_mask3 0b00001000
#define Bit_mask4 0b00010000
#define Bit_mask5 0b00100000
#define Bit_mask6 0b01000000
#define Bit_mask7 0b10000000


// User system Define Z80 PIO location
#define Z80_PIO_A 0x00 // Port A
#define Z80_PIO_B 0x01 // Port B
#define Z80_PIO_A_CTL 0x02 // Port Control A
#define Z80_PIO_B_CTL 0x03 // Port Control B

// Z80 PIO Mode define
#define Z80_PIO_M0 0x0f // Mode 0 Port is output only
#define Z80_PIO_M1 0x4f // Mode 1 Port is input only
#define Z80_PIO_M2 0x8f // Mode 2 Port is Bidirectonal operation
#define Z80_PIO_M3 0xCf // Mode 3 Port is port direction can be
// set per bit via direction mask.
// this command expects a mask byte to follow
// 0 bit = output and 1 bit = input
//



// Z80 PIO interruot setup

#define Z80_PIO_EI 0x87 // Enable PIO interrupts
// The following bit wise OR with above

// Mode 3 interrupt options
// Bit D5 Look for port to be High or low state.
// where set to 0 for low, 1 for high
// Bit D6 AND/OR state, AND all ports must be in
// active state, or only one need be in active state
// for interrupt. Bit D4 is mask byte to follow,
// Bit set to 1 that port bit is ignored, 0 watch port bit.


#define Z80_PIO_EI_MF 0b00010000 // Mask follows command
#define Z80_PIO_EI_AND 0b01000000 // AND Bits
#define Z80_PIO_EI_OR 0b00000000 // OR Bits
#define Z80_PIO_EI_HIGH 0b00100000 // HIGH Transistion triggers
#define Z80_PIO_EI_LOW 0b00000000 // LOW Transistion triggers



#define Z80_PIO_DI 0x07 // Disable PIO interrupts

// Z80 PIO 0 address
__sfr __at 0x00 Z80PIOA;
__sfr __at 0x01 Z80PIOB;
__sfr __at 0x02 Z80PIOA_REG;
__sfr __at 0x03 Z80PIOB_REG;

extern void z80_io_write( unsigned char port, unsigned char data);
extern unsigned char z80_io_read( unsigned char port);

void z80_pio_write_bit(unsigned char port, unsigned char bit, unsigned bit_state);
unsigned char z80_pio_read_bit(unsigned char port, unsigned char bit);
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

Yeah this is an idea being considered.

Currenty a particular target defines io ports, etc, in its config directory. The yaz180 has a lot as does the zxn target. As an example:
https://github.com/z88dk/z88dk/tree/mas ... zxn/config

The *.m4 contain configuration information. The file config_zxn_uart.m4 ( https://github.com/z88dk/z88dk/blob/mas ... xn_uart.m4 ) defines some io ports and bits for the uart device. When the target library is built, all the config file defines are made available to the program through the include file <arch.h> in C or through EXTERN for asm (and also include "config_private.inc" for the defines instead of link time resolution). The built defines can be found in the target's main directory ( https://github.com/z88dk/z88dk/tree/mas ... target/zxn ) as config_zxn_private.inc and config_zxn.h in this example.

Then the library supplies code for these devices.

The thing we'd like to do is provide macros for common devices that can generate code for different io ports. The same macro could be used for multiple devices on different ports. The mechanism for macros is already there. If you add .m4 to the end of a filename, zcc will expand the macro before processing the file. So an implementation could be in foo.asm.m4, the library would instantiate the driver with io ports from the config and when the library is built, the driver would show up with proper ports filled in.

Then the issue of integrating into stdio is there too. Doing it statically in the crt where drivers are put onto file descriptors can be easily done just like stdin, stdout, stderr are currently done. But we'd like to be able to dynamically open and close files during program execution and that's not in the newlib yet because that's waiting for the disk io to be integrated before it can be done. An open would go through a directory hierarchy of devices like in unix and then land on a device name. The rest of the open string would be passed to the device open function and that string could contain anything, like parameters for serial communication so that the device could initialize itself in the open call. Changes could be done with ioctl messages.

Anyway that's the direction.
Post Reply