From d5765af82392678756512cba1340a13e6a9476f1 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 1 Oct 2018 22:53:35 +0100 Subject: [PATCH] sc108: flesh out all the serial support We still don't support full RTS/CTS but really the I/O paths for SIO handling need to be rewritten to fast asm helpers anyway. --- Kernel/platform-sc108/devtty.c | 145 ++++++++++++++- Kernel/platform-sc108/rc2014.h | 2 + Kernel/platform-sc108/sc108.s | 330 ++++++++++++++++----------------- 3 files changed, 297 insertions(+), 180 deletions(-) diff --git a/Kernel/platform-sc108/devtty.c b/Kernel/platform-sc108/devtty.c index c60736fd..3f2f6da1 100644 --- a/Kernel/platform-sc108/devtty.c +++ b/Kernel/platform-sc108/devtty.c @@ -11,52 +11,177 @@ char tbuf2[TTYSIZ]; uint8_t ser_type = 2; +tcflag_t uart0_mask[4] = { + _ISYS, + _OSYS, + CSIZE|CSTOPB|PARENB|PARODD|_CSYS, + _LSYS +}; + +tcflag_t uart1_mask[4] = { + _ISYS, + /* FIXME: break */ + _OSYS, + /* FIXME CTS/RTS */ + CSIZE|CBAUD|CSTOPB|PARENB|PARODD|_CSYS, + _LSYS, +}; + +tcflag_t *termios_mask[NUM_DEV_TTY + 1] = { + NULL, + uart0_mask, + uart1_mask +}; + struct s_queue ttyinq[NUM_DEV_TTY + 1] = { /* ttyinq[0] is never used */ {NULL, NULL, NULL, 0, 0, 0}, {tbuf1, tbuf1, tbuf1, TTYSIZ, 0, TTYSIZ / 2}, {tbuf2, tbuf2, tbuf2, TTYSIZ, 0, TTYSIZ / 2}, }; +uint8_t sio_r[] = { + 0x03, 0xC1, + 0x04, 0xC4, + 0x05, 0xEA +}; + +static void sio2_setup(uint8_t minor, uint8_t flags) +{ + struct termios *t = &ttydata[minor].termios; + uint8_t r; + /* Set bits per character */ + sio_r[1] = 0x01 | ((t->c_cflag & CSIZE) << 2); + r = 0xC4; + if (t->c_cflag & CSTOPB) + r |= 0x08; + if (t->c_cflag & PARENB) + r |= 0x01; + if (t->c_cflag & PARODD) + r |= 0x02; + sio_r[3] = r; + sio_r[5] = 0x8A | ((t->c_cflag & CSIZE) << 1); +} + void tty_setup(uint8_t minor, uint8_t flags) { - if (minor == 1) { + if (ser_type == 1) { + sio2_setup(minor, flags); + sio2_otir(SIO0_BASE + 2 * minor); + /* We need to do CTS/RTS support and baud setting on channel 2 + yet */ + } + if (ser_type == 2) { + struct termios *t = &ttydata[1].termios; + uint8_t r = t->c_cflag & CSIZE; + /* No CS5/CS6 CS7 must have parity enabled */ + if (r <= CS7) { + t->c_cflag &= ~CSIZE; + t->c_cflag |= CS7|PARENB; + } + /* No CS8 parity and 2 stop bits */ + if (r == CS8 && (t->c_cflag & PARENB)) + t->c_cflag &= ~CSTOPB; + /* There is no obvious logic to this */ + switch(t->c_cflag & (CSIZE|PARENB|PARODD|CSTOPB)) { + case CS7|PARENB: + r = 0xEB; + break; + case CS7|PARENB|PARODD: + r = 0xEF; + break; + case CS7|PARENB|CSTOPB: + r = 0xE3; + case CS7|PARENB|PARODD|CSTOPB: + r = 0xE7; + case CS8|CSTOPB: + r = 0xF3; + break; + case CS8: + r = 0xF7; + break; + case CS8|PARENB: + r = 0xFB; + break; + case CS8|PARENB|PARODD: + r = 0xFF; + break; + } + ACIA_C = r; } } int tty_carrier(uint8_t minor) { -// uint8_t c; - if (minor == 1) { -// c = UART0_MSR; -// return (c & 0x80) ? 1 : 0; /* test DCD */ - } - return 1; + uint8_t c; + if (ser_type == 1) { + if (minor == 1) { + SIOA_C = 0; + c = SIOA_C; + } else { + SIOB_C = 0; + c = SIOB_C; + } + if (c & 0x8) + return 1; + return 0; + } else /* ACIA isn't wired for carrier on any bord */ + return 1; } void tty_pollirq_sio(void) { + static uint8_t old_ca, old_cb; uint8_t ca, cb; + uint8_t progress; + + /* Check for an interrupt */ + SIOA_C = 0; + if (!(SIOA_C & 2)) + return; /* FIXME: need to process error/event interrupts as we can get spurious characters or lines on an unused SIO floating */ do { + progress = 0; SIOA_C = 0; // read register 0 ca = SIOA_C; - if (ca & 1) + /* Input pending */ + if ((ca & 1) && !fullq(&ttyinq[1])) { + progress = 1; tty_inproc(1, SIOA_D); + } + /* Break */ + if (ca & 2) + SIOA_C = 2 << 5; + /* Output pending */ if (ca & 4) { tty_outproc(1); SIOA_C = 5 << 3; // reg 0 CMD 5 - reset transmit interrupt pending } + /* Carrier changed */ + if ((ca ^ old_ca) & 8) { + if (ca & 8) + tty_carrier_raise(1); + else + tty_carrier_drop(1); + } SIOB_C = 0; // read register 0 cb = SIOB_C; - if (cb & 1) + if ((cb & 1) && !fullq(&ttyinq[2])) { tty_inproc(2, SIOB_D); + progress = 1; + } if (cb & 4) { tty_outproc(2); SIOB_C = 5 << 3; // reg 0 CMD 5 - reset transmit interrupt pending } - } while((ca | cb) & 1); + if ((cb ^ old_cb) & 8) { + if (cb & 8) + tty_carrier_raise(2); + else + tty_carrier_drop(2); + } + } while(progress); } void tty_pollirq_acia(void) diff --git a/Kernel/platform-sc108/rc2014.h b/Kernel/platform-sc108/rc2014.h index fffce867..21ee491c 100644 --- a/Kernel/platform-sc108/rc2014.h +++ b/Kernel/platform-sc108/rc2014.h @@ -20,4 +20,6 @@ __sfr __at (SIO0_BASE + 3) SIOB_D; __sfr __at (ACIA_BASE + 0) ACIA_C; __sfr __at (ACIA_BASE + 1) ACIA_D; +extern void sio2_otir(uint8_t port) __z88dk_fastcall; + #endif diff --git a/Kernel/platform-sc108/sc108.s b/Kernel/platform-sc108/sc108.s index fd639b3c..e6bb0e56 100644 --- a/Kernel/platform-sc108/sc108.s +++ b/Kernel/platform-sc108/sc108.s @@ -1,42 +1,42 @@ ; -; SC108 Initial Support +; SC108 Initial Support ; - .module sc108 - - ; exported symbols - .globl init_hardware - .globl interrupt_handler - .globl _program_vectors - .globl _kernel_flag - .globl map_page_low - .globl map_kernel_low - .globl map_user_low - .globl map_save_low - .globl map_restore_low - .globl _platform_doexec - .globl _platform_reboot - .globl _int_disabled - - ; exported debugging tools - .globl _platform_monitor - .globl outchar - - ; imported symbols - .globl _ramsize - .globl _procmem - .globl istack_top - .globl istack_switched_sp - .globl kstack_top - .globl unix_syscall_entry - .globl outcharhex - .globl _ser_type - - .globl s__COMMONMEM - .globl l__COMMONMEM - - .include "kernel.def" - .include "../kernel.def" + .module sc108 + + ; exported symbols + .globl init_hardware + .globl interrupt_handler + .globl _program_vectors + .globl _kernel_flag + .globl map_page_low + .globl map_kernel_low + .globl map_user_low + .globl map_save_low + .globl map_restore_low + .globl _platform_doexec + .globl _platform_reboot + .globl _int_disabled + + ; exported debugging tools + .globl _platform_monitor + .globl outchar + + ; imported symbols + .globl _ramsize + .globl _procmem + .globl istack_top + .globl istack_switched_sp + .globl kstack_top + .globl unix_syscall_entry + .globl outcharhex + .globl _ser_type + + .globl s__COMMONMEM + .globl l__COMMONMEM + + .include "kernel.def" + .include "../kernel.def" ; @@ -44,11 +44,11 @@ ; so we can recover the discard memory into the buffer pool ; - .globl _bufpool - .area _BUFFERS + .globl _bufpool + .area _BUFFERS _bufpool: - .ds BUFSIZE * NBUFS + .ds BUFSIZE * NBUFS ; ----------------------------------------------------------------------------- ; @@ -56,17 +56,17 @@ _bufpool: ; usual Z80 setup. ; ; ----------------------------------------------------------------------------- - .area _COMMONMEM + .area _COMMONMEM _platform_monitor: ; Reboot ends up back in the monitor _platform_reboot: - xor a - out (0x38), a ; ROM appears low - rst 0 ; bang + xor a + out (0x38), a ; ROM appears low + rst 0 ; bang _int_disabled: - .db 1 + .db 1 ; ----------------------------------------------------------------------------- ; @@ -76,7 +76,7 @@ _int_disabled: ; ----------------------------------------------------------------------------- banknum: - .byte 0x81 ; copied into far bank then set to 1 + .byte 0x81 ; copied into far bank then set to 1 ; ----------------------------------------------------------------------------- ; All of discard gets reclaimed when init is run @@ -84,135 +84,112 @@ banknum: ; Discard must be above 0x8000 as we need some of it when the ROM ; is paged in during init_hardware ; ----------------------------------------------------------------------------- - .area _DISCARD + .area _DISCARD init_hardware: - ld hl, #128 - ld (_ramsize), hl - ld hl,#64 - ld (_procmem), hl - - ld hl,#s__COMMONMEM - ld ix,#s__COMMONMEM - ld bc,#l__COMMONMEM - xor a ; Kernel + ROM - out (0x38),a ; - - ld de,#0x8000 ; bank 0 to bank 1 (ROM in) - xor a ; return to bank 0 - call 0x7FFD ; ROM helper vector - - ld a,#0x01 ; bank 0 ROM out - out (0x38),a - ld (banknum),a ; and correct page - - ; We now have our common in place. We can do the rest ourselves - - ; Put the low stubs into place in the kernel - ld hl,#stubs_low - ld de,#0 - ld bc,#0x68 - ldir - ld hl,#stubs_low - ld ix,#0 - ld bc,#0x68 - call ldir_to_user - - ; Play guess the serial port - ld bc,#0x80 - ; If writing to 0x80 changes the data we see on an input then - ; it's most likely an SIO and not the 68B50 - out (c),b - in d,(c) - inc b - out (c),b - in a,(c) - sub d -;;FIXME jr z, is_sio - - ; We have however pooped on the 68B50 setup so put it back into - ; a sensible state. - ld a,#0x03 - out (c),a - in a,(c) - or a - jr z, not_acia_either - ld a, #ACIA_RTS_LOW_A - out (c),a ; Initialise ACIA - ld a,#2 - ld (_ser_type),a - im 1 - ret - - ; - ; Doomed I say .... doomed, we're all doomed - ; - ; At least until RC2014 grows a nice keyboard/display card! - ; + ld hl, #128 + ld (_ramsize), hl + ld hl,#64 + ld (_procmem), hl + + ld hl,#s__COMMONMEM + ld ix,#s__COMMONMEM + ld bc,#l__COMMONMEM + xor a ; Kernel + ROM + out (0x38),a ; + + ld de,#0x8000 ; bank 0 to bank 1 (ROM in) + xor a ; return to bank 0 + call 0x7FFD ; ROM helper vector + + ld a,#0x01 ; bank 0 ROM out + out (0x38),a + ld (banknum),a ; and correct page + + ; We now have our common in place. We can do the rest ourselves + + ; Put the low stubs into place in the kernel + ld hl,#stubs_low + ld de,#0 + ld bc,#0x68 + ldir + ld hl,#stubs_low + ld ix,#0 + ld bc,#0x68 + call ldir_to_user + + ; Play guess the serial port + ; This needs doing better. We might be fooled by floating flow + ; control lines as the SC104 does expose flow control. FIXME + in a,(SIOA_C) + and #0x2C + cp #0x2C + ; CTS and DCD should be high as they are not wired + jr nz, try_acia + + ; Repeat the check on SIO B + in a,(SIOB_C) + and #0x2C + cp #0x2C + jr z, is_sio +try_acia: + ; + ; Look for an ACIA + ; + ld a,#ACIA_RESET + out (ACIA_C),a + ; TX should now have gone + in a,(ACIA_C) + bit 1,a + jr z, not_acia_either + ; Set up the ACIA + + ld a, #ACIA_RTS_LOW_A + out (ACIA_C),a ; Initialise ACIA + ld a,#2 + ld (_ser_type),a + jp serial_up + + ; + ; Doomed I say .... doomed, we're all doomed + ; + ; At least until RC2014 grows a nice keyboard/display card! + ; not_acia_either: - xor a - ld (_ser_type),a - ret - -is_sio: ld a,b - ld (_ser_type),a - -init_partial_uart: - ld a,#0x00 - out (SIOA_C),a - ld a,#0x18 - out (SIOA_C),a - - ld a,#0x04 - out (SIOA_C),a - ld a,#0xC4 - out (SIOA_C),a - - ld a,#0x01 - out (SIOA_C),a - ld a,#0x18;A? ; Receive int mode 11, tx int enable (was $18) - out (SIOA_C),a - - ld a,#0x03 - out (SIOA_C),a - ld a,#0xE1 - out (SIOA_C),a - -RTS_LOW .EQU 0xEA - - ld a,#0x05 - out (SIOA_C),a - ld a,#RTS_LOW - out (SIOA_C),a - - ld a,#0x00 - out (SIOB_C),a - ld a,#0x18 - out (SIOB_C),a - - ld a,#0x04 - out (SIOB_C),a - ld a,#0xC4 - out (SIOB_C),a - - ld a,#0x01 - out (SIOB_C),a - ld a, #0x18;A? ; Receive int mode 11, tx int enable (was $18) - out (SIOB_C),a - - ld a,#0x03 - out (SIOB_C),a - ld a,#0xE1 - out (SIOB_C),a - - ld a,#0x05 - out (SIOB_C),a - ld a,#RTS_LOW - out (SIOB_C),a - - im 1 ; set CPU interrupt mode + xor a + ld (_ser_type),a + jp serial_up +; +; We have an SIO so do the required SIO hdance +; +is_sio: ld a,b + ld (_ser_type),a + + ld hl,#sio_setup + ld bc,#0xA00 + SIOA_C ; 10 bytes to SIOA_C + otir + ld hl,#sio_setup + ld bc,#0x0A00 + SIOB_C ; and to SIOB_C + otir + +serial_up: + im 1 ; set CPU interrupt mode + ret + +RTS_LOW .EQU 0xEA + +sio_setup: + .byte 0x00 + .byte 0x18 ; Reset + .byte 0x04 + .byte 0xC4 + .byte 0x01 + .byte 0x18 + .byte 0x03 + .byte 0xE1 + .byte 0x05 + .byte RTS_LOW - ret ; ; Our memory setup is weird and common is kind of meaningless here @@ -230,6 +207,19 @@ map_page_low: _program_vectors: ret + +; +; A little SIO helper +; + .globl _sio_r + .globl _sio2_otir + +_sio2_otir: + ld b,#0x06 + ld c,l + ld hl,#_sio_r + otir + ret ; ; outchar: Wait for UART TX idle, then print the char in A ; destroys: AF -- 2.34.1