From: Alan Cox Date: Wed, 9 Jan 2019 19:27:50 +0000 (+0000) Subject: linc80: tty updates X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=866393958e4b23945287f1053743f25630e6704a;p=FUZIX.git linc80: tty updates --- diff --git a/Kernel/platform-linc80/config.h b/Kernel/platform-linc80/config.h index a876a5f1..79e15490 100644 --- a/Kernel/platform-linc80/config.h +++ b/Kernel/platform-linc80/config.h @@ -14,7 +14,7 @@ #define CONFIG_LARGE_IO_DIRECT(x) 1 /* One memory bank */ #define CONFIG_BANKS 1 -#define TICKSPERSEC 10 /* Ticks per second */ +#define TICKSPERSEC 40 /* Ticks per second */ #define PROGBASE 0x8000 /* also data base */ #define PROGLOAD 0x8000 /* also data base */ #define PROGTOP 0xFFFF /* Top of program */ diff --git a/Kernel/platform-linc80/devtty.c b/Kernel/platform-linc80/devtty.c index 97119bcc..f3b745c2 100644 --- a/Kernel/platform-linc80/devtty.c +++ b/Kernel/platform-linc80/devtty.c @@ -11,7 +11,7 @@ static char tbuf2[TTYSIZ]; static tcflag_t uart_mask[4] = { _ISYS, _OSYS, - CSIZE|CSTOPB|CBAUD|PARENB|PARODD|_CSYS, + CSIZE|CSTOPB|CBAUD|PARENB|PARODD|CRTSCTS|_CSYS, _LSYS }; @@ -33,6 +33,8 @@ uint8_t sio_r[] = { 0x05, 0xEA }; +static uint8_t sleeping; + static void sio2_setup(uint8_t minor, uint8_t flags) { used(flags); @@ -50,10 +52,8 @@ static void sio2_setup(uint8_t minor, uint8_t flags) r |= 0x02; sio_r[3] = r; sio_r[5] = 0x8A | ((t->c_cflag & CSIZE) << 1); - if (minor == 1) - sio2a_wr5 = sio_r[5]; - else - sio2b_wr5 = sio_r[5]; + sio_wr5[2 - minor] = sio_r[5]; + sio_flow[2 - minor] = (t->c_cflag & CRTSCTS); } void tty_setup(uint8_t minor, uint8_t flags) @@ -80,92 +80,56 @@ int tty_carrier(uint8_t minor) void tty_drain_sio(void) { + static uint8_t old_ca[2]; uint8_t c; -#if 1 - while(sio2b_rxl) { - c = sio2b_rx_get(); + + /* Start with port B as it is run the fastest usually */ + while(sio_rxl[1]) { + c = siob_rx_get(); tty_inproc(1, c); } - while(sio2a_rxl) { - c = sio2a_rx_get(); + if (sio_dropdcd[1]) { + sio_dropdcd[1] = 0; + tty_carrier_drop(1); + } + if (((old_ca[1] ^ sio_state[1]) & sio_state[1]) & 8) + tty_carrier_raise(1); + old_ca[1] = sio_state[1]; + if (sio_txl[1] < 128 && (sleeping & 2)) { + sleeping &= ~2; + tty_outproc(1); + } + + while(sio_rxl[0]) { + c = sioa_rx_get(); tty_inproc(2, c); } - /* TODO: error, tx flow, modem change etc */ -#else - 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)) -//FIXME 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; - /* Input pending */ - if ((ca & 1) && !fullq(&ttyinq[2])) { - progress = 1; - tty_inproc(2, SIOA_D); - } - /* Break */ - if (ca & 2) - SIOA_C = 2 << 5; - /* Output pending */ - if (ca & 4) { - tty_outproc(2); - 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(2); - else - tty_carrier_drop(2); - } - SIOB_C = 0; // read register 0 - cb = SIOB_C; - if ((cb & 1) && !fullq(&ttyinq[1])) { - tty_inproc(1, SIOB_D); - progress = 1; - } - if (cb & 4) { - tty_outproc(1); - SIOB_C = 5 << 3; // reg 0 CMD 5 - reset transmit interrupt pending - } - if ((cb ^ old_cb) & 8) { - if (cb & 8) - tty_carrier_raise(1); - else - tty_carrier_drop(1); - } - } while(progress); -#endif + if (sio_dropdcd[0]) { + sio_dropdcd[0] = 0; + tty_carrier_drop(2); + } + if (((old_ca[0] ^ sio_state[0]) & sio_state[0]) & 8) + tty_carrier_raise(2); + old_ca[0] = sio_state[0]; + if (sio_txl[0] < 128 && (sleeping & 4)) { + sleeping &= ~4; + tty_outproc(2); + } + } void tty_putc(uint8_t minor, unsigned char c) { -#if 1 if (minor == 1) - sio2b_txqueue(c); + siob_txqueue(c); else - sio2a_txqueue(c); -#else - if (minor == 2) { - SIOA_D = c; - } else if (minor == 1) - SIOB_D = c; -#endif + sioa_txqueue(c); } /* We will need this for SIO once we implement flow control signals */ void tty_sleeping(uint8_t minor) { - used(minor); + sleeping |= (1 << minor); } /* Be careful here. We need to peek at RR but we must be sure nobody else @@ -179,9 +143,9 @@ void tty_sleeping(uint8_t minor) ttyready_t tty_writeready(uint8_t minor) { - if (minor == 1 && sio2b_txl == 255) + if (minor == 1 && sio_txl[1] == 255) return TTY_READY_SOON; - if (minor == 2 && sio2a_txl == 255) + if (minor == 2 && sio_txl[0] == 255) return TTY_READY_SOON; return TTY_READY_NOW; } diff --git a/Kernel/platform-linc80/devtty.h b/Kernel/platform-linc80/devtty.h index 88c239ed..635c3f30 100644 --- a/Kernel/platform-linc80/devtty.h +++ b/Kernel/platform-linc80/devtty.h @@ -11,21 +11,24 @@ extern void sio2_otir(uint8_t port) __z88dk_fastcall; void tty_putc(uint8_t minor, unsigned char c); -extern void sio2a_txqueue(uint8_t c) __z88dk_fastcall; -extern void sio2a_flow_control_on(void); -extern uint16_t sio2a_rx_get(void); -extern uint8_t sio2a_error_get(void); -extern uint8_t sio2a_rxl; -extern uint8_t sio2a_txl; -extern uint8_t sio2a_wr5; - -extern void sio2b_txqueue(uint8_t c) __z88dk_fastcall; -extern void sio2b_flow_control_on(void); -extern uint16_t sio2b_rx_get(void); -extern uint8_t sio2b_error_get(void); -extern uint8_t sio2b_rxl; -extern uint8_t sio2b_txl; -extern uint8_t sio2b_wr5; +extern void sioa_txqueue(uint8_t c) __z88dk_fastcall; +extern void sioa_flow_control_on(void); +extern void sioa_flow_control_off(void); +extern uint16_t sioa_rx_get(void); +extern uint8_t sioa_error_get(void); + +extern uint8_t sio_dropdcd[2]; +extern uint8_t sio_flow[2]; +extern uint8_t sio_rxl[2]; +extern uint8_t sio_state[2]; +extern uint8_t sio_txl[2]; +extern uint8_t sio_wr5[2]; + +extern void siob_txqueue(uint8_t c) __z88dk_fastcall; +extern void siob_flow_control_on(void); +extern void siob_flow_control_off(void); +extern uint16_t siob_rx_get(void); +extern uint8_t siob_error_get(void); extern void tty_drain_sio(void); diff --git a/Kernel/platform-linc80/linc80.s b/Kernel/platform-linc80/linc80.s index a8c0b732..ae72a4f3 100644 --- a/Kernel/platform-linc80/linc80.s +++ b/Kernel/platform-linc80/linc80.s @@ -173,21 +173,21 @@ init_hardware: ld (0x88),hl ; PIO A ld (0x8A),hl ; PIO B - ld hl,#sio2b_txd + ld hl,#siob_txd ld (0x90),hl ; SIO B TX empty - ld hl,#sio2b_status + ld hl,#siob_status ld (0x92),hl ; SIO B External status - ld hl,#sio2b_rx_ring + ld hl,#siob_rx_ring ld (0x94),hl ; SIO B Receive - ld hl,#sio2b_special + ld hl,#siob_special ld (0x96),hl ; SIO B Special - ld hl,#sio2a_txd + ld hl,#sioa_txd ld (0x98),hl ; SIO A TX empty - ld hl,#sio2a_status + ld hl,#sioa_status ld (0x9A),hl ; SIO A External status - ld hl,#sio2a_rx_ring + ld hl,#sioa_rx_ring ld (0x9C),hl ; SIO A Received - ld hl,#sio2a_special + ld hl,#sioa_special ld (0x9E),hl ; SIO A Special ld hl, #80 ld (_ramsize), hl @@ -211,12 +211,12 @@ init_hardware: ld a,#0x25 ; timer, 256 prescale, irq off out (CTC_CH2),a - ld a,#180 ; counter base (160 per second) + ld a,#90 ; counter base (320 per second) out (CTC_CH2),a ld a,#0xF5 ; counter, irq on out (CTC_CH3),a - ld a,#16 - out (CTC_CH3),a ; 160 per sec down to 10 per sec + ld a,#8 + out (CTC_CH3),a ; 320 per sec down to 40 per sec xor a ld i,a ; Use upper half of rst vector page @@ -294,72 +294,64 @@ ocloop_sio: .area _CONSOLE -sio2a_rx: +sioa_rx: jp init ; for boot only .ds 128-3 ; we wrote a JP init in the first 3 -sio2a_tx: ; that will be recycled +sioa_tx: ; that will be recycled .ds 128 -sio2b_rx: +siob_rx: .ds 128 -sio2b_tx: +siob_tx: .ds 128 .area _COMMONMEM -_sio2a_txl: +sioa_error: .db 0 -sio2a_error: +sioa_rxover: .db 0 -sio2a_rxover: +sioa_stat: .db 0 -sio2a_stat: +sioa_txp: + .dw sioa_tx +sioa_txe: + .dw sioa_tx +sioa_rxp: + .dw sioa_rx +sioa_rxe: + .dw sioa_rx + +siob_error: .db 0 -sio2a_txp: - .dw sio2a_tx -sio2a_txe: - .dw sio2a_tx -_sio2a_rxl: +siob_rxover: .db 0 -sio2a_rxp: - .dw sio2a_rx -sio2a_rxe: - .dw sio2a_rx - -_sio2b_txl: - .db 0 -sio2b_error: - .db 0 -sio2b_rxover: +siob_stat: .db 0 -sio2b_stat: - .db 0 -sio2b_txp: - .dw sio2a_tx -sio2b_txe: - .dw sio2a_tx -_sio2b_rxl: - .db 0 -sio2b_rxp: - .dw sio2a_rx -sio2b_rxe: - .dw sio2a_rx +siob_txp: + .dw sioa_tx +siob_txe: + .dw sioa_tx +siob_rxp: + .dw sioa_rx +siob_rxe: + .dw sioa_rx ; ; Interrupt vector handler for port A transmit empty ; -sio2a_txd: +sioa_txd: push af - ld a,(_sio2a_txl) + ld a,(_sioa_txl) or a jr z, tx_a_none push hl dec a - ld (_sio2a_txl),a - ld hl,(sio2a_txp) + ld (_sioa_txl),a + ld hl,(sioa_txp) ld a,(hl) out (SIOA_D),a inc hl set 7,l - ld (sio2a_txp),hl + ld (sioa_txp),hl pop hl tx_a_none: ld a,#0x28 @@ -370,27 +362,26 @@ tx_a_none: ; ; Interrupt vector handler for port A receive ready ; -sio2a_rx_ring: +sioa_rx_ring: push af push hl -sio2a_rx_next: +sioa_rx_next: in a,(SIOA_D) ; read ASAP ld l,a - ld a,(_sio2a_rxl) + ld a,(_sioa_rxl) inc a jp m, a_rx_over - ld (_sio2a_rxl),a + ld (_sioa_rxl),a ; should we check bit 5/6 and if appropriate flow control on bit 5/6 ; high ? -;sio2a_flow_patch: ; patch with fastest 5 byte nop -; cp #0x60 ; flow control threshold -; call z, _sio2a_flow_control_on + cp #0x60 ; flow control threshold + call z, _sioa_flow_control_on ld a,l - ld hl,(sio2a_rxp) + ld hl,(sioa_rxp) ld (hl),a inc l res 7,l - ld (sio2a_rxp),hl + ld (sioa_rxp),hl ; ; The chip has a small FIFO and bytes can also arrive as we ; read. To maximise performance try and empty it each time. @@ -400,15 +391,15 @@ sio2a_rx_next: ; in a,(SIOA_C) ; RR 0 rra - jr c, sio2a_rx_next + jr c, sioa_rx_next pop hl pop af ei reti a_rx_over: - ld a,(sio2a_error) + ld a,(sioa_error) or #0x20 ; Fake an RX overflow bit - ld (sio2a_rxover),a + ld (sioa_rxover),a pop af ei reti @@ -421,12 +412,18 @@ a_rx_over: ; and we can use thw two edges of DCD to work out if we had a hangup ; and if we are now open. ; -sio2a_status: +sioa_status: ; CTS or DCD change push af push hl ; RR0 in a,(SIOA_C) + ld (_sioa_state),a + and #8 + jr z, no_dcd_drop_a + ; \DCD went high + ld (_sioa_dropdcd),a ; Set the dcdflag +no_dcd_drop_a: ; Clear the latched values ld a,#0x10 out (SIOA_C),a @@ -438,14 +435,14 @@ sio2a_status: ; ; Interrupt vector for a port A error ; -sio2a_special: +sioa_special: ; Parity, RX Overrun, Framing ; Probably want to record them, but we at least must clean up push af ld a,#1 out (SIOA_C),a ; RR1 please in a,(SIOA_C) ; clear events - ld (sio2a_error),a ; Save error bits + ld (sioa_error),a ; Save error bits ; Clear the latched values ld a,#0x30 out (SIOA_C),a @@ -456,20 +453,20 @@ sio2a_special: ; ; Interrupt vector handler for port B transmit empty ; -sio2b_txd: +siob_txd: push af - ld a,(_sio2b_txl) + ld a,(_siob_txl) or a jr z, tx_b_none push hl dec a - ld (_sio2b_txl),a - ld hl,(sio2b_txp) + ld (_siob_txl),a + ld hl,(siob_txp) ld a,(hl) out (SIOB_D),a inc hl set 7,l - ld (sio2b_txp),hl + ld (siob_txp),hl pop hl tx_b_none: ld a,#0x28 @@ -480,27 +477,26 @@ tx_b_none: ; ; Interrupt vector handler for port B receive ready ; -sio2b_rx_ring: +siob_rx_ring: push af push hl -sio2b_rx_next: +siob_rx_next: in a,(SIOB_D) ; read ASAP ld l,a - ld a,(_sio2b_rxl) + ld a,(_siob_rxl) inc a jp m, b_rx_over - ld (_sio2b_rxl),a + ld (_siob_rxl),a ; should we check bit 5/6 and if appropriate flow control on bit 5/6 ; high ? -;sio2b_flow_patch: ; patch with fastest 5 byte nop -; cp #0x60 ; flow control threshold -; call z, _sio2b_flow_control_on + cp #0x60 ; flow control threshold + call z, _siob_flow_control_on ld a,l - ld hl,(sio2b_rxp) + ld hl,(siob_rxp) ld (hl),a inc l res 7,l - ld (sio2b_rxp),hl + ld (siob_rxp),hl ; ; The chip has a small FIFO and bytes can also arrive as we ; read. To maximise performance try and empty it each time. @@ -510,15 +506,15 @@ sio2b_rx_next: ; in a,(SIOB_C) ; RR 0 rra - jr c, sio2b_rx_next + jr c, siob_rx_next pop hl pop af ei reti b_rx_over: - ld a,(sio2b_error) + ld a,(siob_error) or #0x20 ; Fake an RX overflow bit - ld (sio2b_rxover),a + ld (siob_rxover),a pop af ei reti @@ -531,12 +527,18 @@ b_rx_over: ; and we can use thw two edges of DCD to work out if we had a hangup ; and if we are now open. ; -sio2b_status: +siob_status: ; CTS or DCD change push af push hl ; RR0 in a,(SIOB_C) + ld (_siob_state),a + and #8 + jr z, no_dcd_drop_b + ; \DCD went high + ld (_siob_dropdcd),a ; Set the dcdflag +no_dcd_drop_b: ; Clear the latched values ld a,#0x10 out (SIOB_C),a @@ -548,14 +550,14 @@ sio2b_status: ; ; Interrupt vector for a port B error ; -sio2b_special: +siob_special: ; Parity, RX Overrun, Framing ; Probably want to record them, but we at least must clean up push af ld a,#1 out (SIOB_C),a ; RR1 please in a,(SIOB_C) ; clear events - ld (sio2b_error),a ; Save error bits + ld (siob_error),a ; Save error bits ; Clear the latched values ld a,#0x30 out (SIOB_C),a @@ -566,28 +568,56 @@ sio2b_special: ; ; C interface methods ; - .globl _sio2a_txqueue - .globl _sio2a_flow_control_on - .globl _sio2a_rx_get - .globl _sio2a_error_get - - .globl _sio2a_rxl - .globl _sio2a_txl - .globl _sio2a_wr5 - - .globl _sio2b_txqueue - .globl _sio2b_flow_control_on - .globl _sio2b_rx_get - .globl _sio2b_error_get - - .globl _sio2b_rxl - .globl _sio2b_txl - .globl _sio2b_wr5 - -_sio2a_wr5: + .globl _sioa_txqueue + .globl _sioa_flow_control_off + .globl _sioa_flow_control_on + .globl _sioa_rx_get + .globl _sioa_error_get + + .globl _siob_txqueue + .globl _siob_flow_control_off + .globl _siob_flow_control_on + .globl _siob_rx_get + .globl _siob_error_get + + .globl _sio_dropdcd + .globl _sio_flow + .globl _sio_rxl + .globl _sio_state + .globl _sio_txl + .globl _sio_wr5 + +; These are paid and exposed as arrays to C +_sio_wr5: +_sioa_wr5: .db 0xEA ; DTR, 8bit, tx enabled -_sio2b_wr5: +_siob_wr5: .db 0xEA ; DTR, 8bit, tx enabled +_sio_flow: +_sioa_flow: + .db 0 ; Flow starts off +_siob_flow: + .db 0 ; Flow starts off +_sio_state: +_sioa_state: + .db 0 ; Last status report +_siob_state: + .db 0 ; Last status report +_sio_dropdcd: +_sioa_dropdcd: + .db 0 ; DCD dropped since last checked +_siob_dropdcd: + .db 0 ; DCD dropped since last checked +_sio_rxl: +_sioa_rxl: + .db 0 +_siob_rxl: + .db 0 +_sio_txl: +_sioa_txl: + .db 0 +_siob_txl: + .db 0 ; ; Queue a byte to be sent (DI required) @@ -598,33 +628,33 @@ _sio2b_wr5: ; (or can we use hardware ?) ; 128 byte ring buffer aligned to upper half (rx is in lower) ; -_sio2a_txqueue: - ld a,(_sio2a_txl) +_sioa_txqueue: + ld a,(_sioa_txl) or a - jr z, sio2a_direct_maybe ; if can tx now then do + jr z, sioa_direct_maybe ; if can tx now then do inc a jp m, txa_overflow -sio2a_queue: - ld (_sio2a_txl),a +sioa_queue: + ld (_sioa_txl),a ld a,l - ld hl,(sio2a_txe) + ld hl,(sioa_txe) ld (hl),a inc l set 7,l - ld (sio2a_txe),hl + ld (sioa_txe),hl ld l,#0 ret txa_overflow: ; some kind of flag for error ld l,#1 ret -sio2a_direct_maybe: +sioa_direct_maybe: ; check RR in a,(SIOA_C) and #0x04 ; RX space ? ; if space ld a,#1 - jr nz, sio2a_queue + jr nz, sioa_queue ; bypass the queue and kickstart the interrupt machine ld a,l out (SIOA_D),a @@ -632,12 +662,19 @@ sio2a_direct_maybe: ret ; Call with DI -_sio2a_flow_control_on: +_sioa_flow_control_off: + ld a,#5 + out(SIOA_C),a ; WR 5 + ld a,(_sioa_wr5) + out (SIOA_C),a ; Turn off RTS + ret + +_sioa_flow_control_on: ld a,#5 out(SIOA_C),a ; WR 5 - ld a,(_sio2a_wr5) - or #0x02 - out (SIOA_C),a ; Turn on RTS + ld a,(_sioa_wr5) + and #0xFD + out (SIOA_C),a ; Turn off RTS ret ; DI required @@ -645,24 +682,24 @@ _sio2a_flow_control_on: ; ; Caller responsible for making post buffer fetch decisions about ; RTS -_sio2a_rx_get: - ld a,(_sio2a_rxl) +_sioa_rx_get: + ld a,(_sioa_rxl) or a ret z dec a - ld (_sio2a_rxl),a - ld hl,(sio2a_rxe) + ld (_sioa_rxl),a + ld hl,(sioa_rxe) ld a,(hl) inc l res 7,l - ld (sio2a_rxe),hl + ld (sioa_rxe),hl scf ld l,a ret ; DI required -_sio2a_error_get: - ld hl,#sio2a_error +_sioa_error_get: + ld hl,#sioa_error ld a,(hl) ld (hl),#0 ld l,a @@ -677,33 +714,33 @@ _sio2a_error_get: ; (or can we use hardware ?) ; 128 byte ring buffer aligned to upper half (rx is in lower) ; -_sio2b_txqueue: - ld a,(_sio2b_txl) +_siob_txqueue: + ld a,(_siob_txl) or a - jr z, sio2b_direct_maybe ; if can tx now then do + jr z, siob_direct_maybe ; if can tx now then do inc a jp m, txb_overflow -sio2b_queue: - ld (_sio2b_txl),a +siob_queue: + ld (_siob_txl),a ld a,l - ld hl,(sio2b_txe) + ld hl,(siob_txe) ld (hl),a inc l set 7,l - ld (sio2b_txe),hl + ld (siob_txe),hl ld l,#0 ret txb_overflow: ; some kind of flag for error ld l,#1 ret -sio2b_direct_maybe: +siob_direct_maybe: ; check RR in a,(SIOB_C) and #0x04 ; RX space ? ; if space ld a,#1 - jr z, sio2b_queue + jr z, siob_queue ; bypass the queue and kickstart the interrupt machine ld a,l out (SIOB_D),a @@ -711,12 +748,22 @@ sio2b_direct_maybe: ret ; Call with DI -_sio2b_flow_control_on: +_siob_flow_control_off: + ld a,#5 + out(SIOB_C),a ; WR 5 + ld a,(_siob_wr5) + out (SIOB_C),a ; Turn off RTS + ret + +_siob_flow_control_on: + ld a, (_siob_flow) + or a + ret z ld a,#5 out(SIOB_C),a ; WR 5 - ld a,(_sio2b_wr5) - or #0x02 - out (SIOB_C),a ; Turn on RTS + ld a,(_siob_wr5) + and #0xFD + out (SIOB_C),a ; Turn off RTS ret ; DI required @@ -724,24 +771,24 @@ _sio2b_flow_control_on: ; ; Caller responsible for making post buffer fetch decisions about ; RTS -_sio2b_rx_get: - ld a,(_sio2b_rxl) +_siob_rx_get: + ld a,(_siob_rxl) or a ret z dec a - ld (_sio2b_rxl),a - ld hl,(sio2b_rxe) + ld (_siob_rxl),a + ld hl,(siob_rxe) ld a,(hl) inc l res 7,l - ld (sio2b_rxe),hl + ld (siob_rxe),hl scf ld l,a ret ; DI required -_sio2b_error_get: - ld hl,#sio2b_error +_siob_error_get: + ld hl,#siob_error ld a,(hl) ld (hl),#0 ld l,a