linc80: initial port
authorAlan Cox <alan@linux.intel.com>
Mon, 7 Jan 2019 01:26:20 +0000 (01:26 +0000)
committerAlan Cox <alan@linux.intel.com>
Mon, 7 Jan 2019 01:26:20 +0000 (01:26 +0000)
Lots of work to do on the IM2 side - serial handlers etc rather than polling
on the timer as an icky hack to get started

17 files changed:
Kernel/platform-linc80/Makefile [new file with mode: 0644]
Kernel/platform-linc80/README [new file with mode: 0644]
Kernel/platform-linc80/commonmem.s [new file with mode: 0644]
Kernel/platform-linc80/config.h [new file with mode: 0644]
Kernel/platform-linc80/crt0.s [new file with mode: 0644]
Kernel/platform-linc80/devices.c [new file with mode: 0644]
Kernel/platform-linc80/devtty.c [new file with mode: 0644]
Kernel/platform-linc80/devtty.h [new file with mode: 0644]
Kernel/platform-linc80/discard.c [new file with mode: 0644]
Kernel/platform-linc80/fuzix.lnk [new file with mode: 0644]
Kernel/platform-linc80/kernel.def [new file with mode: 0644]
Kernel/platform-linc80/linc80.s [new file with mode: 0644]
Kernel/platform-linc80/loader.s [new file with mode: 0644]
Kernel/platform-linc80/main.c [new file with mode: 0644]
Kernel/platform-linc80/platform_ide.h [new file with mode: 0644]
Kernel/platform-linc80/target.mk [new file with mode: 0644]
Kernel/platform-linc80/tricks.s [new file with mode: 0644]

diff --git a/Kernel/platform-linc80/Makefile b/Kernel/platform-linc80/Makefile
new file mode 100644 (file)
index 0000000..6b5c584
--- /dev/null
@@ -0,0 +1,50 @@
+ASRCS = crt0.s tricks.s commonmem.s linc80.s
+CSRCS = devices.c main.c devtty.c
+DISCARD_CSRCS = discard.c
+DISCARD_DSRCS = ../dev/devide_discard.c
+DSRCS = ../dev/devide.c ../dev/mbr.c ../dev/blkdev.c
+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))
+
+OBJS  = $(AOBJS) $(COBJS) $(DOBJS) $(DISCARD_DOBJS) $(DISCARD_COBJS) $(NOBJS)
+
+CROSS_CCOPTS += -I../dev/ -I../dev/net/
+
+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) -c $<
+
+$(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 *~ fuzix.com loader.tmp
+
+image:  loader.bin
+       dd if=../fuzix.bin of=fuzix.com bs=256 skip=1 count=248
+
+loader.bin: loader.s
+       sdasz80 -o loader.s
+       sdldz80 -i loader.rel
+       makebin -s 65536 loader.ihx loader.tmp
+       dd if=loader.tmp bs=256 skip=208 of=loader.bin
diff --git a/Kernel/platform-linc80/README b/Kernel/platform-linc80/README
new file mode 100644 (file)
index 0000000..77da6e0
--- /dev/null
@@ -0,0 +1,41 @@
+LiNC80 Experimental Port
+
+This port supports the following configurations
+
+       LiNC80 with at least one extra 16K bank of RAM as bank 1
+       (additional banks will not be used at this point)
+
+       IDE CF card configured with CP/M to load Fuzix (pending a better
+       loader). Partition table 65536 blocks into the media with at
+       least a root and swap partition present.
+
+       Options:
+               No LiNC80 or RC2014 add in cards are currently supported
+
+       Planned:
+               A different build that supports multiple banks of 16K or
+               with a simple board mod 32K banks
+               Maybe sound card when we get to the Fuzix sound support
+
+
+Memory map:
+
+Kernel
+
+0000-7FFF      Common and kernel
+8000-BFFF      Kernel (banked and in bank 0)
+C000-FFFF      User
+
+User
+
+0000-7FFF      Common and kernel
+8000-BFFF      User (banked and in bank 1)
+C000-FFFF      User
+
+TO DO
+
+Write a proper bootloader that can use partition tables but will trick the
+CPM loader into doing the right thing.
+
+Version that supports multiple 16K banks and multiple processes in memory
+ZX style. Also code to probe for and use the 32K hack which is far nicer.
diff --git a/Kernel/platform-linc80/commonmem.s b/Kernel/platform-linc80/commonmem.s
new file mode 100644 (file)
index 0000000..355bd53
--- /dev/null
@@ -0,0 +1,10 @@
+;
+;      Standard common. Nothing special here except to remember that writes
+;      to common space won't write through all banks
+;
+        .module commonmem
+
+        .area _COMMONMEM
+
+       .include "../cpu-z80/std-commonmem.s"
+
diff --git a/Kernel/platform-linc80/config.h b/Kernel/platform-linc80/config.h
new file mode 100644 (file)
index 0000000..fa23cee
--- /dev/null
@@ -0,0 +1,69 @@
+/* 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
+#define CONFIG_PARENT_FIRST
+#define MAXTICKS 20
+/* 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    0x8000  /* also data base */
+#define PROGLOAD    0x8000  /* also data base */
+#define PROGTOP     0xFFFF  /* Top of program */
+#define KERNTOP            0xC000  /* Grow buffers to 0xC000 */
+
+#define PROC_SIZE   32   /* Memory needed per process (inc udata) */
+
+#define SWAPDEV     (swap_dev) /* A variable for dynamic, or a device major/minor */
+extern unsigned int swap_dev;
+#define SWAP_SIZE   0x41       /* 32.5K in blocks (prog + udata) */
+#define SWAPBASE    0x8000     /* start at the base of user mem */
+#define SWAPTOP            0x10000UL   /* Swap out program */
+#define CONFIG_SPLIT_UDATA     /* Adjacent addresses but different bank! */
+#define UDATA_BLKS  1          /* One block of udata */
+#define UDATA_SIZE  512                /* 512 bytes of udata */
+#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
+
+/* Until we have a bootloader properly done */
+#define CONFIG_MBR_OFFSET      65536
+/*
+ *     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#"
+
+#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 1       /* 1 IDE for now */
+
+/* IDE/CF support */
+#define CONFIG_IDE
+
+/* Device parameters */
+#define NUM_DEV_TTY 2
+
+/* SIO port B 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 */
+
+#define platform_copyright()
diff --git a/Kernel/platform-linc80/crt0.s b/Kernel/platform-linc80/crt0.s
new file mode 100644 (file)
index 0000000..2d2b749
--- /dev/null
@@ -0,0 +1,70 @@
+; 2015-02-20 Sergey Kiselev
+; 2013-12-18 William R Sowerbutts
+
+        .module crt0
+
+        ; Ordering of segments for the linker.
+        .area _CODE
+        .area _HOME     ; compiler stores __mullong etc in here if you use them
+        .area _CODE2
+        .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)
+        .area _INITIALIZER ; binman copies this to the right place for us
+        .area _GSINIT      ; unused
+        .area _GSFINAL     ; unused
+        .area _DISCARD
+        .area _COMMONMEM
+       .area _PAGE0       ; unused but stops binman changing us
+
+        ; 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
+
+       .include "kernel.def"
+
+       .area _COMMONMEM
+
+start:
+       jp init
+
+        .area _CODE
+
+init:
+        di
+        ; switch to stack in high memory
+        ld sp, #kstack_top
+
+        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
diff --git a/Kernel/platform-linc80/devices.c b/Kernel/platform-linc80/devices.c
new file mode 100644 (file)
index 0000000..1a52d3e
--- /dev/null
@@ -0,0 +1,39 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <tty.h>
+#include <devsys.h>
+#include <devfd.h>
+#include <devrd.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-linc80/devtty.c b/Kernel/platform-linc80/devtty.c
new file mode 100644 (file)
index 0000000..ea1342c
--- /dev/null
@@ -0,0 +1,188 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <tty.h>
+#include <devtty.h>
+
+static char tbuf1[TTYSIZ];
+static char tbuf2[TTYSIZ];
+
+static tcflag_t uart_mask[4] = {
+       _ISYS,
+       _OSYS,
+       CSIZE|CSTOPB|CBAUD|PARENB|PARODD|_CSYS,
+       _LSYS
+};
+
+tcflag_t *termios_mask[NUM_DEV_TTY + 1] = {
+       NULL,
+       uart_mask,
+       uart_mask
+};
+
+struct s_queue ttyinq[NUM_DEV_TTY + 1] = {     /* ttyinq[0] is never used */
+       {NULL, NULL, NULL, 0, 0, 0},
+       {tbuf1, tbuf1, tbuf1, TTYSIZ, 0, TTYSIZ / 2},
+       {tbuf2, tbuf2, tbuf2, TTYSIZ, 0, TTYSIZ / 2},
+};
+
+uint8_t sio_r[] = {
+       0x03, 0xC1,
+       0x04, 0xC4,
+       0x05, 0xEA
+};
+
+static void sio2_setup(uint8_t minor, uint8_t flags)
+{
+       struct termios *t = &ttydata[minor].termios;
+       uint8_t r;
+       /* Set bits per character */
+       sio_r[1] = 0x01 | ((t->c_cflag & CSIZE) << 2);
+       r = 0xC4;
+       if (t->c_cflag & CSTOPB)
+               r |= 0x08;
+       if (t->c_cflag & PARENB)
+               r |= 0x01;
+       if (t->c_cflag & PARODD)
+               r |= 0x02;
+       sio_r[3] = r;
+       sio_r[5] = 0x8A | ((t->c_cflag & CSIZE) << 1);
+}
+
+void tty_setup(uint8_t minor, uint8_t flags)
+{
+       sio2_setup(minor, flags);
+       sio2_otir(SIO0_BASE + 4 - minor);       /* minor is 1 or 2 */
+       /* We need to do CTS/RTS support and baud setting yet */
+}
+
+int tty_carrier(uint8_t minor)
+{
+        uint8_t c;
+       if (minor == 2) {
+               SIOA_C = 0;
+               c = SIOA_C;
+       } else {
+               SIOB_C = 0;
+               c = SIOB_C;
+       }
+       if (c & 0x8)
+               return 1;
+       return 0;
+}
+
+void tty_pollirq_sio(void)
+{
+       static uint8_t old_ca, old_cb;
+       uint8_t ca, cb;
+       uint8_t progress;
+
+       /* Check for an interrupt */
+       SIOA_C = 0;
+//     if (!(SIOA_C & 2))
+//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);
+}
+
+void tty_putc(uint8_t minor, unsigned char c)
+{
+       if (minor == 2) {
+               SIOA_D = c;
+       } else if (minor == 1)
+               SIOB_D = c;
+}
+
+/* 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
+
+   Need to review this we should be ok as the IRQ handler always leaves
+   us pointing at RR0 */
+
+ttyready_t tty_writeready(uint8_t minor)
+{
+       irqflags_t irq;
+       uint8_t c;
+
+       irq = di();
+       if (minor == 2) {
+               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 == 1) {
+               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);
+       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-linc80/devtty.h b/Kernel/platform-linc80/devtty.h
new file mode 100644 (file)
index 0000000..0857f80
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef __DEVTTY_DOT_H__
+#define __DEVTTY_DOT_H__
+
+#define SIO0_BASE 0x00
+__sfr __at (SIO0_BASE + 0) SIOA_D;
+__sfr __at (SIO0_BASE + 1) SIOB_D;
+__sfr __at (SIO0_BASE + 2) SIOA_C;
+__sfr __at (SIO0_BASE + 3) SIOB_C;
+
+extern void sio2_otir(uint8_t port) __z88dk_fastcall;
+
+void tty_putc(uint8_t minor, unsigned char c);
+void tty_pollirq_sio(void);
+
+#endif
diff --git a/Kernel/platform-linc80/discard.c b/Kernel/platform-linc80/discard.c
new file mode 100644 (file)
index 0000000..3b5281f
--- /dev/null
@@ -0,0 +1,40 @@
+#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_init(n--);
+}
+
+void device_init(void)
+{
+#ifdef CONFIG_IDE
+       devide_init();
+#endif
+}
diff --git a/Kernel/platform-linc80/fuzix.lnk b/Kernel/platform-linc80/fuzix.lnk
new file mode 100644 (file)
index 0000000..4c22ca5
--- /dev/null
@@ -0,0 +1,40 @@
+-mwxuy
+-i fuzix.ihx
+-b _COMMONMEM=0x0100
+-b _CODE=0x0B00
+-l z80
+platform-linc80/crt0.rel
+platform-linc80/commonmem.rel
+platform-linc80/linc80.rel
+start.rel
+version.rel
+lowlevel-z80.rel
+platform-linc80/tricks.rel
+platform-linc80/main.rel
+timer.rel
+kdata.rel
+platform-linc80/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-linc80/discard.rel
+platform-linc80/devtty.rel
+platform-linc80/mbr.rel
+platform-linc80/blkdev.rel
+platform-linc80/devide.rel
+platform-linc80/devide_discard.rel
+-e
diff --git a/Kernel/platform-linc80/kernel.def b/Kernel/platform-linc80/kernel.def
new file mode 100644 (file)
index 0000000..c4764f7
--- /dev/null
@@ -0,0 +1,32 @@
+; FUZIX mnemonics for memory addresses etc
+
+U_DATA                 .equ    0x0103  ; (this is struct u_data from kernel.h)
+U_DATA__TOTALSIZE      .equ    0x0200  ; 256+256+256 bytes.
+Z80_TYPE               .equ    0       ; CMOS
+
+Z80_MMU_HOOKS          .equ 0
+
+CONFIG_SWAP            .equ 1
+
+PROGBASE               .equ    0x8000
+PROGLOAD               .equ    0x8000
+
+; Mnemonics for I/O ports etc
+
+CONSOLE_RATE           .equ    115200
+
+CPU_CLOCK_KHZ          .equ    7372
+
+SIOA_D         .EQU    0x00
+SIOB_D         .EQU    0x01
+SIOA_C         .EQU    0x02
+SIOB_C         .EQU    0x03
+
+; Z80 CTC ports
+CTC_CH0                .equ    0x08    ; CTC channel 0 and interrupt vector
+CTC_CH1                .equ    0x09    ; CTC channel 1
+CTC_CH2                .equ    0x0A    ; CTC channel 2
+CTC_CH3                .equ    0x0B    ; CTC channel 3
+
+NBUFS          .equ    4
+
diff --git a/Kernel/platform-linc80/linc80.s b/Kernel/platform-linc80/linc80.s
new file mode 100644 (file)
index 0000000..8e79634
--- /dev/null
@@ -0,0 +1,267 @@
+;
+;      Linc80 Initial Support
+;
+
+        .module linc80
+
+        ; exported symbols
+        .globl init_hardware
+        .globl interrupt_handler
+        .globl _program_vectors
+       .globl _kernel_flag
+        .globl map_kernel
+        .globl map_buffers
+        .globl map_process_always
+        .globl map_process
+        .globl map_kernel_di
+        .globl map_process_always_di
+        .globl map_save_kernel
+        .globl map_restore
+       .globl map_for_swap
+       .globl _platform_reboot
+       .globl _int_disabled
+       .globl platform_interrupt_all
+       .globl _need_resched
+
+        ; exported debugging tools
+        .globl _platform_monitor
+        .globl outchar
+
+        ; imported symbols
+        .globl _ramsize
+        .globl _procmem
+        .globl istack_top
+        .globl istack_switched_sp
+       .globl kstack_top
+        .globl unix_syscall_entry
+       .globl null_handler
+       .globl nmi_handler
+        .globl outcharhex
+
+       .globl s__COMMONMEM
+       .globl l__COMMONMEM
+
+        .include "kernel.def"
+        .include "../kernel.def"
+
+
+;
+; Buffers (we use asm to set this up as we need them in a special segment
+; so we can recover the discard memory into the buffer pool
+;
+
+       .globl _bufpool
+       .area _BUFFERS
+
+_bufpool:
+       .ds BUFSIZE * NBUFS
+
+        .area _COMMONMEM
+
+_platform_monitor:
+           ; Reboot ends up back in the monitor
+_platform_reboot:
+       xor a
+       out (0x38), a           ; ROM appears low
+       rst 0                   ; bang
+
+_int_disabled:
+       .db 1
+
+map_buffers:
+map_kernel:
+map_kernel_di:
+       push af
+       ld a,#1
+map_a:
+       ld (mapreg),a
+       out (0x38),a
+       pop af
+       ret
+map_process:
+       ld a,h
+       or l
+       jr z, map_kernel
+map_process_always:
+map_process_always_di:
+map_for_swap:
+       push af
+       ld a,#3
+       jr map_a
+map_save_kernel:
+       push af
+       ld a,(mapreg)
+       ld (mapsave),a
+       ld a,#1
+       jr map_a
+map_restore:
+       push af
+       ld a,(mapsave)
+       jr map_a
+
+_program_early_vectors:
+        ; 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 FUZIX 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
+
+_program_vectors:
+platform_interrupt_all:
+       ret
+
+       .globl spurious         ; so we can debug trap on it
+
+spurious:
+       reti
+
+mapreg:
+       .db 0
+mapsave:
+       .db 0
+
+_need_resched:
+       .db 0
+
+
+
+; -----------------------------------------------------------------------------
+;      All of discard gets reclaimed when init is run
+;
+;      Discard must be above 0x8000 as we need some of it when the ROM
+;      is paged in during init_hardware
+; -----------------------------------------------------------------------------
+       .area _DISCARD
+
+init_hardware:
+       call _program_early_vectors
+       ; IM2 vector for the CTC
+       ld hl, #spurious
+       ld (0x80),hl                    ; CTC vectors
+       ld (0x82),hl
+       ld (0x84),hl
+       ld hl, #interrupt_handler       ; Standard tick handler
+       ld (0x86),hl
+
+       ld hl,#spurious                 ; For now
+       ld (0x88),hl                    ; PIO A
+       ld (0x8A),hl                    ; PIO B
+
+       ld hl,#spurious                 ; For now
+       ld (0x90),hl                    ; SIO B TX empty
+       ld (0x92),hl                    ; SIO B External status
+       ld (0x94),hl                    ; SIO B Receive
+       ld (0x96),hl                    ; SIO B Special
+       ld (0x98),hl                    ; SIO A TX empty
+       ld (0x9A),hl                    ; SIO A External status
+       ld (0x9C),hl                    ; SIO A Received
+       ld (0x9E),hl                    ; SIO A Special
+       ld hl, #80
+        ld (_ramsize), hl
+       ld hl,#32
+        ld (_procmem), hl
+
+       ld hl,#sio_setup
+       ld bc,#0xA00 + SIOA_C           ; 10 bytes to SIOA_C
+       otir
+       ld hl,#sio_setup
+       ld bc,#0x0C00 + SIOB_C          ; and to SIOB_C with vector 
+       otir
+
+       ;
+       ;       Now program up the CTC
+       ;       CTC 0 and CTC 1 are set up for the serial and we should
+       ;       not touch them. We configure up 2 and 3
+       ;
+       ld a,#0x80
+       out (CTC_CH0),a ; set the CTC vector
+
+       ld a,#0x25      ; timer, 256 prescale, irq off
+       out (CTC_CH2),a
+       ld a,#180       ; counter base (160 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
+
+       xor a
+       ld i,a  ; Use upper half of rst vector page
+        im 2   ; set CPU interrupt
+
+        ret
+
+RTS_LOW        .EQU    0xEA
+
+sio_setup:
+       .byte 0x00
+       .byte 0x18              ; Reset
+       .byte 0x04
+       .byte 0xC4
+       .byte 0x01
+       .byte 0x18
+       .byte 0x03
+       .byte 0xE1
+       .byte 0x05
+       .byte RTS_LOW
+       .byte 0x02              ; IRQ vector (B only)
+       .byte 0x90
+
+           .area _CODE
+
+_kernel_flag:
+           .db 1       ; We start in kernel mode
+
+
+;
+;      A little SIO helper
+;
+       .globl _sio_r
+       .globl _sio2_otir
+
+_sio2_otir:
+       ld b,#0x06
+       ld c,l
+       ld hl,#_sio_r
+       otir
+       ret
+;
+; outchar: Wait for UART TX idle, then print the char in A
+; destroys: AF
+;
+; We use the A port for debug as the console is usually on B
+;
+outchar:
+       push af
+       ; 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
+       ret
+
diff --git a/Kernel/platform-linc80/loader.s b/Kernel/platform-linc80/loader.s
new file mode 100644 (file)
index 0000000..686ec30
--- /dev/null
@@ -0,0 +1,118 @@
+;
+;      The CP/M command blindly loads the first 24 blocks moves them to the
+;      top 12K and then runs whatever is indicated at 0xFFFE/FFFF
+;
+
+       .area VECTOR(ABS)
+
+       .org 0xFFFE
+       .word start
+
+       .area LOADER(ABS)
+
+       .org 0xD000
+
+DATA           .equ    0x10
+ERROR          .equ    0x11
+FEATURES       .equ    0x11
+COUNT          .equ    0x12
+LBA_0          .equ    0x13
+LBA_1          .equ    0x14
+LBA_2          .equ    0x15
+LBA_3          .equ    0x16
+STATUS         .equ    0x17
+CMD            .equ    0x17
+
+ERR            .equ    0
+DRQ            .equ    3
+READY          .equ    6
+BUSY           .equ    7
+
+ATA_READ       .equ    0x20
+
+SIOB_C         .equ    3
+SIOB_D         .equ    1
+
+       .ds 10240       ; boot sector and more for loader space
+
+start:
+       ; A modern partition setup has lots of room for boot space, so we
+       ; just load the blocks after the loader (24-147). We can't overlap
+       ; because of the FFFE/FFFF thing.
+
+       ld sp, #0xFE00
+       ld hl,#hello
+       call serstr
+
+       call ide_ready
+       ld a,#0xE0
+       out (LBA_3),a
+       call ide_ready
+       xor a
+       out (LBA_2),a
+       out (LBA_1),a
+
+       ld de,#0x7C18           ; sectors 24-119
+       ld hl,#0x0100           ; load address
+load_loop:
+       call ide_ready
+       ld a,e
+       out (LBA_0),a
+       ld a,#1
+       out (COUNT),a
+       ld a,#ATA_READ
+       out (CMD),a
+       nop
+       call ide_wait_drq
+       ld bc,#DATA
+       inir
+       inir
+       ld a,#'.'
+       call serout
+       inc e
+       dec d
+       jr nz, load_loop
+       ld hl,#gogogo
+       call serstr
+       jp 0x0100
+
+ide_ready:
+       in a,(STATUS)
+       bit BUSY,a
+       jr nz, ide_ready
+       bit READY,a
+       jr z, ide_ready
+       ret
+ide_wait_drq:
+       in a,(STATUS)
+       bit DRQ,a
+       jr z,ide_wait_drq
+       ret
+
+
+serout:
+       push af
+       ; wait for transmitter to be idle
+ocloop_sio:
+        xor a                   ; read register 0
+        out (SIOB_C), a
+       in a,(SIOB_C)           ; read Line Status Register
+       and #0x04                       ; get THRE bit
+       jr z,ocloop_sio
+       ; now output the char to serial port
+       pop af
+       out (SIOB_D),a
+       ret
+
+serstr:
+       ld a,(hl)
+       or a
+       ret z
+       inc hl
+       call serout
+       jr serstr
+
+hello:
+       .asciz 'LiNC80 FUZIX LOADER 0.1\n\n'
+gogogo:
+       .asciz '\nExecuting FUZIX...\n'
diff --git a/Kernel/platform-linc80/main.c b/Kernel/platform-linc80/main.c
new file mode 100644 (file)
index 0000000..2f88a93
--- /dev/null
@@ -0,0 +1,46 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <timer.h>
+#include <devtty.h>
+
+extern unsigned char irqvector;
+struct blkbuf *bufpool_end = bufpool + NBUFS;  /* minimal for boot -- expanded after we're done with _DISCARD */
+uint16_t swap_dev = 0xFFFF;
+uint16_t ramtop = 0xFFFF;
+
+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++;
+       }
+       kprintf("Buffers available: %d\n", bufpool_end - bufpool);
+}
+
+static uint8_t idlect;
+
+void platform_idle(void)
+{
+       __asm
+               halt
+       __endasm;
+}
+
+uint8_t platform_param(unsigned char *p)
+{
+       used(p);
+       return 0;
+}
+
+void platform_interrupt(void)
+{
+       tty_pollirq_sio();              /* For now as we don't have nice
+                                          tty set up yet */
+       timer_interrupt();
+}
+
diff --git a/Kernel/platform-linc80/platform_ide.h b/Kernel/platform-linc80/platform_ide.h
new file mode 100644 (file)
index 0000000..233ca46
--- /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-linc80/target.mk b/Kernel/platform-linc80/target.mk
new file mode 100644 (file)
index 0000000..3bffcde
--- /dev/null
@@ -0,0 +1 @@
+export CPU = z80
diff --git a/Kernel/platform-linc80/tricks.s b/Kernel/platform-linc80/tricks.s
new file mode 100644 (file)
index 0000000..0113d75
--- /dev/null
@@ -0,0 +1,5 @@
+        .include "kernel.def"
+        .include "../kernel.def"
+
+       .include "../lib/z80single.s"
+