rc2014: import the RC2014 fork of Fuzix and realign it with current kernels
authorAlan Cox <alan@linux.intel.com>
Sat, 23 Jun 2018 00:18:01 +0000 (01:18 +0100)
committerAlan Cox <alan@linux.intel.com>
Sat, 23 Jun 2018 00:18:01 +0000 (01:18 +0100)
Not yet tested. In theory the changes done are small...

29 files changed:
Kernel/platform-rc2014/Makefile [new file with mode: 0644]
Kernel/platform-rc2014/README [new file with mode: 0644]
Kernel/platform-rc2014/bootrom.s [new file with mode: 0644]
Kernel/platform-rc2014/commonmem.s [new file with mode: 0644]
Kernel/platform-rc2014/config.h [new file with mode: 0644]
Kernel/platform-rc2014/crt0.s [new file with mode: 0644]
Kernel/platform-rc2014/devices.c [new file with mode: 0644]
Kernel/platform-rc2014/devrd_zeta2.c [new file with mode: 0644]
Kernel/platform-rc2014/devrd_zeta2_hw.s [new file with mode: 0644]
Kernel/platform-rc2014/devtty.c [new file with mode: 0644]
Kernel/platform-rc2014/devtty.h [new file with mode: 0644]
Kernel/platform-rc2014/devtty_discard.c [new file with mode: 0644]
Kernel/platform-rc2014/discard.c [new file with mode: 0644]
Kernel/platform-rc2014/diskboot.s [new file with mode: 0644]
Kernel/platform-rc2014/fuzix.lnk [new file with mode: 0644]
Kernel/platform-rc2014/kernel.def [new file with mode: 0644]
Kernel/platform-rc2014/main.c [new file with mode: 0644]
Kernel/platform-rc2014/monitor.s [new file with mode: 0644]
Kernel/platform-rc2014/platform_ide.h [new file with mode: 0644]
Kernel/platform-rc2014/ppide.c [new file with mode: 0644]
Kernel/platform-rc2014/rc2014.h [new file with mode: 0644]
Kernel/platform-rc2014/rc2014.s [new file with mode: 0644]
Kernel/platform-rc2014/target.mk [new file with mode: 0644]
Kernel/platform-rc2014/tricks.s [new file with mode: 0644]
Kernel/platform-rc2014/vfd-debug.c [new file with mode: 0644]
Kernel/platform-rc2014/vfd-debug.h [new file with mode: 0644]
Kernel/platform-rc2014/vfd-term.c [new file with mode: 0644]
Kernel/platform-rc2014/vfd-term.h [new file with mode: 0644]
Kernel/platform-rc2014/vfdterm.s [new file with mode: 0644]

