cromemco: switch to proper IRQ driven serial bufers
authorAlan Cox <alan@linux.intel.com>
Thu, 10 Jan 2019 13:13:03 +0000 (13:13 +0000)
committerAlan Cox <alan@linux.intel.com>
Thu, 10 Jan 2019 13:13:03 +0000 (13:13 +0000)
Not yet tested

Kernel/platform-cromemco/Makefile
Kernel/platform-cromemco/commonmem.s
Kernel/platform-cromemco/crt0.s
Kernel/platform-cromemco/devtty.c
Kernel/platform-cromemco/devtty.h
Kernel/platform-cromemco/discard.c
Kernel/platform-cromemco/fuzix.lnk
Kernel/platform-cromemco/irq.h
Kernel/platform-cromemco/main.c
Kernel/platform-cromemco/tuart.s [new file with mode: 0644]
Kernel/platform-cromemco/vector.s

index 6adaab7..1c97f8b 100644 (file)
@@ -21,6 +21,8 @@ $(COBJS): %.rel: %.c
 $(CDOBJS): %.rel: %.c
        $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $<
 
+vector.rel: tuart.s
+
 clean:
        rm -f *.rel *.lst *.asm *.sym *.rst core *~
        rm -f cloader-16fdc.ihx cloader-16fdc.tmp
index 522503a..df459e1 100644 (file)
@@ -1,7 +1,3 @@
-;
-;      Common on z80pack is at 0xF000 as defined by hardware.
-;
-
         .module commonmem
 
         .area _COMMONMEM
index 6e524d6..cbfe051 100644 (file)
@@ -10,6 +10,7 @@
         .area _CODE2
         .area _CONST
         .area _INITIALIZED
+       .area _INTDATA
         .area _DATA
         .area _BSEG
         .area _BSS
@@ -22,6 +23,8 @@
        .area _DISCARD
         .area _INITIALIZER
         .area _COMMONMEM
+       .area _BOOT
+       .area _SERIAL
 
         ; imported symbols
         .globl _fuzix_main
         .globl l__DATA
         .globl kstack_top
 
+       ; For the boot vector
+       .globl init
+
        .include "../kernel.def"
        .include "kernel.def"
 
+       .area _BOOT
+
+       ; boot code (overlaps serial buffers to be)
+       jp init
+
         ; startup code
         .area _CODE
 init:
index e2c0eba..f803ee8 100644 (file)
@@ -17,10 +17,6 @@ struct  s_queue  ttyinq[NUM_DEV_TTY+1] = {       /* ttyinq[0] is never used */
     {   tbuf3,   tbuf3,   tbuf3,   TTYSIZ,   0,   TTYSIZ/2 },
 };
 
