rc2014-tiny: quick debugging session
authorAlan Cox <alan@linux.intel.com>
Tue, 11 Sep 2018 22:00:32 +0000 (23:00 +0100)
committerAlan Cox <alan@linux.intel.com>
Tue, 11 Sep 2018 22:00:32 +0000 (23:00 +0100)
This seems to kind of work. I'm sure it's not perfect. Anyway it's mostly
intended as a bit of fun

21 files changed:
Kernel/platform-rc2014-tiny/Makefile [new file with mode: 0644]
Kernel/platform-rc2014-tiny/README [new file with mode: 0644]
Kernel/platform-rc2014-tiny/commonmem.s [new file with mode: 0644]
Kernel/platform-rc2014-tiny/config.h [new file with mode: 0644]
Kernel/platform-rc2014-tiny/crt0.s [new file with mode: 0644]
Kernel/platform-rc2014-tiny/devices.c [new file with mode: 0644]
Kernel/platform-rc2014-tiny/devinput.c [new file with mode: 0644]
Kernel/platform-rc2014-tiny/devinput.h [new file with mode: 0644]
Kernel/platform-rc2014-tiny/devtty.c [new file with mode: 0644]
Kernel/platform-rc2014-tiny/devtty.h [new file with mode: 0644]
Kernel/platform-rc2014-tiny/discard.c [new file with mode: 0644]
Kernel/platform-rc2014-tiny/fuzix.lnk [new file with mode: 0644]
Kernel/platform-rc2014-tiny/kernel.def [new file with mode: 0644]
Kernel/platform-rc2014-tiny/main.c [new file with mode: 0644]
Kernel/platform-rc2014-tiny/platform_ide.h [new file with mode: 0644]
Kernel/platform-rc2014-tiny/ppide.c [new file with mode: 0644]
Kernel/platform-rc2014-tiny/rc2014.h [new file with mode: 0644]
Kernel/platform-rc2014-tiny/rc2014.s [new file with mode: 0644]
Kernel/platform-rc2014-tiny/rules.mk [new file with mode: 0644]
Kernel/platform-rc2014-tiny/target.mk [new file with mode: 0644]
Kernel/platform-rc2014-tiny/tricks.s [new file with mode: 0644]