diff --git a/Kernel/platform-rc2014/Makefile b/Kernel/platform-rc2014/Makefile
new file mode 100644 (file)
index 0000000..d267797
--- /dev/null
@@ -0,0 +1,64 @@
+ASRCS = crt0.s tricks.s commonmem.s rc2014.s monitor.s vfdterm.s
+ASRCS += devrd_zeta2_hw.s
+CSRCS = devices.c main.c devtty.c devrd_zeta2.c vfd-debug.c vfd-term.c
+DISCARD_CSRCS = discard.c devtty_discard.c
+DISCARD_DSRCS = 
+DSRCS = ../dev/devfd.c ../dev/devsd.c ../dev/mbr.c ../dev/blkdev.c
+DSRCS +=  ../dev/devrd.c
+DASRCS = ../dev/devfd_hw.s ../dev/devrd_hw.s
+
+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))
+
+OBJS  = $(AOBJS) $(COBJS) $(DOBJS) $(DAOBJS) $(DISCARD_DOBJS) $(DISCARD_COBJS)
+
+CROSS_CCOPTS += -I../dev/
+
+JUNK = *.rel *.lst *.asm *.sym *.rst *.map *.ihx *.bin
+
+all:   $(OBJS) diskboot.bin
+
+$(AOBJS): %.rel: %.s
+       $(CROSS_AS) $(ASOPTS) $<
+
+$(COBJS): %.rel: %.c
+       $(CROSS_CC) $(CROSS_CCOPTS) -c $<
+
+$(DOBJS): %.rel: ../dev/%.c
+       $(CROSS_CC) $(CROSS_CCOPTS) -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 $<
+
+clean:
+       rm -f $(OBJS) $(JUNK)  core *~ bootrom.ihx bootrom.bin diskboot.bin fuzix.com fuzix.rom
+
+diskboot.bin:  diskboot.s
+       $(CROSS_AS) $(ASOPTS) diskboot.s
+       sdldz80 -nmi diskboot.rel
+       makebin -s 65536 diskboot.ihx | dd bs=512 skip=125 count=1 of=diskboot.bin
+
+image:
+       sdasz80 -o bootrom.s
+       sdldz80 -m -i bootrom.rel
+       makebin -s 136 bootrom.ihx > bootrom.bin
+#      cat bootrom.bin ../fuzix.bin | dd conv=sync bs=65536 count=1 of=fuzix.rom
+       cat bootrom.bin ../fuzix.bin > tmp.rom
+       cat tmp.rom | dd conv=sync bs=65536 count=1 of=fuzix.rom
+       cat fuzix.rom ../rc2014_root_fs > fuzix_rc2014_sio_bootfs.rom
+       ../cpm-loader/makecpmloader ../cpm-loader/cpmload.bin ../fuzix.bin 0x88 fuzix.com
+       ../cpm-loader/makecpmloader ../cpm-loader/fuzixload.bin ../fuzix.bin 0x88 fuzix
+
+cleanup_sio_acia:
+       rm -f devtty.asm devtty.rel main.asm main.rel rc2014.rel 
+       rm -f devtty_discard.asm devtty_discard.rel discard.asm discard.rel
diff --git a/Kernel/platform-rc2014/README b/Kernel/platform-rc2014/README
new file mode 100644 (file)
index 0000000..32b5384
--- /dev/null
@@ -0,0 +1,48 @@
+--- README for RC2014 ---
+This is Fuzix for the RC2014
+
+Imported into the current tree from Scott Baker's git tree and adjusted to
+build against a current kernel. Don't blame Scott for any bugs!
+
+Modified for RC2014 with FlashROM/Ram board by Scott Baker <smbaker@gmail.com>.
+
+Heavily based on prior work by Will Sowerbutts <will@sowerbutts.com>, 
+Sergey Kiselev <skiselev@gmail.com>, and others.
+
+Supported Hardware
+
+  * The Flash ROM / RAM board is required. This board is basically a clone of
+    the memory management subsystem of the Zeta V2. It replaces the RC2014's
+    default ROM and RAM boards.
+
+  * A serial IO board is required. This can either be an SIO/2 board or a 
+    68B50 ACIA board. The 68B50 ACIA is the one that comes standard with the
+    RC2014 kit.
+
+  * VFD Display. If config.h:CONFIG_VFD_TERM is defined, then the VFD Terminal
+    will be supported. This will display all output to the serial port on the
+    VFD. If it's defined and you don't have a VFD, then it probably won't hurt
+    anything, other than some useless io to ports 0-3. 
+
+Notes
+
+  * This platform is based heavily on the Zeta V2 platform, so consult the
+    Zeta V2 readme for more instructions. This instructions are intentionally
+    minimal, focusing on items specific to the RC2014 configuration.
+
+Configuration
+
+  * Make sure to edit config.h and kernel.def to specify whether you are
+    using SIO/2 or ACIA. 
+
+  * The Makefile assumes a file system image exists in ../rc2014_root_fs. 
+    See the Zeta V2 instructions for building a filesystem.
+
+Things that don't work
+
+  * The RC2014 doesn't come with a clock. I added fakeclock.c, which is a 
+    clock that always returns 0. 
+
+  * I couldn't get the WD37C65 floppy to work.
+
+  * Flow control isn't yet enabled for the serial port.
diff --git a/Kernel/platform-rc2014/bootrom.s b/Kernel/platform-rc2014/bootrom.s
new file mode 100644 (file)
index 0000000..0cfe86f
--- /dev/null
@@ -0,0 +1,59 @@
+;
+;      ROM boot for FUZIX on the RC2014
+;
+               .module bootrom
+               .include "kernel.def"
+
+               .area _LOADER (ABS)
+               .org 0x0000
+start:
+               ; map ROM page 0 to bank #0 and enable paging
+               di                      ; better be safe than sorry
+               xor a
+               out (MPGSEL_0),a        ; map page 0 (ROM) to bank #0
+               ld a,#1
+               out (MPGENA),a          ; enable paging
+
+               ; copy FUZIX kernel to RAM
+               ; 4 pages, starting from ROM page 0, RAM page 32
+               xor a
+kernel_copy:
+               out (MPGSEL_1),a        ; map ROM page to bank #1
+               add #32                 ; RAM page = ROM page + 32      
+               out (MPGSEL_2),a        ; map RAM page to bank #2
+               ld hl,#0x4000           ; source - bank #1 offset
+               ld de,#0x8000           ; destination - bank #2 offset
+               ld bc,#0x4000           ; count - 16 KiB
+               ldir                    ; copy it
+               sub a,#31               ; next ROM page = RAM page - 32 + 1
+               cp #4                   ; are we there yet (RAM page == 4?)
+               jr nz,kernel_copy
+
+;;             ; copy data to RAM disk
+;;             ; 16 pages, starting from ROM page 4, RAM page 48
+;;             ld a,#4
+;; ramdisk_copy:
+;;             out (MPGSEL_1),a        ; map ROM page to bank #1
+;;             add #44                 ; RAM page = ROM page + 44
+;;             out (MPGSEL_2),a        ; map RAM page to bank #2
+;;             ld hl,#0x4000           ; source - bank #1 offset
+;;             ld de,#0x8000           ; destination - bank #2 offset
+;;             ld bc,#0x4000           ; count - 16 KiB
+;;             ldir                    ; copy it
+;;             sub #43                 ; next ROM page = RAM page - 44 + 1
+;;             cp #20                  ; are we there yet (RAM page == 4 + 16?)
+;;             jr nz,ramdisk_copy
+;; 
+               ; scary... switching memory bank under our feet
+               ld a,#32                ; map page 32 (RAM) to bank 0 
+               out (MPGSEL_0),a
+               inc a                   ; map page 33 (RAM+16k) to bank 1
+               out (MPGSEL_1),a
+               inc a                   ; map page 34 (RAM+32K) to bank 2
+               out (MPGSEL_2),a
+               inc a                   ; map page 35 (RAM+48K) to bank 3
+               out (MPGSEL_3),a
+
+               jp 0x8B                 ; jump to init_from_rom in crt0
+; pad
+               .ds     (0x88-(.-start))
diff --git a/Kernel/platform-rc2014/commonmem.s b/Kernel/platform-rc2014/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/config.h b/Kernel/platform-rc2014/config.h
new file mode 100644 (file)
index 0000000..e560250
--- /dev/null
@@ -0,0 +1,100 @@
+/* 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 */
+#define CONFIG_MULTI
+/* Single tasking */
+#undef CONFIG_SINGLETASK
+/* CP/M emulation */
+#undef CONFIG_CPM_EMU
+/* Flexible 4x16K banking */
+#define CONFIG_BANK16
+/* Permit large I/O requests to bypass cache and go direct to userspace */
+#define CONFIG_LARGE_IO_DIRECT
+/* 32 x 16K pages, 3 pages for kernel, whatever the RAM disk uses */
+#define MAX_MAPS       (32 - 3 - DEV_RD_RAM_PAGES)
+
+/* Banks as reported to user space */
+#define CONFIG_BANKS   4
+
+#define TICKSPERSEC 20      /* Ticks per second */
+#define PROGBASE    0x0000  /* also data base */
+#define PROGLOAD    0x0100  /* also data base */
+#define PROGTOP     0xF000  /* Top of program, base of U_DATA copy */
+#define KERNTOP     0xC000  /* Top of kernel (first 3 banks), base of shared bank */
+#define PROC_SIZE   64   /* Memory needed per process */
+
+/* WRS: this is probably wrong -- we want to swap the full 64K minus the common code */
+/* For now let's just use something and fix this up later when we have a swap device */
+#define SWAP_SIZE   0x7F       /* 63.5K in blocks (which is the wrong number) */
+#define SWAPBASE    0x0000     /* start at the base of user mem */
+#define SWAPTOP            0xFF00      /* can we stop at the top? not sure how. let's stop short. */
+#define MAX_SWAPS      10          /* Well, that depends really, hmmmmmm. Pick a number, any number. */
+
+/* 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 SWAPDEV  (256 + 1)  /* Device for swapping */
+#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         4        /* Number of mounts at a time */
+
+#define MAX_BLKDEV 4       /* 1 ROM disk, 1 RAM disk, 1 floppy, 1 PPIDE */
+
+#if 0  /* for now */
+/* On-board DS1302, we can read the time of day from it */
+#define CONFIG_RTC
+#define CONFIG_RTC_INTERVAL 30 /* deciseconds between reading RTC seconds counter */
+#endif
+
+/* Floppy support */
+#define CONFIG_FLOPPY          /* #define CONFIG_FLOPPY to enable floppy */
+
+/* Optional ParPortProp board connected to PPI */
+//#define CONFIG_PPP           /* #define CONFIG_PPP to enable as tty3 */
+
+#define CONFIG_SIO              /* #define CONFIG_SIO to enable SIO support */
+//#define CONFIG_ACIA              /* #define CONFIG_SIO to enable ACIA support */
+
+#define CONFIG_VFD_TERM         /* #define CONFIG_VFD_TERM to show console output on VFD display */
+
+// sanity check
+#ifdef CONFIG_SIO
+#ifdef CONFIG_ACIA
+#error "please define either CONFIG_SIO or CONFIG_ACIA but not both"
+#endif
+#endif
+
+/* Device parameters */
+#define CONFIG_DEV_MEM          /* enable /dev/mem driver */
+
+#define CONFIG_RAMDISK          /* enable memory-backed disk driver */
+#define DEV_RD_ROM_PAGES 28     /* size of the ROM disk in 16KB pages (max 32, any unused pages are at the start of the ROM) */
+#define DEV_RD_RAM_PAGES 0      /* size of the RAM disk in 16KB pages */
+
+#define DEV_RD_ROM_START ((uint32_t)(32-DEV_RD_ROM_PAGES) << 14)        /* first byte used by the ROM disk */
+#define DEV_RD_RAM_START ((uint32_t)(64-DEV_RD_RAM_PAGES) << 14)        /* first byte used by the RAM disk */
+#define DEV_RD_ROM_SIZE  ((uint32_t)DEV_RD_ROM_PAGES << 14)             /* size of the ROM disk */
+#define DEV_RD_RAM_SIZE  ((uint32_t)DEV_RD_RAM_PAGES << 14)             /* size of the RAM disk */
+
+#ifdef CONFIG_PPP
+       /* SD card in ParPortProp */
+       #define CONFIG_SD
+        #define SD_DRIVE_COUNT 1
+       #define NUM_DEV_TTY 3
+
+       /* ParPortProp as the console */
+       #define BOOT_TTY (512 + 3)
+#else
+       #define NUM_DEV_TTY 2
+
+       /* UART0 as the console */
+       #define BOOT_TTY (512 + 1)
+       #define TTY_INIT_BAUD B38400
+#endif
+
+#define TTYDEV   BOOT_TTY /* Device used by kernel for messages, panics */
diff --git a/Kernel/platform-rc2014/crt0.s b/Kernel/platform-rc2014/crt0.s
new file mode 100644 (file)
index 0000000..7183d9c
--- /dev/null
@@ -0,0 +1,114 @@
+; 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.
+        .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
+
+        ; exported symbols
+        .globl init
+        .globl init_from_rom
+        .globl _boot_from_rom
+
+        ; 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"
+
+        ; startup code
+        .area _CODE
+init:                       ; must be at 0x88 -- warm boot methods enter here
+        xor a
+        jr init_common
+init_from_rom:              ; must be at 0x8B -- bootrom.s enters here
+        ld a, #1
+        ; fall through
+init_common:
+        di
+        ld (_boot_from_rom), a
+        or a
+        jr nz, mappedok     ; bootrom.s loads us in the correct pages
+
+        ; move kernel to the correct location in RAM
+        ; note that this cannot cope with kernel images larger than 48KB
+        ld hl, #0x0000
+        ld a, #32               ; first page of RAM is page 32
+movenextbank:
+        out (MPGSEL_3), a       ; map page at 0xC000 upwards
+        ld de, #0xC000
+        ld bc, #0x4000          ; copy 16KB
+        ldir
+        inc a
+        cp #35                  ; done three pages?
+        jr nz, movenextbank
+
+       ; setup the memory paging for kernel
+        out (MPGSEL_3), a       ; map page 35 at 0xC000
+        ld a, #32
+        out (MPGSEL_0), a       ; map page 32 at 0x0000
+        inc a
+        out (MPGSEL_1), a       ; map page 33 at 0x4000
+        inc a
+        out (MPGSEL_2), a       ; map page 34 at 0x8000
+
+mappedok:
+        ; switch to stack in high memory
+        ld sp, #kstack_top
+
+        ; move the common memory where it belongs    
+        ld hl, #s__DATA
+        ld de, #s__COMMONMEM
+        ld bc, #l__COMMONMEM
+        ldir
+        ; and the discard
+        ld de, #s__DISCARD
+        ld bc, #l__DISCARD
+        ldir
+        ; then 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
+
+_boot_from_rom: .db 0
diff --git a/Kernel/platform-rc2014/devices.c b/Kernel/platform-rc2014/devices.c
new file mode 100644 (file)
index 0000000..63bbb7d
--- /dev/null
@@ -0,0 +1,47 @@
+#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_PPIDE
+  {  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 */
+#ifdef CONFIG_FLOPPY
+  {  fd_open,      fd_close,   fd_read,        fd_write,       no_ioctl},
+#else
+  {  no_open,      no_close,   no_rdwr,        no_rdwr,        no_ioctl},
+#endif
+  /* 2: /dev/tty -- serial ports */
+  {  tty_open,     tty_close,  tty_read,       tty_write,      tty_ioctl},
+  /* 3: RAM disk */
+#ifdef CONFIG_RAMDISK
+  {  rd_open,      no_close,   rd_read,        rd_write,       no_ioctl},
+#else
+  {  no_open,      no_close,   no_rdwr,        no_rdwr,        no_ioctl},
+#endif
+  /* 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/devrd_zeta2.c b/Kernel/platform-rc2014/devrd_zeta2.c
new file mode 100644 (file)
index 0000000..9588060
--- /dev/null
@@ -0,0 +1,45 @@
+/* Zeta SBC V2  memory driver
+ *
+ * 2017-01-03 William R Sowerbutts, based on RAM disk code by Sergey Kiselev
+ */
+
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#define DEVRD_PRIVATE
+#include "devrd.h"
+
+void rd_page_copy(void); // devrd_zeta2_hw.s
+
+void rd_platform_copy(void)
+{
+    uint16_t ocount, count, maxcpy;
+
+    ocount = count = rd_cpy_count;
+
+    while(true){
+        /* ensure transfer will not span a 16KB bank boundary */
+        maxcpy = ((uint16_t)rd_src_address) & 0x3FFF;
+        if((rd_dst_address & 0x3FFF) > maxcpy)
+            maxcpy = rd_dst_address & 0x3FFF;
+        maxcpy = 0x4000 - maxcpy;
+        if(rd_cpy_count > maxcpy)
+            rd_cpy_count = maxcpy;
+#ifdef DEBUG
+        kprintf("rd_transfer: src=0x%lx, dst=0x%x(%s) reverse=%d count=%d\n",
+                rd_src_address, rd_dst_address, rd_dst_userspace?"user":"kern",
+                rd_reverse, rd_cpy_count);
+#endif
+        rd_page_copy();
+
+        count -= rd_cpy_count;
+        if(!count)
+            break;
+
+        rd_dst_address += rd_cpy_count;
+        rd_src_address += rd_cpy_count;
+        rd_cpy_count = count;
+    }
+
+    rd_cpy_count = ocount;
+}
diff --git a/Kernel/platform-rc2014/devrd_zeta2_hw.s b/Kernel/platform-rc2014/devrd_zeta2_hw.s
new file mode 100644 (file)
index 0000000..05b2f86
--- /dev/null
@@ -0,0 +1,141 @@
+        .module devrd_hw
+
+        ; imported symbols
+        .globl map_kernel, mpgsel_cache, _kernel_pages
+        .globl _rd_platform_copy
+
+        ; exported symbols
+        .globl _rd_page_copy
+        .globl _rd_cpy_count
+        .globl _rd_reverse
+        .globl _rd_dst_userspace
+        .globl _rd_dst_address
+        .globl _rd_src_address
+        .globl _devmem_read
+        .globl _devmem_write
+
+        .include "../kernel.def"
+        .include "kernel.def"
+
+        .area _CODE
+_devmem_write:
+        ld a, #1
+        ld (_rd_reverse), a             ; 1 = write
+        jr _devmem_go
+
+_devmem_read:
+        xor a
+        ld (_rd_reverse), a             ; 0 = read
+        inc a
+_devmem_go:
+        ld (_rd_dst_userspace), a       ; 1 = userspace
+        ; load the other parameters
+        ld hl, (U_DATA__U_BASE)
+        ld (_rd_dst_address), hl
+        ld hl, (U_DATA__U_OFFSET)
+        ld (_rd_src_address), hl
+        ld hl, (U_DATA__U_OFFSET+2)
+        ld (_rd_src_address+2), hl
+        ld hl, (U_DATA__U_COUNT)
+        ld (_rd_cpy_count), hl
+        ; for single byte transfers we can optimise away the outer loop
+        dec l                           ; test for HL=1
+        ld a, h
+        or l
+        jp nz, _rd_platform_copy        ; > 1 byte, do it the hard way
+        call _rd_page_copy              ; transfer single byte
+        ld hl, #1                       ; return with HL set appropriately
+        ret
+
+        .area _COMMONMEM
+;=========================================================================
+; _rd_page_copy - Copy data from one physical page to another
+; See notes in devrd.h for input parameters
+;=========================================================================
+_rd_page_copy:
+        ; split rd_src_address into page and offset -- it's limited to 20 bits (max 0xFFFFF)
+        ; example address 0x000ABCDE 
+        ; in memory it is stored: DE BC 0A 00
+        ; offset would be 0x0ABCDE & 0x3FFF = 0x3CDE
+        ; page would be   0x0ABCDE >> 14    = 0x2A
+
+        ; compute source page number
+        ld a,(_rd_src_address+1)        ; load 0xBC -> B
+        ld b, a
+        ld a,(_rd_src_address+2)        ; load 0x0A -> A
+        rl b                            ; grab the top bit into carry
+        rla                             ; shift accumulator left, load carry bit at the bottom 
+        rl b                            ; and again
+        rla                             ; now A is the page number (0x2A)
+
+        ; map source page
+        ld (mpgsel_cache+1),a           ; save the mapping
+        out (MPGSEL_1),a                ; map source page to bank #1
+
+        ; compute source page offset, store in DE
+        ld a,(_rd_src_address+1)
+        and #0x3F                       ; mask to 16KB
+        or #0x40                        ; add offset for bank 1
+        ld d, a
+        ld a,(_rd_src_address+0)
+        ld e, a                         ; now offset is in DE
+
+        ; compute destination page index (addr 0xABCD >> 14 = 0x02)
+        ld a,(_rd_dst_address+1)        ; load top 8 bits
+        and #0xc0                       ; mask off top 2 bits
+        rlca                            ; rotate into lower 2 bits
+        rlca
+        ld b, #0
+        ld c, a                         ; store in l
+
+        ; look up page number
+        ld a,(_rd_dst_userspace)        ; are we loading into userspace memory?
+        or a
+        jr nz, rd_translate_userspace
+        ld hl, #_kernel_pages           ; get kernel page table
+        jr rd_do_translate
+rd_translate_userspace:
+        ld hl, #U_DATA__U_PAGE          ; get user process page table
+rd_do_translate:
+        add hl, bc                      ; add index to base ptr (uint8_t *)
+        ld a, (hl)                      ; load the page number from the page table
+
+        ; map destination page
+        ld (mpgsel_cache+2),a           ; save the mapping
+        out (MPGSEL_2),a                ; map destination page to bank #2
+
+        ; compute destination page offset, store in HL
+        ld a,(_rd_dst_address+1)
+        and #0x3F                       ; mask to 16KB
+        or #0x80                        ; add offset for bank #2
+        ld h, a
+        ld a, (_rd_dst_address+0)
+        ld l, a                         ; now offset is in HL
+
+        ; load byte count
+        ld bc,(_rd_cpy_count)           ; bytes to copy
+
+        ; check if reversed
+        ld a, (_rd_reverse)
+        or a
+        jr nz, go
+        ex de,hl                        ; reverse if necessary
+go:
+        ldir                            ; do the copy
+        jp map_kernel                   ; map back the kernel
+
+; variables
+_rd_cpy_count:
+        .dw     0                       ; uint16_t
+_rd_reverse:
+        .db     0                       ; bool
+_rd_dst_userspace:
+        .db     0                       ; bool
+_rd_dst_address:
+        .dw     0                       ; uint16_t
+_rd_src_address:
+        .db     0                       ; uint32_t
+        .db     0
+        .db     0
+        .db     0
+;=========================================================================
diff --git a/Kernel/platform-rc2014/devtty.c b/Kernel/platform-rc2014/devtty.c
new file mode 100644 (file)
index 0000000..2b47b7d
--- /dev/null
@@ -0,0 +1,155 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <tty.h>
+#include <devtty.h>
+#include <rc2014.h>
+#include "vfd-term.h"
+#include "vfd-debug.h"
+
+char tbuf1[TTYSIZ];
+char tbuf2[TTYSIZ];
+
+#ifdef CONFIG_PPP
+char tbufp[TTYSIZ];
+#endif
+
+unsigned char sio_type;
+
+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},
+#ifdef CONFIG_PPP
+       {tbufp, tbufp,  tbufp,  TTYSIZ, 0,      TTYSIZ/2},
+#endif
+};
+
+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;
+
+        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
+        }
+}
+
+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);
+        }
+}
+
+#ifdef CONFIG_PPP
+void tty_poll_ppp(void)
+{
+    while(PROPIO2_STAT & 0x20)
+        tty_inproc(3, PROPIO2_TERM);
+}
+#endif
+
+void tty_putc(uint8_t minor, unsigned char c)
+{
+//        while (tty_writeready(minor) != TTY_READY_NOW) ;
+       if (minor == 1) {
+#ifdef CONFIG_SIO
+               SIOA_D = c;
+#endif
+#ifdef CONFIG_ACIA
+               ACIA_D = c;
+#endif
+#ifdef CONFIG_VFD_TERM
+                vfd_term_write(c);
+#endif
+       } else if (minor == 2) {
+               SIOB_D = c;
+#ifdef CONFIG_PPP
+       } else if (minor = 3) {
+               /* FIXME: implement */
+#endif
+       }
+}
+
+void tty_sleeping(uint8_t minor)
+{
+       if (minor == 1) {
+//             UART0_IER = 0x0B; /* enable all but LSR interrupt */
+       }
+}
+
+ttyready_t tty_writeready(uint8_t minor)
+{
+       uint8_t c;
+       if (minor == 1) {
+#ifdef CONFIG_SIO
+            SIOA_C = 0; // read register 0
+            c = SIOA_C;
+           if (c & 0x04) /* THRE? */
+               return TTY_READY_NOW;
+            return TTY_READY_SOON;
+#endif
+#ifdef CONFIG_ACIA
+            c = ACIA_C;
+           if (c & 0x02) /* THRE? */
+               return TTY_READY_NOW;
+            return TTY_READY_SOON;
+#endif
+       } else  if (minor == 2) {
+#ifdef CONFIG_SIO
+            SIOB_C = 0; // read register 0
+            c = SIOB_C;
+           if (c & 0x04) /* THRE? */
+               return TTY_READY_NOW;
+            return TTY_READY_SOON;
+#endif
+       }
+       return TTY_READY_NOW;
+}
+
+/* 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/devtty.h b/Kernel/platform-rc2014/devtty.h
new file mode 100644 (file)
index 0000000..e88fb5e
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef __DEVTTY_DOT_H__
+#define __DEVTTY_DOT_H__
+
+#define SIO_SIO 1
+
+void tty_putc(uint8_t minor, unsigned char c);
+void tty_pollirq_sio(void);
+void tty_pollirq_acia(void);
+
+void sio_init(void);
+void acia_init(void);
+
+#ifdef CONFIG_PPP
+void tty_poll_ppp(void);
+#endif
+#endif
diff --git a/Kernel/platform-rc2014/devtty_discard.c b/Kernel/platform-rc2014/devtty_discard.c
new file mode 100644 (file)
index 0000000..989d99f
--- /dev/null
@@ -0,0 +1,21 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <tty.h>
+#include <devtty.h>
+#include <rc2014.h>
+
+extern unsigned char sio_type;
+
+/* uart0_init - detect UART type, print it, enable FIFO if present
+ */
+void sio_init(void) {
+        kprintf("UART0 type: SIO/2.\n");
+}
+
+void acia_init(void) {
+        kprintf("UART0 type: ACIA.\n");
+}
+
+
diff --git a/Kernel/platform-rc2014/discard.c b/Kernel/platform-rc2014/discard.c
new file mode 100644 (file)
index 0000000..74f3fef
--- /dev/null
@@ -0,0 +1,62 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+#include <ds1302.h>
+#include "config.h"
+#include "devrd.h"
+#include "vfd-term.h"
+
+/* Everything in here is discarded after init starts */
+
+#ifdef CONFIG_PPIDE
+#include <devide.h>
+void ppide_init(void);
+#endif
+
+void init_hardware_c(void)
+{
+//    vfd_debug_init();
+#ifdef CONFIG_VFD_TERM
+    vfd_term_init();
+#endif
+    ramsize = 512;
+    procmem = 512 - 64 - (DEV_RD_RAM_PAGES<<4);
+    /* zero out the initial bufpool */
+    memset(bufpool, 0, (char*)bufpool_end - (char*)bufpool);
+}
+
+void pagemap_init(void)
+{
+       int i;
+
+       /* ZETA SBC V2 has RAM in the top 512 KiB of physical memory
+        * corresponding pages are 32-63 (page size is 16 KiB)
+        * Pages 32-34 are used by the kernel
+        * Page 35 is the common area
+        * Pages starting from DEV_RD_START are used by RAM disk
+        */
+       for (i = 32 + 4; i < (DEV_RD_RAM_START >> 14); i++)
+               pagemap_add(i);
+
+       /* finally add the common area */
+       pagemap_add(32 + 3);
+}
+
+void map_init(void)
+{
+}
+
+void device_init(void)
+{
+#ifdef CONFIG_SIO
+       sio_init();
+#endif
+#ifdef CONFIG_ACIA
+       acia_init();
+#endif
+#ifdef CONFIG_PPIDE
+       ppide_init();
+       devide_init();
+#endif
+}
diff --git a/Kernel/platform-rc2014/diskboot.s b/Kernel/platform-rc2014/diskboot.s
new file mode 100644 (file)
index 0000000..9b57d5e
--- /dev/null
@@ -0,0 +1,197 @@
+; 2015-01-21 Will Sowerbutts <will@sowerbutts.com>
+;
+; Boot sector for N8VEM Mark IV SBC with UNA BIOS, based on
+; my UNA CP/M boot sector (2014-07-11)
+
+        .module diskboot
+
+
+; we are loaded at 0x8000
+himem     = 0xFA00 ; our location in memory
+buffer    = 0xF800 ; disk buffer (512 bytes)
+stacktop  = 0xFE00 ; top of stack (512 bytes)
+
+; UNA BIOS constants
+UNABIOS_STUB_ENTRY          = 0xFFFD    ; main UNA entry vector
+UNABIOS_BOOTHISTORY         = 0xFC      ; C register (subfunction in B)
+UNABIOS_BOOT_GET            = 0x00      ;   B register (BOOTHISTORY subfunction)
+UNABIOS_GETINFO             = 0xFA      ; C regsister (subfunction in B)
+UNABIOS_GET_USER_PAGES      = 0x05      ;   B register (GETINFO subfunction)
+UNABIOS_BANKEDMEM           = 0xFB      ; C register (subfunction in B)
+UNABIOS_BANK_GET            = 0x00      ;   B register (BANKEDMEM subfunction)
+UNABIOS_BANK_SET            = 0x01      ;   B register (BANKEDMEM subfunction)
+UNABIOS_GET_HMA             = 0xF1      ; C register (subfunction in B)
+UNABIOS_BLOCK_SETLBA        = 0x41      ; C register (unit number in B, 28-bit LBA in DEHL)
+UNABIOS_BLOCK_READ          = 0x42      ; C register (unit number in B, buffer address in DE, sector count in L)
+UNABIOS_OUTPUT_WRITE        = 0x12      ; C register (unit number in B)
+
+        .area _LOADER (ABS)
+        .org himem
+start:
+        ; UNA BIOS loads us from disk sector 0 at 0x8000
+        jr gocopy                       ; we must start with a JP or JR instruction.
+        .ds 0x40 - (.-start)            ; must leave room for floppy or partition superblock information
+
+        ; Copy us up into high memory
+gocopy: ld hl, #0x8000
+        ld de, #himem
+        ld bc, #512
+        ldir
+        jp go
+        
+        ; Executes in high memory
+go:     ld sp, #stacktop                ; set inital stack
+        ; write a character
+        ld e, #0x5B                     ; '['
+        call printchar
+
+        ; determine the boot unit
+        ld bc, #(UNABIOS_BOOT_GET << 8 | UNABIOS_BOOTHISTORY)
+        call #UNABIOS_STUB_ENTRY
+        ld a, l
+        ld (unit), a                    ; save boot unit
+
+        ; get the page number for the user memory bank
+        ld bc, #(UNABIOS_GET_USER_PAGES << 8 | UNABIOS_GETINFO)
+        call #UNABIOS_STUB_ENTRY
+        ; returns EXEC_PAGE value in DE
+
+        ; map in user memory bank
+        ld bc, #(UNABIOS_BANK_SET << 8 | UNABIOS_BANKEDMEM)
+        call #UNABIOS_STUB_ENTRY
+
+        ; write unabios vector in user memory
+        ld hl, #UNABIOS_STUB_ENTRY
+        ld de, #0x0008
+        ld bc, #3
+        ldir
+
+        ; wipe BDOS entry vector
+        ld a, #0x76                     ; halt instruction
+        ld (0x0005), a                  ; this is used as a marker to detect cold boot versus warm reload
+
+        ; wipe persistent memory pointer (persist_ptr, immediately below UNA UBIOS stub / HMA)
+        ld c, #UNABIOS_GET_HMA          ; get pointer to lowest byte used by UNA BIOS stub
+        call #UNABIOS_STUB_ENTRY        ; returns lowest used byte in HL.
+        xor a                           ; zero out the two bytes below that.
+        dec hl
+        ld (hl), a
+        dec hl
+        ld (hl), a
+
+        ld a, (firstblock)
+        ld (block), a
+
+nextblock:
+        ; print a = character only every other block
+        ld a, (block)
+        and #1
+        jr z, setlba
+        ld e, #0x3D                     ; '='
+        call printchar
+
+setlba: ; set LBA
+        xor a
+        ld d, a
+        ld e, a
+        ld h, a
+        ld a, (block)
+        ld l, a
+        inc a               ; setup for next block now
+        ld (block), a
+        ld c, #UNABIOS_BLOCK_SETLBA
+        ld a, (unit)
+        ld b, a
+        call #UNABIOS_STUB_ENTRY
+        jr nz, error
+
+        ; read block into buffer
+        ld c, #UNABIOS_BLOCK_READ
+        ld a, (unit)
+        ld b, a
+        ld l, #1
+        ld de, #buffer
+        call #UNABIOS_STUB_ENTRY
+        jr nz, error
+
+        ; copy block into low memory
+        ld hl, #buffer
+        ld de, (copyaddr)
+        ld bc, #512
+        ldir
+
+        ld (copyaddr), de
+        ld a, (firstblock)
+        ld d, a
+        ld a, (count)
+        ld e, a
+        ld a, (block)
+        sub d
+        cp e
+        jr nz, nextblock
+
+        ld e, #0x5D         ; ']'
+        call printchar
+        ld e, #0x0D
+        call printchar
+        ld e, #0x0A
+        call printchar
+
+        ; we're loaded. let's go.
+        ld hl, (entryaddr)
+        jp (hl)
+
+
+; print a hex byte in A
+byt_out:
+        push af         ; save low nibble
+        rrca            ; move high nibble into position
+        rrca            ; **
+        rrca
+        rrca
+        call nib_out    ; put out the high nibble
+        pop af          ; fall into nib_out to put out low nibble
+; print a hex-nibble in A
+nib_out:
+        and #0x0F       ; mask the nibble
+        add #0          ; clear the AUX carry bit
+        daa             ; decimal adjust the A
+        add #0xF0       ; move hi-nib into carry, hi-nib is 0 or F
+        adc #0x40       ; form ascii character
+        ld  e, a
+        ; fall through into printchar
+printchar:
+        ld bc, #UNABIOS_OUTPUT_WRITE
+        jp UNABIOS_STUB_ENTRY
+
+error:
+        ; print the error
+        ld a, c
+        call byt_out
+        ld e, a
+        call printchar
+
+        ; sad face :(
+        ld e, #0x20     ; space
+        call printchar
+        ld e, #0x3A     ; ':'
+        call printchar
+        ld e, #0x28     ; '('
+        call printchar
+
+        ; park the vehicle
+        halt
+
+block:      .ds 1
+unit:       .ds 1
+firstblock: .db 2       ; start loading at sector 2
+count:      .db 124     ; max sectors we can load before we overwrite ourselves (62KB)
+copyaddr:   .dw 0x0088  ; load address
+entryaddr:  .dw 0x0088  ; entry address
+
+    .ds 0x1BE - ( . -start) ; pad to start of partition tables
+    .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; partition 1
+    .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; partition 2
+    .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; partition 3
+    .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; partition 4
+    .dw 0xAA55              ; DOS boot signature
diff --git a/Kernel/platform-rc2014/fuzix.lnk b/Kernel/platform-rc2014/fuzix.lnk
new file mode 100644 (file)
index 0000000..890d55c
--- /dev/null
@@ -0,0 +1,50 @@
+-mwxuy
+-i fuzix.ihx
+-b _CODE=0x0088
+-b _COMMONMEM=0xF000
+-b _DISCARD=0xE000
+-l z80
+platform-rc2014/crt0.rel
+platform-rc2014/commonmem.rel
+platform-rc2014/rc2014.rel
+platform-rc2014/vfd-debug.rel
+platform-rc2014/vfdterm.rel
+platform-rc2014/vfd-term.rel
+start.rel
+version.rel
+lowlevel-z80.rel
+platform-rc2014/tricks.rel
+platform-rc2014/main.rel
+timer.rel
+kdata.rel
+platform-rc2014/devfd.rel
+platform-rc2014/devfd_hw.rel
+platform-rc2014/devrd.rel
+platform-rc2014/devrd_hw.rel
+platform-rc2014/devrd_zeta2.rel
+platform-rc2014/devrd_zeta2_hw.rel
+platform-rc2014/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
+bank16k.rel
+tty.rel
+devsys.rel
+usermem.rel
+usermem_std-z80.rel
+platform-rc2014/discard.rel
+platform-rc2014/devtty.rel
+platform-rc2014/devtty_discard.rel
+platform-rc2014/mbr.rel
+platform-rc2014/blkdev.rel
+platform-rc2014/monitor.rel
+-e
diff --git a/Kernel/platform-rc2014/kernel.def b/Kernel/platform-rc2014/kernel.def
new file mode 100644 (file)
index 0000000..2b2864e
--- /dev/null
@@ -0,0 +1,48 @@
+; UZI mnemonics for memory addresses etc
+
+U_DATA                 .equ    0xF000  ; (this is struct u_data from kernel.h)
+U_DATA__TOTALSIZE      .equ    0x300   ; 256+256+256 bytes.
+Z80_TYPE               .equ    0       ; just a old good Z80
+USE_FANCY_MONITOR      .equ    1       ; disabling this saves around approx 0.5KB
+
+Z80_MMU_HOOKS          .equ 0
+
+PROGBASE               .equ    0x0000
+PROGLOAD               .equ    0x0100
+
+; Zeta SBC V2 mnemonics for I/O ports etc
+
+CONSOLE_RATE           .equ    38400
+
+CPU_CLOCK_KHZ          .equ    7372
+
+; VFD Debugging
+VFD_C   .EQU    0     ; control register
+VFD_D   .EQU    1     ; data register
+
+; Z80 CTC ports
+CTC_CH0                .equ    0x90    ; CTC channel 0 and interrupt vector
+CTC_CH1                .equ    0x91    ; CTC channel 1 (periodic interrupts)
+CTC_CH2                .equ    0x92    ; CTC channel 2 (UART interrupt)
+CTC_CH3                .equ    0x93    ; CTC channel 3 (PPI interrupt)
+
+; 37C65 FDC ports
+FDC_CCR                .equ    0x48    ; Configuration Control Register (W/O)
+FDC_MSR                .equ    0x50    ; 8272 Main Status Register (R/O)
+FDC_DATA       .equ    0x51    ; 8272 Data Port (R/W)
+FDC_DOR                .equ    0x58    ; Digital Output Register (W/O)
+FDC_TC         .equ    0x58    ; Pulse terminal count (R/O)
+
+; MMU Ports
+MPGSEL_0       .equ    0x78    ; Bank_0 page select register (W/O)
+MPGSEL_1       .equ    0x79    ; Bank_1 page select register (W/O)
+MPGSEL_2       .equ    0x7A    ; Bank_2 page select register (W/O)
+MPGSEL_3       .equ    0x7B    ; Bank_3 page select register (W/O)
+MPGENA         .equ    0x7C    ; memory paging enable register, bit 0 (W/O)
+
+; Define which serial device to use
+;    NOTE: Make sure this agrees with CONFIG_SIO and CONFIG_ACIA
+;          in config.h
+CONFIG_SIO      .equ   1
+CONFIG_ACIA     .equ   0
+
diff --git a/Kernel/platform-rc2014/main.c b/Kernel/platform-rc2014/main.c
new file mode 100644 (file)
index 0000000..83972ee
--- /dev/null
@@ -0,0 +1,66 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+#include "config.h"
+#ifdef CONFIG_FLOPPY
+#include <devfd.h>
+#endif
+
+extern unsigned char irqvector;
+struct blkbuf *bufpool_end = bufpool + NBUFS; /* minimal for boot -- expanded after we're done with _DISCARD */
+
+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++;
+    }
+}
+
+void platform_idle(void)
+{
+       /* Let's go to sleep while we wait for something to interrupt us;
+        * Makes the HALT LED go yellow, which amuses me greatly. */
+       __asm
+               halt
+       __endasm;
+}
+
+uint8_t platform_param(unsigned char *p)
+{
+    used(p);
+    return 0;
+}
+
+void platform_interrupt(void)
+{
+       switch(irqvector) {
+               case 1:
+#ifdef CONFIG_PPP
+                       tty_poll_ppp()
+#endif
+#ifdef CONFIG_FLOPPY
+                       fd_tick();
+#endif
+                       timer_interrupt();
+                       return;
+
+               case 4:
+#ifdef CONFIG_SIO
+                       tty_pollirq_sio();
+#endif
+                       return;
+                case 0x38:
+#ifdef CONFIG_ACIA
+                        tty_pollirq_acia();
+#endif
+                        return;
+               default:
+                       return;
+       }
+}
diff --git a/Kernel/platform-rc2014/monitor.s b/Kernel/platform-rc2014/monitor.s
new file mode 100644 (file)
index 0000000..5a18d1a
--- /dev/null
@@ -0,0 +1,37 @@
+; 2015-01-17 William R Sowerbutts
+
+                .module monitor
+                .include "kernel.def"
+                .globl _platform_monitor
+                .globl map_kernel
+
+; -----------------------------------------------------------------------------
+.ifne USE_FANCY_MONITOR ; -----------------------------------------------------
+                .area _CODE ; actual monitor lives in kernel bank
+                .include "../lib/monitor-z80.s"
+
+                .area _COMMONMEM ; just a stub goes in common memory
+_platform_monitor:
+                di
+                call map_kernel
+                jp monitor_entry
+
+
+; -----------------------------------------------------------------------------
+.else ; MICRO MONITOR ---------------------------------------------------------
+                .globl outchar
+                .globl outnewline
+                .globl outhl
+
+                .area _COMMONMEM
+_platform_monitor:  di
+                call outnewline
+                ; just dump a few words from the stack
+                ld b, #50
+stacknext:      pop hl
+                call outhl
+                ld a, #' '
+                call outchar
+                djnz stacknext
+                halt
+.endif
diff --git a/Kernel/platform-rc2014/platform_ide.h b/Kernel/platform-rc2014/platform_ide.h
new file mode 100644 (file)
index 0000000..95d67e1
--- /dev/null
@@ -0,0 +1,38 @@
+#ifdef CONFIG_PPIDE
+#define PPIDE_BASE 0x60         /* Base address of 8255A */
+#define IDE_REG_INDIRECT        /* IDE registers are not directly connected to the CPU bus */
+
+/* IDE control signal to 8255 port C mapping */
+#define PPIDE_A0_LINE           0x01 // Direct from 8255 to IDE interface
+#define PPIDE_A1_LINE           0x02 // Direct from 8255 to IDE interface
+#define PPIDE_A2_LINE           0x04 // Direct from 8255 to IDE interface
+#define PPIDE_CS0_LINE          0x08 // Inverter between 8255 and IDE interface
+#define PPIDE_CS1_LINE          0x10 // Inverter between 8255 and IDE interface
+#define PPIDE_WR_LINE           0x20 // Inverter between 8255 and IDE interface
+#define PPIDE_WR_BIT            5    // (1 << PPIDE_WR_BIT) = PPIDE_WR_LINE
+#define PPIDE_RD_LINE           0x40 // Inverter between 8255 and IDE interface
+#define PPIDE_RD_BIT            6    // (1 << PPIDE_RD_BIT) = PPIDE_RD_LINE
+#define PPIDE_RST_LINE          0x80 // Inverter between 8255 and IDE interface
+
+/* 8255 configuration */
+#define PPIDE_PPI_BUS_READ      0x92
+#define PPIDE_PPI_BUS_WRITE     0x80
+
+/* IDE register addresses */
+#define ide_reg_data      (PPIDE_CS0_LINE)
+#define ide_reg_error     (PPIDE_CS0_LINE | PPIDE_A0_LINE)
+#define ide_reg_features  (PPIDE_CS0_LINE | PPIDE_A0_LINE)
+#define ide_reg_sec_count (PPIDE_CS0_LINE | PPIDE_A1_LINE)
+#define ide_reg_lba_0     (PPIDE_CS0_LINE | PPIDE_A1_LINE | PPIDE_A0_LINE)
+#define ide_reg_lba_1     (PPIDE_CS0_LINE | PPIDE_A2_LINE)
+#define ide_reg_lba_2     (PPIDE_CS0_LINE | PPIDE_A2_LINE | PPIDE_A0_LINE)
+#define ide_reg_lba_3     (PPIDE_CS0_LINE | PPIDE_A2_LINE | PPIDE_A1_LINE)
+#define ide_reg_devhead   (PPIDE_CS0_LINE | PPIDE_A2_LINE | PPIDE_A1_LINE)
+#define ide_reg_command   (PPIDE_CS0_LINE | PPIDE_A2_LINE | PPIDE_A1_LINE | PPIDE_A0_LINE)
+#define ide_reg_status    (PPIDE_CS0_LINE | PPIDE_A2_LINE | PPIDE_A1_LINE | PPIDE_A0_LINE)
+#define ide_reg_altstatus (PPIDE_CS1_LINE | PPIDE_A2_LINE | PPIDE_A1_LINE)
+#define ide_reg_control   (PPIDE_CS1_LINE | PPIDE_A2_LINE | PPIDE_A1_LINE | PPIDE_A0_LINE)
+#endif /* CONFIG_PPIDE */
+
+#define ide_select(x)
+#define ide_deselect()
diff --git a/Kernel/platform-rc2014/ppide.c b/Kernel/platform-rc2014/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/rc2014.h b/Kernel/platform-rc2014/rc2014.h
new file mode 100644 (file)
index 0000000..1cb65e6
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef __RC2014_SIO_DOT_H__
+#define __RC2014_SIO_DOT_H__
+
+#include "config.h"
+
+#define SIO0_IVT 8
+
+#define SIO0_BASE 0x80
+__sfr __at (SIO0_BASE + 0) SIOA_D;
+__sfr __at (SIO0_BASE + 2) SIOA_C;
+__sfr __at (SIO0_BASE + 1) SIOB_D;
+__sfr __at (SIO0_BASE + 3) SIOB_C;
+
+/* ACIA is at same address as SIO. Assume CONFIG_ACIA or CONFIG_SIO has been
+   defined in config.h, but not both.
+*/
+
+#define ACIA_BASE 0x80
+__sfr __at (ACIA_BASE + 0) ACIA_C;
+__sfr __at (ACIA_BASE + 1) ACIA_D;
+
+extern bool boot_from_rom;
+
+#endif
diff --git a/Kernel/platform-rc2014/rc2014.s b/Kernel/platform-rc2014/rc2014.s
new file mode 100644 (file)
index 0000000..0cdbfe1
--- /dev/null
@@ -0,0 +1,496 @@
+; 2014-02-19 Sergey Kiselev
+; RC2014 hardware specific code
+
+        .module zeta_v2
+
+        ; 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 _irqvector
+       .globl platform_interrupt_all
+       .globl mpgsel_cache
+       .globl _kernel_pages
+       .globl _platform_reboot
+       .globl _bufpool
+
+        ; imported symbols
+        .globl _ramsize
+        .globl _procmem
+        .globl _init_hardware_c
+        .globl outhl
+        .globl outnewline
+       .globl interrupt_handler
+       .globl unix_syscall_entry
+       .globl nmi_handler
+       .globl null_handler
+        .globl _boot_from_rom
+
+       ; 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
+
+SIOA_D         .EQU    0x80             ; Base address of SIO/2 chip
+SIOA_C         .EQU    SIOA_D+2
+SIOB_D         .EQU    SIOA_D+1
+SIOB_C         .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:
+        ; program vectors for the kernel
+        ld hl, #0
+        push hl
+        call _program_vectors
+        pop hl
+
+        ; Stop floppy drive motors
+        ld a, #0x0C
+        out (FDC_DOR), a
+
+       ; initialize UART0
+        ld a, (_boot_from_rom)          ; do not set the baud rate and other
+        or a                            ; serial line parameters if the BIOS
+        jr z, init_partial_uart         ; already set them for us.
+        ; nothing to do here yet
+init_partial_uart:
+
+.if CONFIG_SIO
+        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,#0x1A          ; 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, #0x1A          ; 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
+        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
+        ; Only supported for SIO, since CTC must operate in IM2.
+        ; If you don't have a CTC probably nothing bad will happen, other than
+        ; your floppy not working.
+
+       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,#0xC7                      ; counter mode, 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,#0xD7                      ; counter mode, rising edge
+;                                      ; enable interrupts
+;      out (CTC_CH2),a                 ; set CH2 mode
+;      ld a,#1                         ; time constant = 1
+;      out (CTC_CH2),a                 ; set CH2 time constant
+;      ; FIXME: should use interrupts when PPP firmware allows it
+;      ld a,#0x37                      ; timer mode for now, disable interrupts
+;      out (CTC_CH3),a
+;      ld a,#0                         ; time constant = 256
+;      out (CTC_CH3),a                 ; set CH3 time constant
+
+       ld hl,#intvectors
+       ld a,l
+       and #0xF8                       ; get bits 7-3 of int. vectors table
+       out (CTC_CH0),a                 ; send it to CTC
+
+        ; Done CTC Stuff
+        ; ---------------------------------------------------------------------
+
+       ld hl,#intvectors
+       ld a,h                          ; get bits 15-8 of int. vectors table
+       ld i,a                          ; load to I register
+       im 2                            ; set Z80 CPU interrupt mode 2
+.endif
+
+.if CONFIG_ACIA
+        LD        A, #ACIA_RESET
+        OUT       (ACIA_C),A\r
+        LD        A, #ACIA_RTS_LOW_A\r
+        OUT       (ACIA_C),A         ; Initialise ACIA
+
+        im 1
+.endif
+
+        jp _init_hardware_c             ; pass control to C, which returns for us
+
+;=========================================================================
+; Kernel code
+;=========================================================================
+        .area _CODE
+
+_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.
+        di
+        ld hl, #(MPGENA << 8) | 0xD3    ; OUT (MPGENA), A
+        ld (0xFFFE), hl                 ; put it at the very top of RAM
+        xor a                           ; A=0
+        jp 0xFFFE                       ; execute it; PC then wraps to 0
+
+
+;=========================================================================
+; Common Memory (0xF000 upwards)
+;=========================================================================
+        .area _COMMONMEM
+
+;=========================================================================
+; Interrupt stuff
+;=========================================================================
+; IM2 interrupt verctors table
+; Note: this is linked after the udata block, so it is aligned on 256 byte
+; boundary
+intvectors:
+       .dw     ctc0_int                ; CTC CH0 used as prescaler for CH1
+       .dw     ctc1_int                ; timer interrupt handler
+       .dw     serial_int              ; UART interrupt handler
+       .dw     ppi_int                 ; PPI interrupt handler
+        .dw     sio_int                 ; SIO interrupt handler
+
+_irqvector:
+       .db     0                       ; used to identify interrupt vector
+
+; CTC CH0 shouldn't be used to generate interrupts
+; but we'll implement it just in case
+ctc0_int:
+       push af
+       xor a                           ; IRQ vector = 0
+       ld (_irqvector),a               ; store it
+       pop af
+       jp interrupt_handler
+
+; periodic timer interrupt
+ctc1_int:
+       push af
+       ld a,#1                         ; IRQ vector = 1
+       ld (_irqvector),a               ; store it
+       pop af
+       jp interrupt_handler
+
+; UART interrupt
+serial_int:
+       push af
+       ld a,#2                         ; IRQ vector = 2
+       ld (_irqvector),a               ; store it
+       pop af
+       jp interrupt_handler
+
+; PPI interrupt - not used for now
+ppi_int:
+       push af
+       ld a,#3                         ; IRQ vector = 3
+       ld (_irqvector),a               ; store it
+       pop af
+       jp interrupt_handler
+
+; SIO interrupt
+sio_int:
+       push af
+       ld a,#4                         ; IRQ vector = 4
+       ld (_irqvector),a               ; store it
+       pop af
+       jp interrupt_handler
+
+; int38h handler
+;    Calls interrupt_handler with irqvector of 0x38
+;       For SIO/2, nothing will happen, since it uses IM2
+;       For ACIA, serial interrupt handler will execute
+int38h_int:
+       push af
+        LD A, #'B'
+        OUT (VFD_D),A
+       ld a,#0x38                      ; not a real vector, just a signal that the 0x38h occurred
+       ld (_irqvector),a               ; store it
+       pop af
+       jp interrupt_handler
+
+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,#int38h_int
+       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
+; - kernel pages:     32 - 34
+; - common page:      35
+; - user space pages: 36 - 63
+;=========================================================================
+
+;=========================================================================
+; map_process_always - map process pages
+; Inputs: page table address in #U_DATA__U_PAGE
+; Outputs: none; all registers preserved
+;=========================================================================
+map_process_always:
+       push hl
+       ld hl,#U_DATA__U_PAGE
+        jr map_process_2_pophl_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 nz,map_process_2             ; HL == 0 - map the kernel
+
+;=========================================================================
+; map_kernel - map kernel pages
+; Inputs: none
+; Outputs: none; all registers preserved
+;=========================================================================
+map_kernel:
+       push hl
+       ld hl,#_kernel_pages
+        jr map_process_2_pophl_ret
+
+;=========================================================================
+; map_process_2 - map process or kernel pages
+; Inputs: page table address in HL
+; Outputs: none, HL destroyed
+;=========================================================================
+map_process_2:
+       push de
+       push af
+       ld de,#mpgsel_cache             ; paging registers are write only
+                                       ; so cache their content in RAM
+       ld a,(hl)                       ; memory page number for bank #0
+       ld (de),a
+       out (MPGSEL_0),a                ; set bank #0
+       inc hl
+       inc de
+       ld a,(hl)                       ; memory page number for bank #1
+       ld (de),a
+       out (MPGSEL_1),a                ; set bank #1
+       inc hl
+       inc de
+       ld a,(hl)                       ; memory page number for bank #2
+       ld (de),a
+       out (MPGSEL_2),a                ; set bank #2
+       pop af
+       pop de
+       ret
+
+;=========================================================================
+; map_restore - restore a saved page mapping
+; Inputs: none
+; Outputs: none, all registers preserved
+;=========================================================================
+map_restore:
+       push hl
+       ld hl,#map_savearea
+map_process_2_pophl_ret:
+       call map_process_2
+       pop hl
+       ret
+
+;=========================================================================
+; map_save - save the current page mapping to map_savearea
+; Inputs: none
+; Outputs: none
+;=========================================================================
+map_save:
+       push hl
+       ld hl,(mpgsel_cache)
+       ld (map_savearea),hl
+       ld hl,(mpgsel_cache+2)
+       ld (map_savearea+2),hl
+       pop hl
+       ret
+
+; MPGSEL registers are read only, so their content is cached here
+mpgsel_cache:
+       .db     0,0,0,0
+
+; kernel page mapping
+_kernel_pages:
+       .db     32,33,34,35
+
+; memory page mapping save area for map_save/map_restore
+map_savearea:
+       .db     0,0,0,0
+
+;=========================================================================
+; Basic console I/O
+;=========================================================================
+
+;=========================================================================
+; outchar - Wait for UART TX idle, then print the char in A
+; Inputs: A - character to print
+; Outputs: none
+;=========================================================================
+outchar:
+
+.if CONFIG_SIO
+       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
+.endif
+
+.if CONFIG_ACIA
+       push af
+       ; 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
+.endif
+
+        out (VFD_D),a
+       ret
+
+;=========================================================================
+; inchar - Wait for character on UART, return in A
+; Inputs: none
+; Outputs: A - received character, F destroyed
+;=========================================================================
+inchar:
+.if CONFIG_SIO
+        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
+       jp z,inchar                     ; no data, wait
+       in a,(SIOA_D)                   ; read the character from the UART
+.endif
+
+.if CONFIG_ACIA
+       in a,(ACIA_C)                   ; read Line Status Register
+       and #0x01                       ; test if data is in receive buffer
+       jp z,inchar                     ; no data, wait
+       in a,(ACIA_D)                   ; read the character from the UART
+.endif
+       ret
diff --git a/Kernel/platform-rc2014/target.mk b/Kernel/platform-rc2014/target.mk
new file mode 100644 (file)
index 0000000..3bffcde
--- /dev/null
@@ -0,0 +1 @@
+export CPU = z80
diff --git a/Kernel/platform-rc2014/tricks.s b/Kernel/platform-rc2014/tricks.s
new file mode 100644 (file)
index 0000000..6e8917f
--- /dev/null
@@ -0,0 +1,235 @@
+; 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 map_kernel
+       .globl _ramtop
+       .globl _need_resched
+       .globl mpgsel_cache
+
+        ; imported debug symbols
+        .globl outstring, outde, outhl, outbc, outnewline, outchar, outcharhex
+
+        .include "kernel.def"
+        .include "../kernel.def"
+
+        .area _COMMONMEM
+
+; ramtop must be in common for single process swapping cases
+; and its a constant for the others from before init forks so it'll be fine
+; here
+_ramtop:
+       .dw 0
+_need_resched:
+       .db 0
+
+; 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:
+        ; 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
+
+_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
+
+        ld hl, #P_TAB__P_PAGE_OFFSET+3 ; Common
+       add hl, de              ; process ptr
+       ld a, (hl)
+       out (MPGSEL_3), a       ; *CAUTION* our stack just left the building
+
+       ; ------- No stack -------
+        ; 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 hl, #P_TAB__P_STATUS_OFFSET
+       add hl, de
+       ld (hl), #P_RUNNING
+
+        ; 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)
+
+       ; ---- New task stack ----
+
+        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.
+
+       ; --------- we switch stack copies in this call -----------
+       call fork_copy                  ; copy 0x000 to udata.u_top and the
+                                       ; uarea and return on the childs
+                                       ; common
+       ; We are now in the kernel child context
+
+        ; 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
+
+        ; The child makes its own new process table entry, etc.
+        ld  hl, (fork_proc_ptr)
+        push hl
+        call _newproc
+        pop bc 
+
+       ; any calls to map process will now map the childs memory
+
+        ; 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
+
+fork_copy:
+       ld hl, (U_DATA__U_TOP)
+       ld de, #0x0fff
+       add hl, de              ; + 0x1000 (-1 for the rounding to follow)
+       ld a, h
+       rlca
+       rlca                    ; get just the number of banks in the bottom
+                               ; bits
+       and #3
+       inc a                   ; and round up to the next bank
+       ld b, a
+       ; we need to copy the relevant chunks
+       ld hl, (fork_proc_ptr)
+       ld de, #P_TAB__P_PAGE_OFFSET
+       add hl, de
+       ; hl now points into the child pages
+       ld de, #U_DATA__U_PAGE
+       ; and de is the parent
+fork_next:
+       ld a,(hl)
+       out (MPGSEL_1), a       ; 0x4000 map the child
+       ld c, a
+       inc hl
+       ld a, (de)
+       out (MPGSEL_2), a       ; 0x8000 maps the parent
+       inc de
+       exx
+       ld hl, #0x8000          ; copy the bank
+       ld de, #0x4000
+       ld bc, #0x4000          ; we copy the whole bank, we could optimise
+                               ; further
+       ldir
+       exx
+       call map_kernel         ; put the maps back so we can look in p_tab
+       djnz fork_next
+       ld a, c
+       ld (mpgsel_cache+3),a   ; cache the page number
+       out (MPGSEL_3), a       ; our last bank repeats up to common
+       ; --- we are now on the stack copy, parent stack is locked away ---
+       ret                     ; this stack is copied so safe to return on
+
+       
diff --git a/Kernel/platform-rc2014/vfd-debug.c b/Kernel/platform-rc2014/vfd-debug.c
new file mode 100644 (file)
index 0000000..acdf6a1
--- /dev/null
@@ -0,0 +1,10 @@
+#include "vfd-debug.h"
+
+void vfd_debug_init(void) {
+  VFD_C = 0x30;
+  VFD_D = 0;
+  VFD_C = 1;
+  VFD_C = 0x0F;
+  VFD_D = '>';
+}
+
diff --git a/Kernel/platform-rc2014/vfd-debug.h b/Kernel/platform-rc2014/vfd-debug.h
new file mode 100644 (file)
index 0000000..2a16b02
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __VFD_DEBUG_DOT_H__
+#define __VFD_DEBUG_DOT_H__
+
+#include "config.h"
+
+__sfr __at (0) VFD_C;
+__sfr __at (1) VFD_D;
+
+void vfd_debug_init(void);
+
+#define vprtch(c) VFD_D=(c);
+
+#endif
diff --git a/Kernel/platform-rc2014/vfd-term.c b/Kernel/platform-rc2014/vfd-term.c
new file mode 100644 (file)
index 0000000..1d74ea6
--- /dev/null
@@ -0,0 +1,18 @@
+#include "vfd-term.h"
+
+void vfd_term_init(void) {
+  __asm
+       call VFDTERM_PREINIT
+  __endasm;
+}
+
+void vfd_term_write(char c) {
+  __asm
+        ld      hl, #2+0
+        add     hl, sp
+        ld      e, (hl)
+        call    VFDTERM_PUTC
+  __endasm;
+  (void)c; // suppress error
+}
+
diff --git a/Kernel/platform-rc2014/vfd-term.h b/Kernel/platform-rc2014/vfd-term.h
new file mode 100644 (file)
index 0000000..89e4450
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef __VFD_TERM_DOT_H__
+#define __VFD_TERM_DOT_H__
+
+#include "config.h"
+
+void vfd_term_init(void);
+void vfd_term_write(char c);
+
+#endif
diff --git a/Kernel/platform-rc2014/vfdterm.s b/Kernel/platform-rc2014/vfdterm.s
new file mode 100644 (file)
index 0000000..1450a1b
--- /dev/null
@@ -0,0 +1,191 @@
+        .module vfdterm
+
+        .include "kernel.def"
+        .include "../kernel.def"
+
+        .globl  VFDTERM_PREINIT
+        .globl  VFDTERM_PUTC
+
+;------------------------
+; VFD dumb terminal
+;------------------------
+
+VFDTERM_C0            .EQU   0
+VFDTERM_D0            .EQU   1
+VFDTERM_C1            .EQU   2
+VFDTERM_D1            .EQU   3
+
+                 .area _DATA
+vfdPtr:          .DW     0
+vfdLen:          .DB     0
+vfdLine1:        .DW     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+vfdLine2:        .DW     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+vfdLine3:        .DW     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+vfdLine4:        .DW     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+
+vfdLineLen       .EQU    40
+
+
+                 .area _CODE
+VFDTERM_PREINIT:
+                  ; initialize first two lines
+                  LD      A, #0x30
+                  OUT     (VFDTERM_C0), A
+                  LD      A, #0
+                  OUT     (VFDTERM_D0), A
+                  LD      A, #1
+                  OUT     (VFDTERM_C0), A
+                  LD      A, #0x0C            ; display on, cursor off
+                  OUT     (VFDTERM_C0), A
+
+                  ; initialize second two lines
+                  LD      A, #0x30
+                  OUT     (VFDTERM_C1), A
+                  LD      A, #0
+                  OUT     (VFDTERM_D1), A
+                  LD      A, #1
+                  OUT     (VFDTERM_C1), A
+                  LD      A, #0x0F            ; display on, cursor on
+                  OUT     (VFDTERM_C1), A
+
+                  ; position to start of last line
+                  CALL   VFDTERM_SOL
+                  RET
+
+                  ; assume character in E
+VFDTERM_PUTC:     PUSH   AF
+                  PUSH   BC
+                  PUSH   DE
+                  PUSH   HL
+
+                  LD     A,E
+                  CP     #0x08
+                  JR     Z, VFDTERM_BSPC
+                  CP     #0x0A                ; line feed
+                  JR     Z, VFDTERM_NEWLINE
+                  CP     #0x0D                ; CR
+                  JR     Z, VFDTERM_CR
+
+VFDTERM_STOREC:   LD     A, E               ; write the character to the vfd
+                  OUT    (VFDTERM_D1), A
+
+                  LD     HL, (vfdPtr)        ; update pointer
+                  LD     (HL), E
+                  INC    HL
+                  LD     (vfdPtr), HL
+
+                  LD     A, (vfdLen)        ; update position index
+                  INC    A
+                  LD     (vfdLen), A
+
+                  LD     A, (vfdLen)        ; check if we just wrapped
+                  CP     #vfdLineLen
+                  JR     NZ, VFDTERM_PUTC_OUT
+
+VFDTERM_NEWLINE:
+                  CALL   VFDTERM_SCROLL
+                  CALL   VFDTERM_REDRAW
+                  CALL   VFDTERM_SOL
+                  JR     VFDTERM_PUTC_OUT
+
+VFDTERM_BSPC:     LD     A, (vfdLen)
+                  CP     #0x00
+                  JR     Z, VFDTERM_PUTC_OUT ; at beginning of buffer, no-op
+
+                  DEC    A                   ; decrement line len
+                  LD     (vfdLen), A
+                  LD     HL, (vfdPtr)        ; decrement ptr
+                  DEC    HL
+                  LD     (vfdPtr), HL
+
+                  LD     A, #0x10              ; shift cursor left one place
+                  OUT    (VFDTERM_C1), A
+
+                  JR     VFDTERM_PUTC_OUT
+
+VFDTERM_CR:       CALL   VFDTERM_SOL
+                  JR     VFDTERM_PUTC_OUT
+
+VFDTERM_PUTC_OUT:
+                  POP    HL
+                  POP    DE
+                  POP    BC
+                  POP    AF
+                  RET
+
+                  ; scroll the buffer up one line
+VFDTERM_SCROLL:
+                  LD     HL, #vfdLine2
+                  LD     DE, #vfdLine1
+                  LD     BC, #120
+                  LDIR                      ; do the move
+                  LD     HL, #vfdLine4       ; clear the last line of the buffer
+                  LD     BC, #vfdLineLen
+                  LD     A, #' '
+                  CALL   UTIL_FILL
+                  RET
+
+UTIL_FILL:
+       LD      D,H             ; SET DE TO HL\r
+       LD      E,L             ; SO DESTINATION EQUALS SOURCE\r
+       LD      (HL),A          ; FILL THE FIRST BYTE WITH DESIRED VALUE\r
+       INC     DE              ; INCREMENT DESTINATION\r
+       DEC     BC              ; DECREMENT THE COUNT\r
+       LDIR                    ; DO THE REST\r
+       RET                     ; RETURN
+
+                  ; move pointer to start of 4th line
+VFDTERM_SOL:
+                  LD     HL, #vfdLine4
+                  LD     (vfdPtr), HL
+                  LD     A, #0
+                  LD     (vfdLen), A
+                  LD     A, #0xC0             ; command to move to start of line 2
+                  OUT    (VFDTERM_C1), A    ; send to VFD
+                  RET
+
+VFDTERM_REDRAW:
+                  LD     A, #0x80             ; command to move to start of line 1
+                  OUT    (VFDTERM_C0), A
+                  LD     DE, #vfdLine1
+                  LD     C, #vfdLineLen
+VFDTERM_REDRAW0:  LD     A, (DE)
+                  INC    DE
+                  OUT    (VFDTERM_D0), A
+                  DEC    C
+                  JR     NZ, VFDTERM_REDRAW0
+
+                  LD     A, #0xC0             ; command to move to start of line 2
+                  OUT    (VFDTERM_C0), A
+                  LD     DE, #vfdLine2
+                  LD     C, #vfdLineLen
+VFDTERM_REDRAW1:  LD     A, (DE)
+                  INC    DE
+                  OUT    (VFDTERM_D0), A
+                  DEC    C
+                  JR     NZ, VFDTERM_REDRAW1
+
+                  LD     A, #0x80             ; command to move to start of line 3
+                  OUT    (VFDTERM_C1), A
+                  LD     DE, #vfdLine3
+                  LD     C, #vfdLineLen
+VFDTERM_REDRAW2:  LD     A, (DE)
+                  INC    DE
+                  OUT    (VFDTERM_D1), A
+                  DEC    C
+                  JR     NZ, VFDTERM_REDRAW2
+
+                  LD     A, #0xC0             ; command to move to start of line 4
+                  OUT    (VFDTERM_C1), A
+                  LD     DE, #vfdLine4
+                  LD     C, #vfdLineLen
+VFDTERM_REDRAW3:  LD     A, (DE)
+                  INC    DE
+                  OUT    (VFDTERM_D1), A
+                  DEC    C
+                  JR     NZ, VFDTERM_REDRAW3
+
+                  RET
+
+
+