-static uint8_t ttybase[NUM_DEV_TTY+1] = {
- 0, 0, 32, 80
-};
-
 tcflag_t uart_mask[4] = {
        _ISYS,
        _OSYS,
@@ -37,28 +33,38 @@ tcflag_t *termios_mask[NUM_DEV_TTY + 1] = {
 
 static uint8_t ttypoll;
 
+static uint8_t ttybase[] = { 0, 0, 32, 80 };
+
+__sfr __at 0x00 tuart0_status;
+__sfr __at 0x01 tuart0_data;
+
 /* Write to system console */
 void kputchar(char c)
 {
-    /* handle CRLF */
-    if(c=='\n')
-        tty_putc(1, '\r');
-    tty_putc(1, c);
+    /* Has to run polled */
+    while(!(tuart0_status & 0x80));
+    tuart0_data = c;
 }
 
 char tty_writeready(uint8_t minor)
 {
-    uint8_t r = ttybase[minor];
-    r = in(r);
-    if (r & 0x80)
-        return 1;
-    return 0;
+    if (minor == 1 && tuart0_txl < 63)
+        return TTY_READY_NOW;
+    if (minor == 2 && tuart1_txl < 63)
+        return TTY_READY_NOW;
+    if (minor == 3 && tuart2_txl < 63)
+        return TTY_READY_NOW;
+    return TTY_READY_SOON;
 }
 
 void tty_putc(uint8_t minor, unsigned char c)
 {
-    uint8_t r = ttybase[minor];
-    out(r + 1, c);
+    if (minor == 1)
+        tuart0_txqueue(c);
+    else if (minor == 2)
+        tuart1_txqueue(c);
+    else
+        tuart2_txqueue(c);
 }
 
 void tty_sleeping(uint8_t minor)
@@ -68,24 +74,31 @@ void tty_sleeping(uint8_t minor)
 
 void tty_data_consumed(uint8_t minor)
 {
+    used(minor);
 }
 
-void tty_irq(uint8_t minor)
+void tty_drain(void)
 {
-    if (minor != 1)
-        return;        /* For the moment */
-    if (rx0a_int) {
-        uint8_t c = rx0a_char;
-        rx0a_int = 0;
-        tty_inproc(1, rx0a_char);
-    }
-    if (tx0a_int) {
-        tx0a_int = 0;
+    while (tuart0_rxl)
+        tty_inproc(1, tuart0_rx_get());
+    if (tuart0_txl < 32 && (ttypoll & (1 << 1))) {
         ttypoll &= ~(1 << 1);
-        wakeup(&ttydata[1]);
+        tty_outproc(1);
+    }
+    while (tuart1_rxl)
+        tty_inproc(1, tuart1_rx_get());
+    if (tuart1_txl < 32 && (ttypoll & (1 << 2))) {
+        ttypoll &= ~(1 << 2);
+        tty_outproc(2);
+    }
+    while (tuart2_rxl)
+        tty_inproc(1, tuart2_rx_get());
+    if (tuart2_txl < 32 && (ttypoll & (1 << 3))) {
+        ttypoll &= ~(1 << 3);
+        tty_outproc(3);
     }
 }    
-
 static uint8_t baudbits[] = {
     1,
     1,
@@ -111,15 +124,16 @@ void tty_setup(uint8_t minor, uint8_t flags)
     struct termios *t = &ttydata[minor].termios;
     uint8_t baud = t->c_cflag & CBAUD;
     uint8_t r = ttybase[minor];
+
+    used(flags);
+
     out(r, baudbits[baud] | (t->c_cflag & CSTOPB) ? 0 : 0x80);
-    /* Assume we keep to IM1 */
     if (baud <= B9600)
         out(r + 2, 0x8);
     else
         out(r + 2, 0x18);
 }
 
-/* For the moment */
 int tty_carrier(uint8_t minor)
 {
     used(minor);
index ddb0f42..ef232c6 100644 (file)
@@ -1 +1,25 @@
-extern void tty_irq(uint8_t minor);
+extern void tty_drain(void);
+
+extern void tuart0_txqueue(uint8_t c) __z88dk_fastcall;
+extern uint8_t tuart0_rx_get(void);
+extern void tuart0_error_get(void);
+extern void tuart0_txd(uint8_t unused);
+extern void tuart0_rx_ring(uint8_t unused);
+
+extern uint8_t tuart0_txl, tuart0_rxl;
+
+extern void tuart1_txqueue(uint8_t c) __z88dk_fastcall;
+extern uint8_t tuart1_rx_get(void);
+extern void tuart1_error_get(void);
+extern void tuart1_txd(uint8_t unused);
+extern void tuart1_rx_ring(uint8_t unused);
+
+extern uint8_t tuart1_txl, tuart1_rxl;
+
+extern void tuart2_txqueue(uint8_t c) __z88dk_fastcall;
+extern uint8_t tuart2_rx_get(void);
+extern void tuart2_error_get(void);
+extern void tuart2_txd(uint8_t unused);
+extern void tuart2_rx_ring(uint8_t unused);
+
+extern uint8_t tuart2_txl, tuart2_rxl;
index 1700128..c768086 100644 (file)
@@ -15,9 +15,9 @@ void pagemap_init(void)
 /* Nothing to do for the map of init but we do set our vectors up here */
 void map_init(void)
 {
- if (request_irq(0xE7, uart0a_rx) |
- request_irq(0xEF, uart0a_txdone) |
- request_irq(0xF7, uart0a_timer4))
+ if (request_irq(0xE7, tuart0_rx_ring) |
+ request_irq(0xEF, tuart0_txd) |
+ request_irq(0xF7, tuart0_timer4))
   panic("irqset");
  /* We need to claim these in case we set one off as they are at odd vectors
     as the base tu_uart is strapped for 8080 mode */
@@ -29,6 +29,7 @@ void map_init(void)
   request_irq(0xFF, spurious)
   )
   panic("irqset2");
+  /* FIXME: request vectors for uart1 and 2 */
 }
 
 uint8_t platform_param(char *p)
index 04e26f2..fd1b2c4 100644 (file)
@@ -1,8 +1,10 @@
 -mwxuy
 -i fuzix.ihx
--b _CODE=0x0100
+-b _CODE=0x0280
 -b _COMMONMEM=0xF200
 -b _DISCARD=0xE000
+-b _SERIAL=0x0100
+-b _BOOT=0x0100
 -l z80
 platform-cromemco/crt0.rel
 platform-cromemco/commonmem.rel
index 1dd00c7..a9db31a 100644 (file)
@@ -6,8 +6,4 @@ extern uint8_t irqvec[];
 extern void spurious(uint8_t vec);
 extern void set_irq(uint16_t vec, void (*func)(uint8_t));
 
-extern void uart0a_rx(uint8_t unused);
-extern void uart0a_txdone(uint8_t unused);
-extern void uart0a_timer4(uint8_t unused);
-
-extern uint8_t rx0a_int, tx0a_int, rx0a_char;
+extern void tuart0_timer4(uint8_t unused);
index 8b5834a..f975f4e 100644 (file)
@@ -18,10 +18,8 @@ __sfr __at 0x08 timer4;
 void platform_interrupt(void)
 {
  timer4 = 156;
- tty_irq(1);
+ tty_drain();
  timer_interrupt();
-// tty_irq(2);
-// tty_irq(3);
 }
 
 /* This points to the last buffer in the disk buffers. There must be at least
diff --git a/Kernel/platform-cromemco/tuart.s b/Kernel/platform-cromemco/tuart.s
new file mode 100644 (file)
index 0000000..20cf3dd
--- /dev/null
@@ -0,0 +1,226 @@
+;
+;      Based on the SIO driver but for the Cromemco TU-ART
+;
+;      The big difference is that we have to do a minimal task switch
+;      in order to access our data as we don't have a true common and also
+;      common space is precious
+;
+;      For speed we flip bank but not stack so once we flip we must not
+;      use the stack until we flip back.
+;
+
+.macro tuart_ports X
+
+       .globl _tuart'X'_rxl
+       .globl _tuart'X'_txl
+
+;
+;      Must be aligned. Need not be common
+;
+
+       .area   _SERIAL
+tuart'X'_rx:
+       .ds     64
+tuart'X'_tx:
+       .ds     64
+
+;
+;      We flip maps so we don't need this in common
+;
+       .area _INTDATA
+tuart'X'_error:
+       .db     0
+tuart'X'_rxover:
+       .db     0
+tuart'X'_txp:
+       .dw     tuart'X'_tx
+tuart'X'_txe:
+       .dw     tuart'X'_tx
+tuart'X'_rxp:
+       .dw     tuart'X'_rx
+tuart'X'_rxe:
+       .dw     tuart'X'_rx
+_tuart'X'_rxl:
+       .db     0
+_tuart'X'_txl:
+       .db     0
+_tuart'X'_error:
+       .db     0
+
+.endm
+
+.macro tuart_handler_im2 X P lh RET
+
+;
+;      C interface methods
+;
+       .globl _tuart'X'_txqueue
+       .globl _tuart'X'_rx_get
+       .globl _tuart'X'_error_get
+       .globl _tuart'X'_txd
+       .globl _tuart'X'_rx_ring
+
+       .area _COMMONMEM
+;
+;      Interrupt vector handler for port A transmit empty
+;
+_tuart'X'_txd:
+       push af
+       push hl
+       push bc
+       ld bc,#0x4001
+       in a,(c)
+       out (c),b
+       ld b,a
+       ld a,(_tuart'X'_txl)
+       or a
+       jr z, tx_'X'_none
+       dec a
+       ld (_tuart'X'_txl),a
+       ld hl,(tuart'X'_txp)
+       ld a,(hl)
+       out (P + 1),a
+       inc l
+       set 6,l
+       lh 7,l                  ; Force to upper or lower half
+       ld (tuart'X'_txp),hl
+tx_'X'_none:
+       ; Do we need to mask the int off
+       ; if so need to cache 03 state (intmask) and add 0x20 (TBE)
+       out (c),b
+       pop bc
+       pop hl
+       pop af
+       ei
+       RET
+;
+;      Interrupt vector handler for port A receive ready
+;
+_tuart'X'_rx_ring:
+       push af
+       push hl
+       push bc
+       ld bc,#0x4001
+       in a,(c)
+       out (c),b
+       ld b,a
+tuart'X'_rx_next:
+       in a,(P)                ; status
+       and #7
+       jp z, tuart'X'_no_error
+       ld hl,#_tuart'X'_error  ; accumulate error bits
+       or (hl)
+       ld (hl),a
+tuart'X'_no_error:
+       in a,(P + 1)            ; read ASAP
+       ld l,a
+       ld a,(_tuart'X'_rxl)
+       inc a
+       bit 6,a
+       jp nz, tuart'X'_rx_over
+       ld (_tuart'X'_rxl),a
+       ld a,l
+       ld hl,(tuart'X'_rxp)
+       ld (hl),a
+       inc l
+       res 6,l
+       lh 7,l
+       ld (tuart'X'_rxp),hl
+       ;
+       ;       This is bounded as worst case at high data rate and low
+       ;       CPU speed we will overrun and bail out.
+       ;
+       in a,(P)                ; RR 0
+       bit 6,a                 ; RDA is high if there is more to read
+       jr c, tuart'X'_rx_next
+       out (c),b
+       pop bc
+       pop hl
+       pop af
+       ei
+       RET
+tuart'X'_rx_over:
+       ld a,(tuart'X'_error)
+       or #0x04                ; Fake an RX overflow bit
+       ld (tuart'X'_error),a
+       out (c),b
+       pop bc
+       pop hl
+       pop af
+       ei
+       RET
+
+       .area _CODE
+
+;
+;      Queue a byte to be sent (DI required)
+;
+;      l = byte
+;
+;      Need a way to halt processing somewhere here or a_tx ?
+;      (or can we use hardware ?)
+;      128 byte ring buffer aligned to upper half (rx is in lower)
+;
+_tuart'X'_txqueue:
+       ld a,(_tuart'X'_txl)
+       or a
+       jr z, tuart'X'_direct_maybe     ; if can tx now then do
+       inc a
+       bit 6,a
+       jp nz, tx'X'_overflow
+tuart'X'_queue:
+       ld (_tuart'X'_txl),a
+       ld a,l
+       ld hl,(tuart'X'_txe)
+       ld (hl),a
+       inc l
+       set 6,l
+       lh 7,l
+       ld (tuart'X'_txe),hl
+       ld l,#0
+       ret
+tx'X'_overflow:
+       ; some kind of flag for error
+       ld l,#1
+       ret
+tuart'X'_direct_maybe:
+       ; check RR
+       in a,(P)
+       rla                     ; RX space ?
+       ; if space
+       ld a,#1
+       jr nc, tuart'X'_queue
+       ; bypass the queue and kickstart the interrupt machine
+       ld a,l
+       out (P + 1),a
+       ld l,#0
+       ret
+
+       ; DI required
+       ; Returns char in L
+_tuart'X'_rx_get:
+       ld a,(_tuart'X'_rxl)
+       or a
+       ret z
+       dec a
+       ld (_tuart'X'_rxl),a
+       ld hl,(tuart'X'_rxe)
+       ld a,(hl)
+       inc l
+       res 6,l
+       lh 7,l
+       ld (tuart'X'_rxe),hl
+       scf
+       ld l,a
+       ret
+
+       ; DI required
+_tuart'X'_error_get:
+       ld hl,#tuart'X'_error
+       ld a,(hl)
+       ld (hl),#0
+       ld l,a
+       ret
+
+
+.endm
index 67d1e60..0645ffb 100644 (file)
@@ -1,3 +1,5 @@
+
+       .include 'tuart.s'
 ;
 ;      Interrupt handlers. These will get replaced by some proper FIFO
 ; logic
@@ -6,55 +8,20 @@
        .area _COMMONMEM
        .module vector
 
-       .globl _rx0a_char
-       .globl _rx0a_int
-       .globl _tx0a_int
        .globl interrupt_high
+       .globl _tuart0_timer4
 
-       .globl _uart0a_rx
-       .globl _uart0a_txdone
-       .globl _uart0a_timer4
-
-_uart0a_rx:                    ; 0xE7
-       push af
-       push bc
-       push de
-       ld bc,#0x8140
-       in d,(c)
-       out (c),b
-       in a,(1)
-       ld (_rx0a_char),a
-       ld a,#1
-       ld (_rx0a_int),a
-       out (c),d
-       pop de
-       pop bc
-       pop af
-       ei
-       reti
+_tuart0_timer4:
+       jp interrupt_high
 
-_uart0a_txdone:                        ; 0xEF
-       push af
-       push bc
-       push de
-       ld bc,#0x8140
-       in d,(c)
-       out (c),b
-       ld a,#1
-       ld (_tx0a_int),a
-       out (c),d
-       pop de
-       pop bc
-       pop af
-       ei
-       reti
+tuart_ports    0
+tuart_ports    1
+tuart_ports    2
 
-_uart0a_timer4:
-       jp interrupt_high
+       .area _COMMONMEM
 
-_rx0a_char:
-       .byte 0
-_rx0a_int:
-       .byte 0
-_tx0a_int:
-       .byte 0
+; Console tuart
+tuart_handler_im2 0 0 res reti
+; Additional ports on cards
+tuart_handler_im2 1 0x80 set reti
+tuart_handler_im2 2 0x90 res reti