diff --git a/Kernel/platform-rc2014-tiny/Makefile b/Kernel/platform-rc2014-tiny/Makefile
new file mode 100644 (file)
index 0000000..4e44a3b
--- /dev/null
@@ -0,0 +1,56 @@
+ASRCS = crt0.s tricks.s commonmem.s rc2014.s
+CSRCS = devices.c main.c devtty.c
+DISCARD_CSRCS = discard.c
+DISCARD_DSRCS = ../dev/devide_discard.c ../dev/ds1302_discard.c
+DSRCS = ../dev/devide.c ../dev/mbr.c ../dev/blkdev.c
+DSRCS +=  ../dev/ds1302.c
+DASRCS = ../dev/ds1302_rc2014.s
+NSRCS = 
+
+AOBJS = $(ASRCS:.s=.rel)
+COBJS = $(CSRCS:.c=.rel)
+DISCARD_COBJS = $(DISCARD_CSRCS:.c=.rel)
+DISCARD_DOBJS = $(patsubst ../dev/%.c,%.rel, $(DISCARD_DSRCS))
+DOBJS = $(patsubst ../dev/%.c,%.rel, $(DSRCS))
+DAOBJS = $(patsubst ../dev/%.s,%.rel, $(DASRCS))
+NOBJS = $(patsubst ../dev/net/%.c,%.rel, $(NSRCS))
+
+OBJS  = $(AOBJS) $(COBJS) $(DOBJS) $(DAOBJS) $(DISCARD_DOBJS) $(DISCARD_COBJS) $(NOBJS)
+
+CROSS_CCOPTS += -I../dev/ -I../dev/net/
+
+CROSS_CC_HIGH = --codeseg COMMONMEM
+
+JUNK = *.rel *.lst *.asm *.sym *.rst *.map *.ihx *.bin
+
+all:   $(OBJS)
+
+$(AOBJS): %.rel: %.s
+       $(CROSS_AS) $(ASOPTS) $<
+
+$(COBJS): %.rel: %.c
+       $(CROSS_CC) $(CROSS_CCOPTS) -c $<
+
+$(DOBJS): %.rel: ../dev/%.c
+       $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_HIGH) -c $<
+
+$(DAOBJS): %.rel: ../dev/%.s
+       $(CROSS_AS) $(ASOPTS) $@ $<
+
+$(DISCARD_COBJS): %.rel: %.c
+       $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $<
+
+$(DISCARD_DOBJS): %.rel: ../dev/%.c
+       $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $<
+
+$(NOBJS): %.rel: ../dev/net/%.c
+       $(CROSS_CC) $(CROSS_CCOPTS) -c $<
+
+clean:
+       rm -f $(OBJS) $(JUNK)  core *~ diskstrap fuzix.rom
+
+image:
+       dd if=../fuzix.bin of=fuzix.rom bs=32768 count=1
+       # We have a 512 byte hole we leave for the loader
+       dd if=../fuzix.bin of=diskstrap bs=33280 count=1 skip=1
+
diff --git a/Kernel/platform-rc2014-tiny/README b/Kernel/platform-rc2014-tiny/README
new file mode 100644 (file)
index 0000000..0f94924
--- /dev/null
@@ -0,0 +1,34 @@
+This is a prototype Fuzix for the RC2014 with only the pageable ROM. Fuzix
+occupies the ROM and loads its data and high space from disk on boot.
+
+This is btw not a good way to run Fuzix, it's more for the challenge!
+
+Memory map
+
+Kernel mode
+
+0000-7FFF      Kernel (and bootstrap)
+8000-BFFF      Discardables / Userspace
+C000-FFFF      Kernel
+
+User mode (one process in memory at a time, swap mandatory)
+
+0000-BFFF      User space
+C000-FFFF      Kernel
+
+
+Things that don't work
+
+  * Flow control isn't yet enabled for the serial port.
+
+Stuff To Do
+
+  * SIO v ACIA detection is bust
+
+  * It could be made a chunk smaller if we dumped the nice fancy IDE support
+    for simple block IDE without full partitions etc.
+
+  * Set up SIO with some kind of fast IRQ path or we'll drop a lot of bytes
+    (perhaps in IRQ only do rtc check if fifo empty or something ?)
+
+  * RETI fix on polled SIO path
diff --git a/Kernel/platform-rc2014-tiny/commonmem.s b/Kernel/platform-rc2014-tiny/commonmem.s
new file mode 100644 (file)
index 0000000..1288445
--- /dev/null
@@ -0,0 +1,9 @@
+;
+;      Common is placed at 0xF000 by fuzix.lnk
+;
+
+        .module commonmem
+
+        .area _COMMONMEM
+
+       .include "../cpu-z80/std-commonmem.s"
diff --git a/Kernel/platform-rc2014-tiny/config.h b/Kernel/platform-rc2014-tiny/config.h
new file mode 100644 (file)
index 0000000..184048c
--- /dev/null
@@ -0,0 +1,65 @@
+/* Enable to make ^Z dump the inode table for debug */
+#undef CONFIG_IDUMP
+/* Enable to make ^A drop back into the monitor */
+#undef CONFIG_MONITOR
+/* Profil syscall support (not yet complete) */
+#undef CONFIG_PROFIL
+/* Multiple processes in memory at once */
+#undef CONFIG_MULTI
+/* Swap based one process in RAM */
+#define CONFIG_SWAP_ONLY
+/* Permit large I/O requests to bypass cache and go direct to userspace */
+#define CONFIG_LARGE_IO_DIRECT
+/* One memory bank */
+#define CONFIG_BANKS   1
+#define TICKSPERSEC 10      /* Ticks per second */
+#define PROGBASE    0x0000  /* also data base */
+#define PROGLOAD    0x0100  /* also data base */
+#define PROGTOP     0xC000  /* Top of program */
+#define KERNTOP            0xFFFF  /* common grows from C000, buffers above*/
+
+#define PROC_SIZE   48   /* Memory needed per process */
+
+#define SWAPDEV     (swap_dev) /* A variable for dynamic, or a device major/minor */
+extern unsigned int swap_dev;
+#define SWAP_SIZE   0x61       /* 48.5K in blocks (prog + udata) */
+#define SWAPBASE    0x0000     /* start at the base of user mem */
+#define SWAPTOP            0xC200      /* Swap out udata and program */
+#define MAX_SWAPS   16         /* We will size if from the partition */
+/* Swap will be set up when a suitably labelled partition is seen */
+#define CONFIG_DYNAMIC_SWAP
+
+/*
+ *     When the kernel swaps something it needs to map the right page into
+ *     memory using map_for_swap and then turn the user address into a
+ *     physical address. For a simple banked setup there is no conversion
+ *     needed so identity map it.
+ */
+#define swap_map(x)    ((uint8_t *)(x))
+
+/* We need a tidier way to do this from the loader */
+#define CMDLINE        NULL  /* Location of root dev name */
+#define BOOTDEVICENAMES "hd#,fd,,rd"
+
+#define CONFIG_DYNAMIC_BUFPOOL /* we expand bufpool to overwrite the _DISCARD segment at boot */
+#define NBUFS    4        /* Number of block buffers, keep in line with space reserved in zeta-v2.s */
+#define NMOUNTS         2        /* Number of mounts at a time */
+
+#define MAX_BLKDEV 4       /* 1 ROM disk, 1 RAM disk, 1 floppy, 1 IDE */
+
+/* On-board DS1302, we can read the time of day from it */
+#define CONFIG_RTC
+#define CONFIG_RTC_FULL
+#define CONFIG_NO_CLOCK
+
+/* IDE/CF support */
+#define CONFIG_IDE
+
+/* Device parameters */
+#define NUM_DEV_TTY 2
+
+/* UART0 as the console */
+#define BOOT_TTY (512 + 1)
+#define TTY_INIT_BAUD B115200  /* Hardwired generally */
+
+#define TTYDEV   BOOT_TTY /* Device used by kernel for messages, panics */
diff --git a/Kernel/platform-rc2014-tiny/crt0.s b/Kernel/platform-rc2014-tiny/crt0.s
new file mode 100644 (file)
index 0000000..9757445
--- /dev/null
@@ -0,0 +1,165 @@
+; 2015-02-20 Sergey Kiselev
+; 2013-12-18 William R Sowerbutts
+
+        .module crt0
+
+        ; Ordering of segments for the linker.
+        ; WRS: Note we list all our segments here, even though
+        ; we don't use them all, because their ordering is set
+        ; when they are first seen.
+
+       ; Start with the ROM area CODE-CODE2
+        .area _CODE
+        .area _HOME     ; compiler stores __mullong etc in here if you use them
+        .area _CODE2
+       ; Discard is loaded where process memory wil blow it away
+        .area _DISCARD
+       ; The rest grows upwards from C000 starting with the udata so we can
+       ; swap in one block, ending with the buffers so they can expand up
+        .area _COMMONMEM
+        .area _CONST
+        .area _INITIALIZED
+        .area _DATA
+        .area _BSEG
+        .area _BSS
+        .area _HEAP
+        ; note that areas below here may be overwritten by the heap at runtime, so
+        ; put initialisation stuff in here
+        .area _BUFFERS     ; _BUFFERS grows to consume all before it (up to KERNTOP)
+       ; These get overwritten and don't matter
+        .area _INITIALIZER ; binman copies this to the right place for us
+        .area _GSINIT      ; unused
+        .area _GSFINAL     ; unused
+
+        ; exported symbols
+        .globl init
+
+        ; imported symbols
+        .globl _fuzix_main
+        .globl init_hardware
+        .globl s__INITIALIZER
+        .globl s__COMMONMEM
+        .globl l__COMMONMEM
+        .globl s__DISCARD
+        .globl l__DISCARD
+        .globl s__DATA
+        .globl l__DATA
+        .globl kstack_top
+
+       .globl interrupt_handler
+       .globl nmi_handler
+
+       .include "kernel.def"
+
+        ; startup code
+        .area _PAGE0(ABS)
+
+.org   0
+
+restart0:
+       jp init
+       .ds 5
+restart8:
+       .ds 8
+restart10:
+       .ds 8
+restart18:
+       .ds 8
+restart20:
+       .ds 8
+restart28:
+       .ds 8
+restart30:
+       .ds 8
+restart38:
+       jp interrupt_handler
+       .ds 5
+; 0x40
+       .ds 26
+; 0x66
+       jp nmi_handler
+;
+;      And 0x69 onwards we could use for code
+;
+
+       ; Starts at 0x0080 at the moment
+
+       .area _CODE
+
+init:  
+        di
+       ld sp,#0x8200           ; safe spot
+
+       ; Init the ATA CF
+       ; For now this is fairly dumb.
+       ; We ought to init the UART here first so we can say something
+       ; before loading.
+       ld a,#0xE0
+       out (0x16),a
+       xor a
+       out (0x14),a
+       out (0x15),a
+       ; Set 8bit mode
+       call wait_ready
+       ld a, #1                ; 8bit PIO
+       out (0x11),a
+       ld a, #0xEF             ; SET FEATURES (8bit PIO)
+       out (0x17),a
+       call wait_ready
+
+       ; Load and map the rest of the image
+       ld d,#1
+       ld bc,#0x10             ; c = data port  b = 0
+       ld hl,#0x8200           ; Load 8200-FFFF
+loader:
+       inc d
+       call load_sector
+       bit 6,d                 ; load 64 sectors 2-66
+       jr z, loader
+
+        ; switch to stack in high memory
+        ld sp, #kstack_top
+
+        ; Zero the data area
+        ld hl, #s__DATA
+        ld de, #s__DATA + 1
+        ld bc, #l__DATA - 1
+        ld (hl), #0
+        ldir
+
+        ; Hardware setup
+        call init_hardware
+
+        ; Call the C main routine
+        call _fuzix_main
+    
+        ; fuzix_main() shouldn't return, but if it does...
+        di
+stop:   halt
+        jr stop
+
+;
+;      Load sector d from disk into HL and advance HL accordingly
+;
+load_sector:
+       ld a,d
+       out (0x13),a            ; LBA
+       ld a,#1
+       out (0x12),a            ; 1 sector
+       ld a,#0x20
+       out (0x17),a            ; command
+       ; Wait 
+wait_drq:
+       in a,(0x17)
+       bit 3,a
+       jr z, wait_drq
+       ; Get data, leave HL pointing to next byte, leaves B as 0 again
+       inir
+       inir
+       ret
+wait_ready:
+       in a,(0x17)
+       bit 6,a
+       jr z,wait_ready
+       ret
+       
\ No newline at end of file
diff --git a/Kernel/platform-rc2014-tiny/devices.c b/Kernel/platform-rc2014-tiny/devices.c
new file mode 100644 (file)
index 0000000..f3f1029
--- /dev/null
@@ -0,0 +1,37 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <tty.h>
+#include <devsys.h>
+#include <devtty.h>
+#include <blkdev.h>
+#include <ds1302.h>
+
+struct devsw dev_tab[] =  /* The device driver switch table */
+{
+/*   open          close       read            write           ioctl */
+  /* 0: /dev/hd - block device interface */
+#ifdef CONFIG_IDE
+  {  blkdev_open,   no_close,   blkdev_read,    blkdev_write,  blkdev_ioctl},
+#else
+  {  no_open,      no_close,   no_rdwr,        no_rdwr,        no_ioctl},
+#endif
+  /* 1: /dev/fd - Floppy disk block devices */
+  {  no_open,      no_close,   no_rdwr,        no_rdwr,        no_ioctl},
+  /* 2: /dev/tty -- serial ports */
+  {  tty_open,     tty_close,  tty_read,       tty_write,      tty_ioctl},
+  /* 3: RAM disk */
+  {  no_open,      no_close,   no_rdwr,        no_rdwr,        no_ioctl},
+  /* 4: /dev/mem etc      System devices (one offs) */
+  {  no_open,      no_close,   sys_read,       sys_write,      sys_ioctl},
+};
+
+bool validdev(uint16_t dev)
+{
+       /* This is a bit uglier than needed but the right hand side is
+        a constant this way */
+       if(dev > ((sizeof(dev_tab)/sizeof(struct devsw)) << 8) + 255)
+               return false;
+       else
+               return true;
+}
diff --git a/Kernel/platform-rc2014-tiny/devinput.c b/Kernel/platform-rc2014-tiny/devinput.c
new file mode 100644 (file)
index 0000000..4e5eb54
--- /dev/null
@@ -0,0 +1,61 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <input.h>
+#include <devinput.h>
+
+__sfr __at 0x01 js1;
+__sfr __at 0x02 js2;
+
+static uint8_t js_data[2]= {255, 255};
+
+uint8_t read_js(uint8_t *slot, uint8_t n, uint8_t r)
+{
+    uint8_t d = 0;
+    r &= 63;
+    if (r == js_data[n])
+        return 0;
+    js_data[n] = r;
+    if (r & 1)
+        d = STICK_DIGITAL_U;
+    if (r & 2)
+        d |= STICK_DIGITAL_D;
+    if (r & 4)
+        d |= STICK_DIGITAL_L;
+    if (r & 8)
+        d |= STICK_DIGITAL_R;
+    if (r & 16)
+        d |= BUTTON(0);
+    if (r & 32)
+        d |= BUTTON(1);
+    *slot++ = STICK_DIGITAL | (n + 1);
+    *slot = d;
+    return 2;
+}
+
+int platform_input_read(uint8_t *slot)
+{
+    if (read_js(slot, 0, js1))
+        return 2;
+    if (read_js(slot, 1, js2))
+        return 2;
+    return 0;
+}
+
+void platform_input_wait(void)
+{
+    psleep(&js_data);
+}
+
+void poll_input(void)
+{
+    if ((js1 & 63) != js_data[0] ||
+        ((js2 & 63) != js_data[1]))
+        wakeup(&js_data);
+}
+
+int platform_input_write(uint8_t flag)
+{
+    flag;
+    udata.u_error = EINVAL;
+    return -1;
+}
diff --git a/Kernel/platform-rc2014-tiny/devinput.h b/Kernel/platform-rc2014-tiny/devinput.h
new file mode 100644 (file)
index 0000000..5e7922a
--- /dev/null
@@ -0,0 +1 @@
+extern void poll_input(void);
diff --git a/Kernel/platform-rc2014-tiny/devtty.c b/Kernel/platform-rc2014-tiny/devtty.c
new file mode 100644 (file)
index 0000000..4b3d955
--- /dev/null
@@ -0,0 +1,142 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <tty.h>
+#include <devtty.h>
+#include <rc2014.h>
+
+char tbuf1[TTYSIZ];
+char tbuf2[TTYSIZ];
+
+uint8_t ser_type = 1;
+
+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},
+};
+
+void tty_setup(uint8_t minor)
+{
+       if (minor == 1) {
+       }
+}
+
+int tty_carrier(uint8_t minor)
+{
+//      uint8_t c;
+       if (minor == 1) {
+//              c = UART0_MSR;
+//              return (c & 0x80) ? 1 : 0; /* test DCD */
+       }
+       return 1;
+}
+
+void tty_pollirq_sio(void)
+{
+       uint8_t ca, cb;
+
+       /* FIXME: need to process error/event interrupts as we can get
+          spurious characters or lines on an unused SIO floating */
+       do {
+               SIOA_C = 0;             // read register 0
+               ca = SIOA_C;
+               if (ca & 1)
+                       tty_inproc(1, SIOA_D);
+               if (ca & 4) {
+                       tty_outproc(1);
+                       SIOA_C = 5 << 3;        // reg 0 CMD 5 - reset transmit interrupt pending
+               }
+               SIOB_C = 0;             // read register 0
+               cb = SIOB_C;
+               if (cb & 1)
+                       tty_inproc(2, SIOB_D);
+               if (cb & 4) {
+                       tty_outproc(2);
+                       SIOB_C = 5 << 3;        // reg 0 CMD 5 - reset transmit interrupt pending
+               }
+       } while((ca | cb) & 1);
+}
+
+void tty_pollirq_acia(void)
+{
+       uint8_t ca;
+
+       ca = ACIA_C;
+       if (ca & 1) {
+               tty_inproc(1, ACIA_D);
+       }
+       if (ca & 2) {
+               tty_outproc(1);
+       }
+}
+
+static char hex[] = { "0123456789ABCDEF" };
+
+void tty_putc(uint8_t minor, unsigned char c)
+{
+       if (ser_type == 1) {
+               if (minor == 1) {
+                       SIOA_D = c;
+               } else if (minor == 2)
+                       SIOB_D = c;
+       } else if (minor == 1)
+               ACIA_D = c;
+       else if (minor = 3) {
+               /* FIXME: implement */
+       }
+}
+
+/* We will need this for SIO once we implement flow control signals */
+void tty_sleeping(uint8_t minor)
+{
+}
+
+/* Be careful here. We need to peek at RR but we must be sure nobody else
+   interrupts as we do this. Really we want to switch to irq driven tx ints
+   on this platform I think. Need to time it and see
+
+   An asm common level tty driver might be a better idea */
+ttyready_t tty_writeready(uint8_t minor)
+{
+       irqflags_t irq;
+       uint8_t c;
+       if (ser_type == 1) {
+               irq = di();
+               if (minor == 1) {
+                       SIOA_C = 0;     /* read register 0 */
+                       c = SIOA_C;
+                       irqrestore(irq);
+                       if (c & 0x04)   /* THRE? */
+                               return TTY_READY_NOW;
+                       return TTY_READY_SOON;
+               } else if (minor == 2) {
+                       SIOB_C = 0;     /* read register 0 */
+                       c = SIOB_C;
+                       irqrestore(irq);
+                       if (c & 0x04)   /* THRE? */
+                               return TTY_READY_NOW;
+                       return TTY_READY_SOON;
+               }
+               irqrestore(irq);
+       } else if (ser_type == 2 && minor == 1) {
+               c = ACIA_C;
+               if (c & 0x02)   /* THRE? */
+                       return TTY_READY_NOW;
+               return TTY_READY_SOON;
+       }
+       return TTY_READY_NOW;
+}
+
+void tty_data_consumed(uint8_t minor)
+{
+}
+
+/* kernel writes to system console -- never sleep! */
+void kputchar(char c)
+{
+       tty_putc(TTYDEV - 512, c);
+       if (c == '\n')
+               tty_putc(TTYDEV - 512, '\r');
+}
diff --git a/Kernel/platform-rc2014-tiny/devtty.h b/Kernel/platform-rc2014-tiny/devtty.h
new file mode 100644 (file)
index 0000000..518450e
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __DEVTTY_DOT_H__
+#define __DEVTTY_DOT_H__
+
+void tty_putc(uint8_t minor, unsigned char c);
+void tty_pollirq_sio(void);
+void tty_pollirq_acia(void);
+
+extern uint8_t ser_type;
+
+#endif
diff --git a/Kernel/platform-rc2014-tiny/discard.c b/Kernel/platform-rc2014-tiny/discard.c
new file mode 100644 (file)
index 0000000..5766275
--- /dev/null
@@ -0,0 +1,41 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+#include <ds1302.h>
+#include <devide.h>
+#include <blkdev.h>
+#include "config.h"
+
+void map_init(void)
+{
+}
+
+/*
+ *     This function is called for partitioned devices if a partition is found
+ *     and marked as swap type. The first one found will be used as swap. We
+ *     only support one swap device.
+ */
+void platform_swap_found(uint8_t letter, uint8_t m)
+{
+  blkdev_t *blk = blk_op.blkdev;
+  uint16_t n;
+  if (swap_dev != 0xFFFF)
+    return;
+  letter -= 'a';
+  kputs("(swap) ");
+  swap_dev = letter << 4 | m;
+  n = blk->lba_count[m - 1] / SWAP_SIZE;
+  if (n > MAX_SWAPS)
+    n = MAX_SWAPS;
+  while(n)
+    swapmap_add(n--);
+}
+
+void device_init(void)
+{
+       ds1302_init();
+#ifdef CONFIG_IDE
+       devide_init();
+#endif
+}
diff --git a/Kernel/platform-rc2014-tiny/fuzix.lnk b/Kernel/platform-rc2014-tiny/fuzix.lnk
new file mode 100644 (file)
index 0000000..ce72d6a
--- /dev/null
@@ -0,0 +1,45 @@
+-mwxuy
+-i fuzix.ihx
+-b _CODE=0x0080
+-b _COMMONMEM=0xC000
+-b _DISCARD=0x8200
+-b _INITIALIZER=0xA000
+-l z80
+platform-rc2014-tiny/crt0.rel
+platform-rc2014-tiny/commonmem.rel
+platform-rc2014-tiny/rc2014.rel
+start.rel
+version.rel
+lowlevel-z80.rel
+platform-rc2014-tiny/tricks.rel
+platform-rc2014-tiny/main.rel
+timer.rel
+kdata.rel
+platform-rc2014-tiny/devices.rel
+devio.rel
+filesys.rel
+process.rel
+inode.rel
+syscall_exec16.rel
+syscall_fs.rel
+syscall_proc.rel
+syscall_fs2.rel
+syscall_fs3.rel
+syscall_other.rel
+mm.rel
+swap.rel
+simple.rel
+tty.rel
+devsys.rel
+usermem.rel
+usermem_std-z80.rel
+platform-rc2014-tiny/discard.rel
+platform-rc2014-tiny/devtty.rel
+platform-rc2014-tiny/mbr.rel
+platform-rc2014-tiny/blkdev.rel
+platform-rc2014-tiny/devide.rel
+platform-rc2014-tiny/devide_discard.rel
+platform-rc2014-tiny/ds1302.rel
+platform-rc2014-tiny/ds1302_discard.rel
+platform-rc2014-tiny/ds1302_rc2014.rel
+-e
diff --git a/Kernel/platform-rc2014-tiny/kernel.def b/Kernel/platform-rc2014-tiny/kernel.def
new file mode 100644 (file)
index 0000000..f7ca5ea
--- /dev/null
@@ -0,0 +1,24 @@
+; FUZIX mnemonics for memory addresses etc
+
+U_DATA                 .equ    0xC000  ; (this is struct u_data from kernel.h)
+U_DATA__TOTALSIZE      .equ    0x300   ; 256+256+256 bytes.
+Z80_TYPE               .equ    1       ; CMOS
+
+Z80_MMU_HOOKS          .equ 0
+
+CONFIG_SWAP            .equ 1
+
+PROGBASE               .equ    0x0000
+PROGLOAD               .equ    0x0100
+
+; Mnemonics for I/O ports etc
+
+CONSOLE_RATE           .equ    115200
+
+CPU_CLOCK_KHZ          .equ    7372
+
+; Z80 CTC ports
+CTC_CH0                .equ    0x88    ; CTC channel 0 and interrupt vector
+CTC_CH1                .equ    0x89    ; CTC channel 1 (periodic interrupts)
+CTC_CH2                .equ    0x8A    ; CTC channel 2
+CTC_CH3                .equ    0x8B    ; CTC channel 3
diff --git a/Kernel/platform-rc2014-tiny/main.c b/Kernel/platform-rc2014-tiny/main.c
new file mode 100644 (file)
index 0000000..1a01036
--- /dev/null
@@ -0,0 +1,122 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <timer.h>
+#include <devtty.h>
+#include <devfd.h>
+#include <devinput.h>
+#include <rtc.h>
+#include <ds1302.h>
+
+extern unsigned char irqvector;
+struct blkbuf *bufpool_end = bufpool + NBUFS;  /* minimal for boot -- expanded after we're done with _DISCARD */
+uint8_t timermsr = 0;
+uint16_t swap_dev = 0xFFFF;
+uint16_t ramtop = 0xC000;
+uint8_t need_resched = 0;
+
+
+void platform_discard(void)
+{
+       while (bufpool_end < (struct blkbuf *) (KERNTOP - sizeof(struct blkbuf))) {
+               memset(bufpool_end, 0, sizeof(struct blkbuf));
+#if BF_FREE != 0
+               bufpool_end->bf_busy = BF_FREE; /* redundant when BF_FREE == 0 */
+#endif
+               bufpool_end->bf_dev = NO_DEVICE;
+               bufpool_end++;
+       }
+}
+
+static uint8_t idlect;
+
+void platform_idle(void)
+{
+       /* Check the clock. We try and reduce the impact of the clock on
+          latency by not doing it so often. 256 may be too small a divide
+          need t see what 1/10th sec looks like in poll loops */
+       if (!idlect++)
+               sync_clock();
+}
+
+uint8_t platform_param(unsigned char *p)
+{
+       used(p);
+       return 0;
+}
+
+void platform_interrupt(void)
+{
+       /* FIXME: need to cover ACIA option.. */
+       tty_pollirq_sio();
+       return;
+}
+
+/*
+ *     Logic for tickless system. If you have an RTC you can ignore this.
+ */
+
+static uint8_t newticks = 0xFF;
+static uint8_t oldticks;
+
+static uint8_t re_enter;
+
+/*
+ *     Hardware specific logic to get the seconds. We really ought to enhance
+ *     this to check minutes as well just in case something gets stuck for
+ *     ages.
+ */
+static void sync_clock_read(void)
+{
+       uint8_t s;
+       oldticks = newticks;
+       ds1302_read_clock(&s, 1);
+       s = (s & 0x0F) + (((s & 0xF0) >> 4) * 10);
+       newticks = s;
+}
+
+/*
+ *     The OS core will invoke this routine when idle (via platform_idle) but
+ *     also after a system call and in certain other spots to ensure the clock
+ *     is roughly valid. It may be called from interrupts, without interrupts
+ *     or even recursively so it must protect itself using the framework
+ *     below.
+ *
+ *     Having worked out how much time has passed in 1/10ths of a second it
+ *     performs that may timer_interrupt events in order to advance the clock.
+ *     The core kernel logic ensures that we won't do anything silly from a
+ *     jump forward of many seconds.
+ *
+ *     We also choose to poll the ttys here so the user has some chance of
+ *     getting control back on a messed up process.
+ */
+void sync_clock(void)
+{
+       if (!timermsr) {
+               irqflags_t irq = di();
+               int16_t tmp;
+               if (!re_enter++) {
+                       sync_clock_read();
+                       if (oldticks != 0xFF) {
+                               tmp = newticks - oldticks;
+                               if (tmp < 0)
+                                       tmp += 60;
+                               tmp *= 10;
+                               while(tmp--) {
+                                       timer_interrupt();
+                               }
+                       }
+                       re_enter--;
+               }
+               irqrestore(irq);
+       }
+}
+
+/*
+ *     This method is called if the kernel has changed the system clock. We
+ *     don't work out how much work we need to do by using it as a reference
+ *     so we don't care.
+ */
+void update_sync_clock(void)
+{
+}
diff --git a/Kernel/platform-rc2014-tiny/platform_ide.h b/Kernel/platform-rc2014-tiny/platform_ide.h
new file mode 100644 (file)
index 0000000..8343e58
--- /dev/null
@@ -0,0 +1,6 @@
+#define ide_select(x)
+#define ide_deselect()
+
+/*8bit, no altstatus/control */
+#define IDE_8BIT_ONLY
+#define IDE_REG_CS1_BASE   0x10
diff --git a/Kernel/platform-rc2014-tiny/ppide.c b/Kernel/platform-rc2014-tiny/ppide.c
new file mode 100644 (file)
index 0000000..4e80bf1
--- /dev/null
@@ -0,0 +1,121 @@
+/* 2015-04-24 WRS: devide glue functions for PPIDE */
+
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <timer.h>
+#include <devide.h>
+#include <blkdev.h>
+
+__sfr __at (PPIDE_BASE + 0x00) ppi_port_a;   /* IDE bus LSB */
+__sfr __at (PPIDE_BASE + 0x01) ppi_port_b;   /* IDE bus MSB */
+__sfr __at (PPIDE_BASE + 0x02) ppi_port_c;   /* IDE bus control signals */
+__sfr __at (PPIDE_BASE + 0x03) ppi_control;  /* 8255 command register */
+
+void ppide_init(void)
+{
+    ppi_control = PPIDE_PPI_BUS_READ;
+    ppi_port_c = ide_reg_status;
+}
+
+uint8_t devide_readb(uint8_t regaddr)
+{
+    uint8_t r;
+
+    /* note: ppi_control should contain PPIDE_PPI_BUS_READ already */
+    ppi_port_c = regaddr;
+    ppi_control = 1 | (PPIDE_RD_BIT << 1); /* begin /RD pulse */
+    r = ppi_port_a;
+    ppi_control = 0 | (PPIDE_RD_BIT << 1); /* end /RD pulse */
+    return r;
+}
+
+void devide_writeb(uint8_t regaddr, uint8_t value)
+{
+    ppi_control = PPIDE_PPI_BUS_WRITE;
+    ppi_port_c = regaddr;
+    ppi_port_a = value;
+    ppi_port_b = 0;
+    ppi_control = 1 | (PPIDE_WR_BIT << 1); /* begin /WR pulse */
+    ppi_control = 0 | (PPIDE_WR_BIT << 1); /* end /WR pulse */
+    ppi_control = PPIDE_PPI_BUS_READ;
+}
+
+/****************************************************************************/
+/* The innermost part of the transfer routines has to live in common memory */
+/* since it must be able to bank switch to the user memory bank.            */
+/****************************************************************************/
+COMMON_MEMORY
+
+void devide_read_data(void) __naked
+{
+    __asm
+            ld a, #ide_reg_data
+            ld c, #PPIDE_BASE+2                     ; select control lines
+            out (c), a                              ; select IDE data register
+            ld hl, (_blk_op+BLKPARAM_ADDR_OFFSET)   ; blkparam.addr
+            ld d, #ide_reg_data                     ; register address
+            ld e, #ide_reg_data | PPIDE_RD_LINE     ; register address with /RD asserted
+            ld b, #0                                ; setup count
+            ld a, (_blk_op+BLKPARAM_IS_USER_OFFSET) ; blkparam.is_user
+            or a                                    ; test is_user
+            push af                                 ; save flags
+            ld a, #PPIDE_BASE+0                     ; I will be needing this later
+            call nz, map_process_always             ; map user memory first if required
+goread:     ; now we do the transfer
+            out (c), e                              ; assert /RD
+            ld c, a                                 ; PPIDE_BASE
+            ini                                     ; read byte from LSB
+            inc c                                   ; up to MSB
+            ini                                     ; read byte from MSB
+            inc c                                   ; control lines
+            out (c), d                              ; de-assert /RD
+            inc b                                   ; (delay) counteract second ini instruction
+            jr nz, goread                           ; (delay) next word
+            ; read completed
+            pop af                                  ; recover is_user test result
+            ret z                                   ; done if kernel memory transfer
+            jp map_kernel                           ; else map kernel then return
+    __endasm;
+}
+
+void devide_write_data(void) __naked
+{
+    __asm
+            ld c, #PPIDE_BASE+2                     ; select control lines
+            ld a, #ide_reg_data
+            out (c), a                              ; select data register
+            ld a, #PPIDE_PPI_BUS_WRITE
+            inc c                                   ; up to 8255A command register
+            out (c), a                              ; 8255A ports A, B to output mode
+            dec c                                   ; back down to the control lines
+            ld hl, (_blk_op+BLKPARAM_ADDR_OFFSET)   ; blkparam.addr
+            ld d, #ide_reg_data                     ; register address
+            ld e, #ide_reg_data | PPIDE_WR_LINE     ; register address with /WR asserted
+            ld b, #0                                ; setup count
+            ld a, (_blk_op+BLKPARAM_IS_USER_OFFSET) ; blkparam.is_user
+            or a                                    ; test is_user
+            push af                                 ; save flags
+            ld a, #PPIDE_BASE+0                     ; I will be needing this later
+            call nz, map_process_always             ; map user memory first if required
+gowrite:    ; now we do the transfer
+            out (c), d                              ; de-assert /WR
+            ld c, a                                 ; PPIDE_BASE
+            outi                                    ; write byte to LSB
+            inc c                                   ; up to MSB
+            outi                                    ; write byte to MSB
+            inc c                                   ; up to control lines
+            out (c), e                              ; assert /WR
+            inc b                                   ; (delay) offset to counteract second outi instruction
+            jr nz, gowrite                          ; (delay) next word
+            ; write completed
+            out (c), d                              ; de-assert /WR
+            ld a, #PPIDE_PPI_BUS_READ
+            inc c                                   ; up to 8255A command register
+            out (c), a                              ; 8255A ports A, B to read mode
+            pop af                                  ; recover is_user test result
+            ret z                                   ; done if kernel memory transfer
+            jp map_kernel                           ; else map kernel then return
+    __endasm;
+}
diff --git a/Kernel/platform-rc2014-tiny/rc2014.h b/Kernel/platform-rc2014-tiny/rc2014.h
new file mode 100644 (file)
index 0000000..2cf8404
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef __RC2014_SIO_DOT_H__
+#define __RC2014_SIO_DOT_H__
+
+#include "config.h"
+
+#define SIO0_IVT 8
+
+/* Standard RC2014 */
+#define SIO0_BASE 0x80
+__sfr __at (SIO0_BASE + 0) SIOA_C;
+__sfr __at (SIO0_BASE + 1) SIOA_D;
+__sfr __at (SIO0_BASE + 2) SIOB_C;
+__sfr __at (SIO0_BASE + 3) SIOB_D;
+
+/* ACIA is at same address as SIO but we autodetect */
+
+#define ACIA_BASE 0x80
+__sfr __at (ACIA_BASE + 0) ACIA_C;
+__sfr __at (ACIA_BASE + 1) ACIA_D;
+
+#endif
diff --git a/Kernel/platform-rc2014-tiny/rc2014.s b/Kernel/platform-rc2014-tiny/rc2014.s
new file mode 100644 (file)
index 0000000..0165650
--- /dev/null
@@ -0,0 +1,437 @@
+; 2014-02-19 Sergey Kiselev
+; RC2014 hardware specific code
+
+        .module rc2014
+
+        ; exported symbols
+        .globl init_hardware
+       .globl _program_vectors
+       .globl map_kernel
+       .globl map_process
+       .globl map_process_always
+       .globl map_save
+       .globl map_restore
+       .globl map_for_swap
+       .globl platform_interrupt_all
+       .globl _platform_reboot
+       .globl _platform_monitor
+       .globl _bufpool
+
+        ; imported symbols
+        .globl _ramsize
+        .globl _procmem
+        .globl outhl
+        .globl outnewline
+       .globl interrupt_handler
+       .globl unix_syscall_entry
+       .globl nmi_handler
+       .globl null_handler
+       .globl _ser_type
+
+       ; exported debugging tools
+       .globl inchar
+       .globl outchar
+
+        .include "kernel.def"
+        .include "../kernel.def"
+
+;=========================================================================
+; Constants
+;=========================================================================
+CONSOLE_DIVISOR                .equ    (1843200 / (16 * CONSOLE_RATE))
+CONSOLE_DIVISOR_HIGH   .equ    (CONSOLE_DIVISOR >> 8)
+CONSOLE_DIVISOR_LOW    .equ    (CONSOLE_DIVISOR & 0xFF)
+
+RTS_HIGH       .EQU    0xE8
+RTS_LOW                .EQU    0xEA
+
+; Base address of SIO/2 chip 0x80
+; For the Scott Baker SIO card adjust the order to match rc2014.h
+SIOA_C         .EQU    0x80
+SIOA_D         .EQU    SIOA_D+1
+SIOB_C         .EQU    SIOA_D+2
+SIOB_D         .EQU    SIOA_D+3
+
+SIO_IV          .EQU    8               ; Interrupt vector table entry to use
+
+ACIA_C          .EQU     0x80
+ACIA_D          .EQU     0x81
+ACIA_RESET      .EQU     0x03
+ACIA_RTS_HIGH_A      .EQU     0xD6   ; rts high, xmit interrupt disabled
+ACIA_RTS_LOW_A       .EQU     0x96   ; rts low, xmit interrupt disabled
+;ACIA_RTS_LOW_A       .EQU     0xB6   ; rts low, xmit interrupt enabled
+
+;=========================================================================
+; Buffers
+;=========================================================================
+        .area _BUFFERS
+_bufpool:
+        .ds (BUFSIZE * 4) ; adjust NBUFS in config.h in line with this
+
+;=========================================================================
+; Initialization code
+;=========================================================================
+        .area _DISCARD
+init_hardware:
+       ld hl,#64
+       ld (_ramsize), hl
+       ld hl,#48
+       ld (_procmem), hl
+       ; 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
+       jr 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 nz, not_acia_either
+        ld a, #ACIA_RTS_LOW_A
+        out (c),a                      ; Initialise ACIA
+       ld a,#2
+       ld (_ser_type),a
+       ret
+
+       ;
+       ; 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
+
+        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,#0x02
+        out (SIOB_C),a
+        ld a,#SIO_IV           ; INTERRUPT VECTOR ADDRESS (needs to go)
+        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
+
+        ; ---------------------------------------------------------------------
+       ; Initialize CTC
+       ;
+       ; We must initialize all channels of the CTC. The documentation
+       ; states that the initial CTC state is undefined and we don't want
+       ; random interrupt surprises
+       ; ---------------------------------------------------------------------
+
+       ld a,#0x57                      ; counter mode, disable interrupts
+       out (CTC_CH0),a                 ; set CH0 mode
+       ld a,#0                         ; time constant = 256
+       out (CTC_CH0),a                 ; set CH0 time constant
+       ld a,#0x57                      ; counter mode, FIXME C7 enable interrupts
+       out (CTC_CH1),a                 ; set CH1 mode
+       ld a,#180                       ; time constant = 180
+       out (CTC_CH1),a                 ; set CH1 time constant
+       ld a,#0x57                      ; counter mode, disable interrupts
+       out (CTC_CH2),a                 ; set CH2 mode
+       ld a,#0x57                      ; counter mode, disable interrupts
+       out (CTC_CH3),a                 ; set CH3 mode
+
+        ; Done CTC Stuff
+        ; ---------------------------------------------------------------------
+
+       im 1                            ; set Z80 CPU interrupt mode 1
+       ret
+
+;=========================================================================
+; Kernel code
+;=========================================================================
+        .area _CODE
+
+_platform_monitor:
+       di
+       halt
+_platform_reboot:
+        ; We need to map the ROM back in -- ideally into every page.
+        ; This little trick based on a clever suggestion from John Coffman.
+       call map_kernel
+       rst 0
+
+;=========================================================================
+; Common Memory (0xF000 upwards)
+;=========================================================================
+        .area _COMMONMEM
+
+;=========================================================================
+
+platform_interrupt_all:
+       ret
+
+; install interrupt vectors
+_program_vectors:
+       di
+       pop de                          ; temporarily store return address
+       pop hl                          ; function argument -- base page number
+       push hl                         ; put stack back as it was
+       push de
+
+       ; At this point the common block has already been copied
+       call map_process
+
+       ; write zeroes across all vectors
+       ld hl,#0
+       ld de,#1
+       ld bc,#0x007f                   ; program first 0x80 bytes only
+       ld (hl),#0x00
+       ldir
+
+       ; now install the interrupt vector at 0x0038
+       ld a,#0xC3                      ; JP instruction
+       ld (0x0038),a
+       ld hl,#interrupt_handler
+       ld (0x0039),hl
+
+       ; set restart vector for UZI system calls
+       ld (0x0030),a                   ; rst 30h is unix function call vector
+       ld hl,#unix_syscall_entry
+       ld (0x0031),hl
+
+       ld (0x0000),a
+       ld hl,#null_handler             ; to Our Trap Handler
+       ld (0x0001),hl
+
+       ld (0x0066),a                   ; Set vector for NMI
+       ld hl,#nmi_handler
+       ld (0x0067),hl
+
+       jr map_kernel
+
+;=========================================================================
+; Memory management
+;=========================================================================
+
+;
+;      The ROM is a toggle. That makes it exciting if we get it wrong!
+;
+;      We *must* have interrupts off here to avoid double toggles.
+;
+
+rom_toggle:
+       .byte 0         ;       ROM starts mapped
+save_rom:
+       .byte 0         ;       For map_save/restore
+
+;
+;      Centralize all control of the toggle in one place so we can debug it
+;
+rom_control:
+       push bc                 ; Messy - clean me up!
+       ld c,a
+       push hl
+       ld a,i
+       push af
+       ld a,c
+       di
+       ld hl,#rom_toggle
+       cp (hl)
+       jr z, no_work
+       ld (hl),a
+       out (0x38),a    ;       anything toggles
+no_work:
+       pop af
+       jp po, was_di
+       ei
+was_di:        pop hl
+       pop bc
+       ret
+
+;=========================================================================
+; map_process - map process or kernel pages
+; Inputs: page table address in HL, map kernel if HL == 0
+; Outputs: none; A and HL destroyed
+;=========================================================================
+map_process:
+       ld a,h
+       or l                            ; HL == 0?
+       jr z,map_kernel                 ; HL == 0 - map the kernel
+
+       ; fall through
+
+;=========================================================================
+; map_for_swap - map a page into a bank for swap I/O
+; Inputs: none
+; Outputs: none
+;
+; The caller will later map_kernel to restore normality
+;
+;=========================================================================
+map_for_swap:
+
+       ; fall through
+
+;=========================================================================
+; map_process_always - map process pages
+; Inputs: page table address in #U_DATA__U_PAGE
+; Outputs: none; all registers preserved
+;=========================================================================
+map_process_always:
+       push af
+       ld a,#1
+       call rom_control
+       pop af
+       ret
+
+;=========================================================================
+; map_kernel - map kernel pages
+; Inputs: none
+; Outputs: none; all registers preserved
+;=========================================================================
+map_kernel:
+       push af
+       xor a
+       call rom_control
+       pop af
+       ret
+
+;=========================================================================
+; map_restore - restore a saved page mapping
+; Inputs: none
+; Outputs: none, all registers preserved
+;=========================================================================
+map_restore:
+       push af
+       ld a,(save_rom)
+       call rom_control
+       pop af
+       ret
+
+;=========================================================================
+; map_save - save the current page mapping to map_savearea
+; Inputs: none
+; Outputs: none
+;=========================================================================
+map_save:
+       push af
+       ld a,(rom_toggle)
+       ld (save_rom),a
+       pop af
+       ret
+
+;=========================================================================
+; Basic console I/O
+;=========================================================================
+
+;=========================================================================
+; outchar - Wait for UART TX idle, then print the char in A
+; Inputs: A - character to print
+; Outputs: none
+;=========================================================================
+outchar:
+
+       push af
+       ld a,(_ser_type)
+       cp #2
+       jr z, ocloop_acia
+
+       ; wait for transmitter to be idle
+ocloop_sio:
+        xor a                   ; read register 0
+        out (SIOA_C), a
+       in a,(SIOA_C)           ; read Line Status Register
+       and #0x04                       ; get THRE bit
+       jr z,ocloop_sio
+       ; now output the char to serial port
+       pop af
+       out (SIOA_D),a
+       jr out_done
+
+       ; wait for transmitter to be idle
+ocloop_acia:
+       in a,(ACIA_C)           ; read Line Status Register
+       and #0x02                       ; get THRE bit
+       jr z,ocloop_acia
+       ; now output the char to serial port
+       pop af
+       out (ACIA_D),a
+out_done:
+       ret
+
+;=========================================================================
+; inchar - Wait for character on UART, return in A
+; Inputs: none
+; Outputs: A - received character, F destroyed
+;=========================================================================
+inchar:
+       ld a,(_ser_type)
+       cp #2
+       jr z,inchar_acia
+inchar_s:
+        xor a                           ; read register 0
+        out (SIOA_C), a
+       in a,(SIOA_C)                   ; read Line Status Register
+       and #0x01                       ; test if data is in receive buffer
+       jr z,inchar_s                   ; no data, wait
+       in a,(SIOA_D)                   ; read the character from the UART
+       ret
+inchar_acia:
+       in a,(ACIA_C)                   ; read Line Status Register
+       and #0x01                       ; test if data is in receive buffer
+       jr z,inchar_acia                ; no data, wait
+       in a,(ACIA_D)                   ; read the character from the UART
+       ret
diff --git a/Kernel/platform-rc2014-tiny/rules.mk b/Kernel/platform-rc2014-tiny/rules.mk
new file mode 100644 (file)
index 0000000..2c727a9
--- /dev/null
@@ -0,0 +1,15 @@
+#
+# Push the execve code high to make room
+#
+export CROSS_CC_SEG1=--codeseg CODE
+export CROSS_CC_SEG2=--codeseg CODE2
+export CROSS_CC_SEG3=--codeseg CODE
+export CROSS_CC_VIDEO=--codeseg CODE2
+#
+export CROSS_CC_SYS1=--codeseg CODE
+export CROSS_CC_SYS2=--codeseg CODE
+export CROSS_CC_SYS3=--codeseg CODE
+export CROSS_CC_SYS4=--codeseg CODE2
+export CROSS_CC_SYS5=--codeseg COMMONMEM
+export CROSS_CC_SEGDISC=--codeseg DISCARD
+
diff --git a/Kernel/platform-rc2014-tiny/target.mk b/Kernel/platform-rc2014-tiny/target.mk
new file mode 100644 (file)
index 0000000..3bffcde
--- /dev/null
@@ -0,0 +1 @@
+export CPU = z80
diff --git a/Kernel/platform-rc2014-tiny/tricks.s b/Kernel/platform-rc2014-tiny/tricks.s
new file mode 100644 (file)
index 0000000..03a841b
--- /dev/null
@@ -0,0 +1,227 @@
+; 2013-12-21 William R Sowerbutts
+
+        .module tricks
+
+        .globl _ptab_alloc
+        .globl _newproc
+        .globl _chksigs
+        .globl _getproc
+        .globl _platform_monitor
+        .globl trap_illegal
+        .globl _platform_switchout
+        .globl _switchin
+        .globl _doexec
+        .globl _dofork
+        .globl _runticks
+        .globl unix_syscall_entry
+        .globl interrupt_handler
+       .globl _swapper
+       .globl _swapout
+
+        ; imported debug symbols
+        .globl outstring, outde, outhl, outbc, outnewline, outchar, outcharhex
+
+        .include "kernel.def"
+        .include "../kernel.def"
+
+        .area _COMMONMEM
+
+; Switchout switches out the current process, finds another that is READY,
+; possibly the same process, and switches it in.  When a process is
+; restarted after calling switchout, it thinks it has just returned
+; from switchout().
+;
+; This function can have no arguments or auto variables.
+_platform_switchout:
+        di
+        ; save machine state
+
+        ld hl, #0 ; return code set here is ignored, but _switchin can 
+        ; return from either _switchout OR _dofork, so they must both write 
+        ; U_DATA__U_SP with the following on the stack:
+        push hl ; return code
+        push ix
+        push iy
+        ld (U_DATA__U_SP), sp ; this is where the SP is restored in _switchin
+
+        ; find another process to run (may select this one again)
+        call _getproc
+
+        push hl
+        call _switchin
+
+        ; we should never get here
+        call _platform_monitor
+
+badswitchmsg: .ascii "_switchin: FAIL"
+            .db 13, 10, 0
+swapped: .ascii "_switchin: SWAPPED"
+            .db 13, 10, 0
+
+_switchin:
+        di
+        pop bc  ; return address
+        pop de  ; new process pointer
+;
+;      FIXME: do we actually *need* to restore the stack !
+;
+        push de ; restore stack
+        push bc ; restore stack
+
+       push de
+        ld hl, #P_TAB__P_PAGE_OFFSET
+       add hl, de      ; process ptr
+       pop de
+
+        ld a, (hl)
+
+       or a
+       jr nz, not_swapped
+       ;
+       ;       We are still on the departing processes stack, which is
+       ;       fine for now.
+       ;
+       ld sp, #_swapstack
+       ;
+       ;       The process we are switching from is not resident. In
+       ;       practice that means it exited. We don't need to write
+       ;       it back out as it's dead.
+       ;
+       ld ix,(U_DATA__U_PTAB)
+       ld a,P_TAB__P_PAGE_OFFSET(ix)
+
+       or a
+       jr z, not_resident
+       ;
+       ;       DE = process we are switching to
+       ;
+       push de ; save process
+       ; We will always swap out the current process
+       ld hl, (U_DATA__U_PTAB)
+       push hl
+       call _swapout
+       pop hl
+       pop de  ; process to swap to
+not_resident:
+       push de ; called function may modify on stack arg so make
+       push de ; two copies
+       call _swapper
+       pop de
+       pop de
+
+not_swapped:        
+        ; check u_data->u_ptab matches what we wanted
+        ld hl, (U_DATA__U_PTAB) ; u_data->u_ptab
+        or a                    ; clear carry flag
+        sbc hl, de              ; subtract, result will be zero if DE==IX
+        jr nz, switchinfail
+
+       ; wants optimising up a bit
+       ld ix, (U_DATA__U_PTAB)
+        ; next_process->p_status = P_RUNNING
+        ld P_TAB__P_STATUS_OFFSET(ix), #P_RUNNING
+
+       ; Fix the moved page pointers
+       ; Just do one byte as that is all we use on this platform
+       ld a, P_TAB__P_PAGE_OFFSET(ix)
+       ld (U_DATA__U_PAGE), a
+        ; runticks = 0
+        ld hl, #0
+        ld (_runticks), hl
+
+        ; restore machine state -- note we may be returning from either
+        ; _switchout or _dofork
+        ld sp, (U_DATA__U_SP)
+
+        pop iy
+        pop ix
+        pop hl ; return code
+
+        ; enable interrupts, if the ISR isn't already running
+        ld a, (U_DATA__U_ININTERRUPT)
+        or a
+        ret nz ; in ISR, leave interrupts off
+        ei
+        ret ; return with interrupts on
+
+switchinfail:
+       call outhl
+        ld hl, #badswitchmsg
+        call outstring
+       ; something went wrong and we didn't switch in what we asked for
+        jp _platform_monitor
+
+fork_proc_ptr: .dw 0 ; (C type is struct p_tab *) -- address of child process p_tab entry
+
+;
+;      Called from _fork. We are in a syscall, the uarea is live as the
+;      parent uarea. The kernel is the mapped object.
+;
+_dofork:
+        ; always disconnect the vehicle battery before performing maintenance
+        di ; should already be the case ... belt and braces.
+
+        pop de  ; return address
+        pop hl  ; new process p_tab*
+        push hl
+        push de
+
+        ld (fork_proc_ptr), hl
+
+        ; prepare return value in parent process -- HL = p->p_pid;
+        ld de, #P_TAB__P_PID_OFFSET
+        add hl, de
+        ld a, (hl)
+        inc hl
+        ld h, (hl)
+        ld l, a
+
+        ; Save the stack pointer and critical registers.
+        ; When this process (the parent) is switched back in, it will be as if
+        ; it returns with the value of the child's pid.
+        push hl ; HL still has p->p_pid from above, the return value in the parent
+        push ix
+        push iy
+
+        ; save kernel stack pointer -- when it comes back in the parent we'll be in
+        ; _switchin which will immediately return (appearing to be _dofork()
+       ; returning) and with HL (ie return code) containing the child PID.
+        ; Hurray.
+        ld (U_DATA__U_SP), sp
+
+        ; now we're in a safe state for _switchin to return in the parent
+       ; process.
+
+       ld hl, (U_DATA__U_PTAB)
+       push hl
+       call _swapout
+       pop hl
+
+        ; now the copy operation is complete we can get rid of the stuff
+        ; _switchin will be expecting from our copy of the stack.
+        pop bc
+        pop bc
+        pop bc
+
+        ; Make a new process table entry, etc.
+        ld  hl, (fork_proc_ptr)
+        push hl
+        call _newproc
+        pop bc 
+
+        ; runticks = 0;
+        ld hl, #0
+        ld (_runticks), hl
+        ; in the child process, fork() returns zero.
+       ;
+       ; And we exit, with the kernel mapped, the child now being deemed
+       ; to be the live uarea. The parent is frozen in time and space as
+       ; if it had done a switchout().
+        ret
+;
+;      We can keep a stack in common because we will complete our
+;      use of it before we switch common block. In this case we have
+;      a true common so it's even easier.
+;
+       .ds 128
+_swapstack: