cromemco: further updates - gets us to the boot prompt
authorAlan Cox <alan@linux.intel.com>
Mon, 10 Dec 2018 15:26:51 +0000 (15:26 +0000)
committerAlan Cox <alan@linux.intel.com>
Mon, 10 Dec 2018 15:26:51 +0000 (15:26 +0000)
The tty interfacing via IM2 mode is a bit hackish for now. Unfortunately because
the emulation of the tu-art in Z80pack is currently extremely buggy we are
basically forced to use IM2.

Eventually we want to do IM2 properly anyway. The entire system is built around
a design that has proper interrupt handling.

With these changes sorted interrupts now work, and you can fail to find a root
file system. Next task is getting the fdc and root fs working.

Kernel/platform-cromemco/Makefile
Kernel/platform-cromemco/README
Kernel/platform-cromemco/cromemco.s
Kernel/platform-cromemco/devtty.c
Kernel/platform-cromemco/fuzix.lnk
Kernel/platform-cromemco/interrupt.c [new file with mode: 0644]
Kernel/platform-cromemco/irq.h [new file with mode: 0644]
Kernel/platform-cromemco/main.c
Kernel/platform-cromemco/rules.mk [new file with mode: 0644]
Kernel/platform-cromemco/usermem.s [new file with mode: 0644]
Kernel/platform-cromemco/vector.s [new file with mode: 0644]

index c511cf8..6ca489a 100644 (file)
@@ -1,9 +1,9 @@
 
-CSRCS = devtty.c devfd.c
+CSRCS = devtty.c devfd.c interrupt.c
 CSRCS += devices.c main.c
 
 ASRCS = crt0.s cromemco.s usermem.s
-ASRCS += tricks.s commonmem.s
+ASRCS += tricks.s commonmem.s vector.s
 
 AOBJS = $(ASRCS:.s=.rel)
 COBJS = $(CSRCS:.c=.rel)
index 2e72ca0..975d0f1 100644 (file)
@@ -19,9 +19,12 @@ one but there are cases we switch and borrow a bit of the other bank copy.
 It's easier to arrange this way anyhow.
 
 TODO
--              Debug a loader (seems to work)
--              An awful lot of early kernel boot debugging
--              Interrupts properly (and IM2)
+DONE   -               Debug a loader (seems to work)
+IP     -               An awful lot of early kernel boot debugging
+HACK   -               Interrupts properly (and IM2)
+                       not yet doing tty interrupts nicely with buffer
+                       and queues
+
 
 
 
@@ -47,7 +50,8 @@ The MMU settings we use are
 
 
 UARTs: TMS 5501 x 2 per board. These can do Z80 IM2 where the vector is
-determined by A7-A5 of the IRQ (used as D7-D5 of the vector)
+determined by A7-A5 of the IRQ (used as D7-D5 of the vector) or generate the
+8080 RST vectors.
 
 R 0            Status
 
@@ -201,3 +205,36 @@ W 40       Disables boot rom as a side effect
 W 40   bank select
 
 
+
+Interrupt vectors
+24 uart1a parallel port
+28 uart1a rda
+2A uart1a tbe
+34 uart1b parallel port
+38 uart1b RDA
+3A uart1b TBE
+
+(Uart0 strapped for 8080 mode for some reason)
+C7 uart 0a timer 1
+CF uart 0a timer 2
+D7 FDC EOJ
+DF uart 0a timer 3
+E7 uart 0a RDA
+EF uart 0a TBE
+F7 uart 0a timer 4
+FF uart 0a timer 5 also RTC timer
+
+Doc actually says
+
+D7-D5 = A7-A5 of port
+D4 = 0 for A 1 for B
+D3-1
+       000     timer 1
+       001     timer 2
+       010     !sensa
+       011     timer 3
+       100     rda
+       101     tbe
+       110     timer4
+       111     timer5 (PI7)
+
index f598ed4..ece53f5 100644 (file)
        .globl _need_resched
        .globl _ssig
 
+       .globl _set_irq
+       .globl _spurious
+       .globl _irqvec
+       .globl interrupt_high
+
        .globl outcharhex
        .globl outhl, outde, outbc
        .globl outnewline
 ; -----------------------------------------------------------------------------
         .area _COMMONMEM
 
+;
+;      Must be page aligned
+;
+_irqvec:
+       ; 0
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       ; 16
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       ; 32
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       ; 48
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       ; 64
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       ; 80
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       ; 96
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       ; 112
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       ; 128
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       ; 144
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       ; 160
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       ; 176
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       ; 192
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       ; 208
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       ; 224
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       ; 240
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       .word _spurious
+       ; 256
+       .byte 0
+
+
 _platform_reboot:
 _platform_monitor:
        jr _platform_monitor
@@ -74,6 +231,15 @@ _int_disabled:
        .area _CODE
 
 init_early:
+        ret
+
+init_hardware:
+        ; set system RAM size
+        ld hl, #448            ; Assuming fully loaded for now
+        ld (_ramsize), hl
+        ld hl, #(448-64)       ; 64K for kernel
+        ld (_procmem), hl
+
        ld a,#0x81              ; Every memory writeable, read kernel
        out (0x40),a            ; MMU set
 
@@ -83,28 +249,20 @@ init_early:
        ld bc,#0x67
        ldir
 
-       ; And the common across all banks
-       ld hl,#s__COMMONMEM
-       ld d,h
-       ld e,l
-       ld bc,#l__COMMONMEM
-       ldir
-
        ld a,#0x01              ; bank to the kernel bank
        out (0x40),a
-        ret
-
-init_hardware:
-        ; set system RAM size
-        ld hl, #448            ; Assuming fully loaded for now
-        ld (_ramsize), hl
-        ld hl, #(448-64)       ; 64K for kernel
-        ld (_procmem), hl
 
+       ld a,#0x40              ; enable interrupt mode
+       out (2),a
+       ld a,#0x70
+       out (3),a               ; serial 0 timer 4 tbe rda
        ld a, #156              ; ticks for 10Hz (9984uS per tick)
        out (8), a              ; 10Hz timer on
 
-       im 1                    ; really should use a page and im2?
+       ld hl,#_irqvec
+       ld a,h                  ; deal with linker limits
+       ld i,a
+       im 2
         ret
 
 
@@ -127,6 +285,40 @@ map_page_low:
 _program_vectors:
        ret
 
+;
+;      Called when we get an unexpected vector - just ack and return
+;
+_spurious:                     ; unexpected IRQ vector - handy breakpoint
+       ei
+       reti
+
+;
+;      Set an interrupt table entry. Done in asm as we want to write it
+;      through to all the banks.
+;
+_set_irq:
+       pop hl
+       pop de
+       pop bc
+       push bc
+       push de
+       push hl
+       ld hl,#_irqvec
+       di
+       add hl,de
+       ld a,#0x81
+       out (0x40),a            ; write to all banks, read kernel
+       ld (hl),c
+       inc hl
+       ld (hl),b
+       ld a,#0x01
+       out (0x40),a            ; kernel mapping back
+       ld a,(_int_disabled)
+       or a
+       ret nz
+       ei
+       ret
+
 ; outchar: Wait for UART TX idle, then print the char in A
 ; destroys: AF
 outchar:
@@ -460,7 +652,6 @@ rst18:
        ; and leap into user space
        jp (hl)
        nop
-       nop
 rst20: ret
        nop
        nop
index ffdb4bc..e2c0eba 100644 (file)
@@ -4,6 +4,7 @@
 #include <stdbool.h>
 #include <tty.h>
 #include <devtty.h>
+#include <irq.h>
 
 char tbuf1[TTYSIZ];
 char tbuf2[TTYSIZ];
@@ -69,26 +70,19 @@ void tty_data_consumed(uint8_t minor)
 {
 }
 
-__sfr __at 0x08 timer4;
-
 void tty_irq(uint8_t minor)
 {
-    uint8_t r = ttybase[minor];
-    uint8_t op;
-    while((op = in(r + 3)) != 0xFF) {
-        switch(op) {
-        case 0xE7:
-            /* should check in(r) for error bits */
-            tty_inproc(minor, in(r + 1 ));
-        case 0xEF:
-            ttypoll &= ~(1 << minor);
-            wakeup(&ttydata[minor]);
-        case 0xF7:
-            if (minor == 1) {
-                timer_interrupt();
-                timer4 = 156;
-            }
-        }
+    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;
+        ttypoll &= ~(1 << 1);
+        wakeup(&ttydata[1]);
     }
 }    
 
index c1e5e7c..bb13048 100644 (file)
@@ -7,7 +7,9 @@
 platform-cromemco/crt0.rel
 platform-cromemco/commonmem.rel
 platform-cromemco/cromemco.rel
+platform-cromemco/vector.rel
 platform-cromemco/main.rel
+platform-cromemco/interrupt.rel
 start.rel
 version.rel
 lowlevel-z80-thunked.rel
diff --git a/Kernel/platform-cromemco/interrupt.c b/Kernel/platform-cromemco/interrupt.c
new file mode 100644 (file)
index 0000000..28379f6
--- /dev/null
@@ -0,0 +1,38 @@
+#include <kernel.h>
+#include <irq.h>
+
+static uint8_t irqbusy(uint8_t vec)
+{
+    uint16_t *p = (uint16_t *)(irqvec + vec);
+    if (*p != (uint16_t)spurious)
+        return 1;
+    return 0;
+}
+    
+static uint8_t irqcheck(uint8_t vec)
+{
+    if (irqbusy(vec & 0xFE))
+        return 1;
+    /* If it's odd and not 255 then check the vector above is also free */
+    if ((vec & 1) && ++vec && irqbusy(vec))
+        return 1;
+    return 0;
+}
+
+int request_irq(uint8_t vec, void (*func)(uint8_t))
+{
+    /* This is fun because the Cromemco has uart 0 set to use the 8080 mode
+       vectors which are odd numbers */
+    if (irqcheck(vec))
+        return -EBUSY;
+    set_irq(vec, func);
+    return 0;
+}
+
+void free_irq(uint8_t vec)
+{
+    if (!irqcheck(vec))
+        panic("free_irq");
+    set_irq(vec, spurious);
+}
+
diff --git a/Kernel/platform-cromemco/irq.h b/Kernel/platform-cromemco/irq.h
new file mode 100644 (file)
index 0000000..1dd00c7
--- /dev/null
@@ -0,0 +1,13 @@
+extern int request_irq(uint8_t vec, void (*func)(uint8_t));
+extern void free_irq(uint8_t vec);
+
+/* These have to live in common space */
+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;
index 38ed256..a24f1e5 100644 (file)
@@ -1,6 +1,7 @@
 #include <kernel.h>
 #include <devtty.h>
 #include <printf.h>
+#include <irq.h>
 
 uaddr_t ramtop = PROGTOP;
 
@@ -14,19 +15,41 @@ void pagemap_init(void)
 
 void platform_idle(void)
 {
-  /* halt ?? */
+ __asm
+  halt
+ __endasm;
 }
 
+__sfr __at 0x08 timer4;
+
 void platform_interrupt(void)
 {
+ timer4 = 156;
  tty_irq(1);
- tty_irq(2);
- tty_irq(3);
+ timer_interrupt();
+// tty_irq(2);
+// tty_irq(3);
 }
 
-/* Nothing to do for the map of init */
+/* Get this into discard ... */
+
+/* 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))
+  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 */
+ if (
+  request_irq(0xC7, spurious) |
+  request_irq(0xCF, spurious) |
+  request_irq(0xD7, spurious) |
+  request_irq(0xDF, spurious) |
+  request_irq(0xFF, spurious)
+  )
+  panic("irqset2");
 }
 
 uint8_t platform_param(char *p)
diff --git a/Kernel/platform-cromemco/rules.mk b/Kernel/platform-cromemco/rules.mk
new file mode 100644 (file)
index 0000000..c3701b0
--- /dev/null
@@ -0,0 +1 @@
+export BANKED=-thunked
diff --git a/Kernel/platform-cromemco/usermem.s b/Kernel/platform-cromemco/usermem.s
new file mode 100644 (file)
index 0000000..1682e92
--- /dev/null
@@ -0,0 +1,144 @@
+;
+;      We have a custom implementation of usermem. We really need
+;      to optimize ldir_to/from_user.
+;
+        .module usermem
+
+       .include "kernel.def"
+        .include "../kernel.def"
+
+        ; exported symbols
+        .globl __uget
+        .globl __ugetc
+        .globl __ugetw
+
+        .globl __uput
+        .globl __uputc
+        .globl __uputw
+        .globl __uzero
+
+       .globl ldir_from_user
+       .globl ldir_to_user
+
+        .area _COMMONMEM
+
+
+uputget:
+        ; load DE with the byte count
+        ld c, 8(ix) ; byte count
+        ld b, 9(ix)
+       ld a, b
+       or c
+       ret z           ; no work
+        ; load HL with the source address
+        ld l, 4(ix) ; src address
+        ld h, 5(ix)
+        ; load DE with destination address
+        ld e, 6(ix)
+        ld d, 7(ix)
+       ret
+
+__uget:
+       push ix
+       ld ix,#0
+       add ix, sp
+       call uputget
+       jr z, uget_out
+       push de
+       pop ix
+       call ldir_from_user
+uget_out:
+       pop ix
+       ld hl,#0
+       ret
+
+__uput:
+       push ix
+       ld ix,#0
+       add ix,sp
+       call uputget
+       jr z, uget_out
+       push de
+       pop ix
+       call ldir_to_user
+       jr uget_out
+
+;
+;      The kernel IRQ code will restore the bank if it interrupts this
+;      logic
+;
+__uzero:
+       pop de
+       pop hl
+       pop bc
+       push bc
+       push hl
+       push de
+       ld a,b
+       or c
+       ret z
+       ld a,(U_DATA__U_PAGE)
+       out (0x40),a            ; user bank
+       ld (hl),#0
+       dec bc
+       ld a,b
+       or c
+       jr z, uout
+       ld e,l
+       ld d,h
+       inc de
+       ldir
+uout:
+       ld a,#1
+       out (0x40),a
+       ret
+
+__ugetc:
+       pop bc
+       pop hl
+       push hl
+       push bc
+       ld a,(U_DATA__U_PAGE)
+       out (0x40),a
+       ld l,(hl)
+       ld h,#0
+       jr uout
+
+__ugetw:
+       pop bc
+       pop hl
+       push hl
+       push bc
+       ld a,(U_DATA__U_PAGE)
+       out (0x40),a
+       ld a,(hl)
+       inc hl
+       ld h,(hl)
+       ld l,a
+       jr uout
+       
+__uputc:
+       pop bc
+       pop de
+       pop hl
+       push hl
+       push de
+       push bc
+       ld a,(U_DATA__U_PAGE)
+       out (0x40),a
+       ld (hl),e
+       jr uout
+
+__uputw:
+       pop bc
+       pop de
+       pop hl
+       push hl
+       push de
+       push bc
+       ld a,(U_DATA__U_PAGE)
+       out (0x40),a
+       ld (hl),e
+       inc hl
+       ld (hl),d
+       jr uout
diff --git a/Kernel/platform-cromemco/vector.s b/Kernel/platform-cromemco/vector.s
new file mode 100644 (file)
index 0000000..67d1e60
--- /dev/null
@@ -0,0 +1,60 @@
+;
+;      Interrupt handlers. These will get replaced by some proper FIFO
+; logic
+;
+
+       .area _COMMONMEM
+       .module vector
+
+       .globl _rx0a_char
+       .globl _rx0a_int
+       .globl _tx0a_int
+       .globl interrupt_high
+
+       .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
+
+_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
+
+_uart0a_timer4:
+       jp interrupt_high
+
+_rx0a_char:
+       .byte 0
+_rx0a_int:
+       .byte 0
+_tx0a_int:
+       .byte 0