zeta-v2: Initial support for Zeta SBC V2 platform
authorSergey Kiselev <skiselev@gmail.com>
Thu, 5 Mar 2015 18:16:07 +0000 (10:16 -0800)
committerSergey Kiselev <skiselev@gmail.com>
Thu, 5 Mar 2015 18:16:07 +0000 (10:16 -0800)
22 files changed:
Kernel/Makefile
Kernel/platform-zeta-v2/Makefile [new file with mode: 0644]
Kernel/platform-zeta-v2/README [new file with mode: 0644]
Kernel/platform-zeta-v2/bootrom.s [new file with mode: 0644]
Kernel/platform-zeta-v2/commonmem.s [new file with mode: 0644]
Kernel/platform-zeta-v2/config.h [new file with mode: 0644]
Kernel/platform-zeta-v2/crt0.s [new file with mode: 0644]
Kernel/platform-zeta-v2/devices.c [new file with mode: 0644]
Kernel/platform-zeta-v2/devrd.c [new file with mode: 0644]
Kernel/platform-zeta-v2/devrd.h [new file with mode: 0644]
Kernel/platform-zeta-v2/devrd_hw.s [new file with mode: 0644]
Kernel/platform-zeta-v2/devtty.c [new file with mode: 0644]
Kernel/platform-zeta-v2/devtty.h [new file with mode: 0644]
Kernel/platform-zeta-v2/discard.c [new file with mode: 0644]
Kernel/platform-zeta-v2/ds1302-n8vem.s [new file with mode: 0644]
Kernel/platform-zeta-v2/kernel.def [new file with mode: 0644]
Kernel/platform-zeta-v2/main.c [new file with mode: 0644]
Kernel/platform-zeta-v2/monitor.s [new file with mode: 0644]
Kernel/platform-zeta-v2/target.mk [new file with mode: 0644]
Kernel/platform-zeta-v2/tricks.s [new file with mode: 0644]
Kernel/platform-zeta-v2/zeta-v2.h [new file with mode: 0644]
Kernel/platform-zeta-v2/zeta-v2.s [new file with mode: 0644]

index 77ecfc3..2e951c9 100644 (file)
@@ -1,4 +1,4 @@
-TARGET_LIST = platform-nc100 platform-micropack platform-pcw8256 platform-socz80 platform-zx128 platform-trs80 platform-z80pack platform-z80pack-lite platform-z80pack32 platform-dragon platform-tgl6502 platform-plus3
+TARGET_LIST = platform-nc100 platform-micropack platform-pcw8256 platform-socz80 platform-zx128 platform-trs80 platform-z80pack platform-z80pack-lite platform-z80pack32 platform-dragon platform-tgl6502 platform-plus3 platform-zeta-v2
 
 #export TARGET = 8086test
 #export TARGET = atarist
@@ -11,14 +11,15 @@ TARGET_LIST = platform-nc100 platform-micropack platform-pcw8256 platform-socz80
 #export TARGET = nc100
 #export TARGET = p112
 #export TARGET = pcw8256
-export TARGET = plus3
+#export TARGET = plus3
 #export TARGET = px4plus
 #export TARGET = tgl6502
 #export TARGET = trs80
 #export TARGET = ubee
 #export TARGET = z80pack
 #export TARGET = z80pack-lite
-#export TARGET= zx128
+#export TARGET = zeta-v2
+#export TARGET = zx128
 
 export VERSION = "0.1"
 export SUBVERSION = "ac1"
diff --git a/Kernel/platform-zeta-v2/Makefile b/Kernel/platform-zeta-v2/Makefile
new file mode 100644 (file)
index 0000000..210bd68
--- /dev/null
@@ -0,0 +1,44 @@
+ASRCS = crt0.s tricks.s commonmem.s zeta-v2.s monitor.s
+ASRCS += ds1302-n8vem.s devrd_hw.s
+CSRCS = devices.c main.c devtty.c devrd.c
+DISCARD_CSRCS = discard.c
+DISCARD_DSRCS = ../dev/ds1302_discard.c
+DSRCS = ../dev/devsd.c ../dev/mbr.c ../dev/blkdev.c ../dev/ds1302.c
+
+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)
+
+CROSS_CCOPTS += -I../dev/
+
+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 $<
+
+clean:
+       rm -f $(OBJS) $(JUNK)  core *~ bootrom.ihx bootrom.bin
+
+image:
+       sdasz80 -o bootrom.s
+       sdldz80 -m -i bootrom.rel
+       makebin -s 256 bootrom.ihx > bootrom.bin
+       cat bootrom.bin ../fuzix.bin > ../fuzix.rom
diff --git a/Kernel/platform-zeta-v2/README b/Kernel/platform-zeta-v2/README
new file mode 100644 (file)
index 0000000..4aba9c6
--- /dev/null
@@ -0,0 +1,117 @@
+--- README for Zeta SBC V2 ---
+This is Fuzix for the Zeta SBV V2
+Written by Sergey Kiselev <skiselev@gmail.com>
+Heavily based on prior work by Will Sowerbutts <will@sowerbutts.com> and others
+
+Supported hardware:
+ - RAM disk
+ - RS232 serial port (16550 UART, tty1)
+ - Real time clock (should be, not tested)
+
+Memory allocation (16 KiB pages):
+- ROM pages:   0 - 31
+  - Kernel image:      0 - 2 - copied by bootrom.s to pages 32 - 34
+  - RAM disk image:    3 - 19 - copied by bootrom.s to pages 48 - 63
+- RAM pages:   32 - 63
+  - Kernel pages:      32 - 34
+  - Common page:       35
+  - User space pages:  36 - 47
+  - RAM disk:          48 - 63
+
+To build the kernel, edit the TARGET line in Kernel/Makefile to read:
+    export TARGET = zeta-v2
+Then run "make clean; make all" in the "Kernel" directory.
+
+Currently the system can be booted from the Flash ROM. Use the following steps
+to build the Flash ROM image:
+
+1. Build the kernel (see above)
+2. Build the userspace utils (needs to be documented)
+3. [In FUZIX/Kernel dir] Create a 256 KiB filesystem image:
+       ../Standalone/mkfs zeta_v2_rootfs.img 16 512
+4. Populate the filesystem image
+       ../Standalone/ucp zeta_v2_rootfs.img
+
+run the following ucp commands:
+
+mkdir bin
+chmod 0755 bin
+mkdir etc
+chmod 0755 etc
+mkdir dev
+chmod 0755 dev
+mkdir tmp
+chmod 01777 tmp
+mkdir usr
+chmod 0755 usr
+mkdir usr/lib
+chmod 0755 usr/lib
+mkdir root
+chmod 0700 root
+cd /dev
+mknod tty1  20660 513
+mknod tty2  20660 514
+mknod tty3  20660 515
+mknod tty4  20660 516
+mknod hda   60660 0
+mknod hda1  60660 1
+mknod fd0   60660 256
+mknod fd1   60660 257
+mknod null  20666 1024
+mknod mem   20660 1025
+mknod zero  20444 1026
+mknod proc  20660 1027
+cd /
+bget ../Applications/util/init
+chmod 0755 init
+cd /etc
+bget passwd
+chmod 0644 passwd
+cd /bin
+bget ../Applications/util/cat
+chmod 0755 cat
+bget ../Applications/util/cp
+chmod 0755 cp
+bget ../Applications/util/date
+chmod 0755 date
+bget ../Applications/util/df
+chmod 0755 df
+bget ../Applications/util/echo
+chmod 0755 echo
+bget ../Applications/util/fdisk
+chmod 0755 fdisk
+bget ../Applications/util/fsck
+chmod 0755 fsck
+bget ../Applications/util/ln
+chmod 0755 ln
+bget ../Applications/util/ls
+chmod 0755 ls
+bget ../Applications/util/mkdir
+chmod 0755 mkdir
+bget ../Applications/util/mkfs
+chmod 0755 mkfs
+bget ../Applications/util/mount
+chmod 0755 mount
+bget ../Applications/util/mv
+chmod 0755 mv
+bget ../Applications/util/passwd
+chmod 0755 passwd
+bget ../Applications/util/rm
+chmod 0755 rm
+bget ../Applications/util/rmdir
+chmod 0755 rmdir
+bget ../Applications/util/ssh
+chmod 0755 ssh
+bget ../Applications/util/umount
+chmod 0755 umount
+exit
+
+5. Create ROM image:
+dd if=fuzix.rom of=fuzix_48k.rom bs=48k count=1 conv=syn
+cat fuzix_48k.rom zeta_v2_rootfs.img > fuzix_zeta_v2_bootfs.rom
+
+6. Program the image (fuzix_zeta_v2_bootfs.rom) to the Flash ROM using an
+EPROM programmer
+
+7. Power on the the system. Enter device number 256 to boot from the RAM disk.
+
diff --git a/Kernel/platform-zeta-v2/bootrom.s b/Kernel/platform-zeta-v2/bootrom.s
new file mode 100644 (file)
index 0000000..ee95c87
--- /dev/null
@@ -0,0 +1,58 @@
+;
+;      ROM boot for FUZIX on the ZETA SBC V2
+;
+               .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
+               ; 3 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 #3                   ; are we there yet (RAM page == 3?)
+               jr nz,kernel_copy
+
+               ; copy data to RAM disk
+               ; 16 pages, starting from ROM page 3, RAM page 48
+               ld a,#3
+ramdisk_copy:
+               out (MPGSEL_1),a        ; map ROM page to bank #1
+               add #45                 ; RAM page = ROM page + 45
+               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 #44                 ; next ROM page = RAM page - 45 + 1
+               cp #19                  ; are we there yet (RAM page == 3 + 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 0x100                ; jump to crt0.s
+; pad
+               .ds     (0x100-(.-start))
diff --git a/Kernel/platform-zeta-v2/commonmem.s b/Kernel/platform-zeta-v2/commonmem.s
new file mode 100644 (file)
index 0000000..522503a
--- /dev/null
@@ -0,0 +1,9 @@
+;
+;      Common on z80pack is at 0xF000 as defined by hardware.
+;
+
+        .module commonmem
+
+        .area _COMMONMEM
+
+       .include "../cpu-z80/std-commonmem.s"
diff --git a/Kernel/platform-zeta-v2/config.h b/Kernel/platform-zeta-v2/config.h
new file mode 100644 (file)
index 0000000..4bcce9f
--- /dev/null
@@ -0,0 +1,73 @@
+/* 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, 16 pages for RAM disk */
+#define MAX_MAPS       13
+
+/* Banks as reported to user space */
+#define CONFIG_BANKS   4
+
+#define TICKSPERSEC 15      /* 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 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 "fd,hd#"
+
+//#define SWAPDEV  (256 + 1)  /* Device for swapping */
+#define NBUFS    10       /* Number of block buffers */
+#define NMOUNTS         4        /* Number of mounts at a time */
+
+#define MAX_BLKDEV 4       /* 1 ROM disk, 1 RAM disk, 1 floppy, 1 SD card */
+
+/* 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 */
+
+/* Optional ParPortProp board connected to PPI */
+//#define CONFIG_PPP           /* #define CONFIG_PPP to enable as tty3 */
+
+/* Device parameters */
+#define NUM_DEV_RD 1
+#define DEV_RD_PAGES 16                /* size of the RAM disk in pages */
+#define DEV_RD_START 48                /* first page used by the RAM disk */
+
+#ifdef CONFIG_PPP
+       /* SD card in ParPortProp */
+       #define DEVICE_SD
+        #define SD_DRIVE_COUNT 1
+       #define NUM_DEV_TTY 2
+
+       /* ParPortProp as the console */
+       #define BOOT_TTY (512 + 2)
+#else
+       #define NUM_DEV_TTY 1
+
+       /* UART0 as the console */
+       #define BOOT_TTY (512 + 1)
+#endif
+
+#define TTYDEV   BOOT_TTY /* Device used by kernel for messages, panics */
diff --git a/Kernel/platform-zeta-v2/crt0.s b/Kernel/platform-zeta-v2/crt0.s
new file mode 100644 (file)
index 0000000..a618496
--- /dev/null
@@ -0,0 +1,75 @@
+; 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 _DATA
+        .area _INITIALIZED
+        .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 _INITIALIZER
+        .area _GSINIT
+        .area _GSFINAL
+        .area _DISCARD
+        .area _COMMONMEM
+
+        ; imported symbols
+        .globl _fuzix_main
+        .globl init_early
+        .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:
+        di
+        ld sp, #kstack_top
+        ; move the common memory where it belongs    
+        ld hl, #s__INITIALIZER
+        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
+
+       ; setup the rest of the memory paging
+       call init_early
+
+        ; 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-zeta-v2/devices.c b/Kernel/platform-zeta-v2/devices.c
new file mode 100644 (file)
index 0000000..fb27ee6
--- /dev/null
@@ -0,0 +1,39 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <tty.h>
+#include <devsys.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/fd - Floppy disk block devices */
+  {  no_open,      no_close,   no_rdwr,        no_rdwr,        no_ioctl},
+  /* 1: /dev/hd - RAM disk interface */
+  {  rd_open,      no_close,   rd_read,        rd_write,       no_ioctl},
+  /* 2: /dev/tty -- serial ports */
+  {  tty_open,     tty_close,  tty_read,       tty_write,      tty_ioctl},
+  /* 3: unused slot */
+  {  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;
+}
+
+void device_init(void)
+{
+    ds1302_init();
+}
diff --git a/Kernel/platform-zeta-v2/devrd.c b/Kernel/platform-zeta-v2/devrd.c
new file mode 100644 (file)
index 0000000..728376d
--- /dev/null
@@ -0,0 +1,121 @@
+/* Zeta SBC V2 RAM disk driver 
+ *
+ * Implements a single RAM disk DEV_RD_PAGES size and
+ * starting from DEV_RD_START page
+ *
+ * */
+
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+
+extern uint8_t src_page;       /* source page number */
+extern uint8_t dst_page;       /* destination page number */
+extern uint16_t src_offset;    /* offset of the data in the source page */
+extern uint16_t dst_offset;    /* offset of the data in the destination page */
+extern uint16_t cpy_count;     /* data transfer length */
+extern uint8_t kernel_pages[]; /* kernel's page table */
+
+int ramdisk_transfer(bool is_read, uint8_t minor, uint8_t rawflag);
+int page_copy(void);           /* assembler code */
+
+int rd_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;
+    return ramdisk_transfer(true, minor, rawflag);
+}
+
+int rd_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;
+    return ramdisk_transfer(false, minor, rawflag);
+}
+
+int ramdisk_transfer(bool is_read, uint8_t minor, uint8_t rawflag)
+{
+       blkno_t block;
+       int block_xfer;     /* r/w return value (number of 512 byte blocks transferred) */
+       uint32_t rd_addr;
+       uint16_t buffer_addr;
+       usize_t xfer_count;
+
+       if (minor >= NUM_DEV_RD) {
+               udata.u_error = ENXIO;
+               return -1;
+       }
+
+       if (rawflag) { /* rawflag == 1, read to or write from user space */
+               xfer_count = udata.u_count;
+               buffer_addr = (uint16_t) udata.u_base;
+               block = udata.u_offset >> 9;
+               block_xfer = xfer_count >> 9;
+       } else { /* rawflag == 0, read to or write from kernel space */
+               xfer_count = 512;
+               buffer_addr = (uint16_t) udata.u_buf->bf_data;
+               block = udata.u_buf->bf_blk;
+               block_xfer = 1;
+       }
+
+       if (block > (DEV_RD_PAGES * 16 * 2)) { /* block beyond RAM disk end? */
+               udata.u_error = EIO;
+               return -1;
+       }
+
+       /* calculate physical address of the RAM drive data */
+       /* rd_addr = block * 512 + DEV_RD_START * 16K; */
+       rd_addr = ((unsigned long) block << 9) + DEV_RD_START * 16384UL;
+       while (xfer_count > 0) {
+               if (is_read) {
+                       /* RAM disk page number = rd_addr / 16K */
+                       src_page = rd_addr >> 14;
+                       /* offset within RAM disk page */
+                       src_offset = rd_addr & 0x3FFF;
+                       /* destination page number */
+                       if (rawflag)
+                               dst_page = ((uint8_t *) &udata.u_page)[buffer_addr >> 14];
+                       else
+                               dst_page = kernel_pages[buffer_addr >> 14];
+                       /* offset in the destination page */
+                       dst_offset = buffer_addr & 0x3FFF;
+               } else {
+                       /* source page number */
+                       if (rawflag)
+                               src_page = ((uint8_t *) &udata.u_page)[buffer_addr >> 14];
+                       else
+                               src_page = kernel_pages[buffer_addr >> 14];
+                       /* offset in the source page */
+                       src_offset = buffer_addr & 0x3FFF;
+                       /* RAM disk page number = rd_addr / 16K */
+                       dst_page = rd_addr >> 14;
+                       /* offset within RAM disk page */
+                       dst_offset = rd_addr & 0x3FFF;
+               }
+               cpy_count = xfer_count;
+               if (cpy_count > 16384 - src_offset)
+                       cpy_count = 16384 - src_offset;
+               if (cpy_count > 16384 - dst_offset)
+                       cpy_count = 16384 - dst_offset;
+#ifdef DEBUG
+               kprintf("page_cpy(src_page=%x, src_offset=%x, dst_page=%x, dst_offset=%x, cpy_count=%x)\n", src_page, src_offset, dst_page, dst_offset, cpy_count);
+#endif
+               __critical {
+                       page_copy();
+               }
+               xfer_count -= cpy_count;
+               buffer_addr += cpy_count;
+               rd_addr += cpy_count;
+       }
+
+       return block_xfer;
+}
+
+
+int rd_open(uint8_t minor)
+{
+    if(minor < NUM_DEV_RD){
+        return 0;
+    } else {
+        udata.u_error = EIO;
+        return -1;
+    }
+}
diff --git a/Kernel/platform-zeta-v2/devrd.h b/Kernel/platform-zeta-v2/devrd.h
new file mode 100644 (file)
index 0000000..e54a154
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __DEVRD_DOT_H__
+#define __DEVRD_DOT_H__
+
+/* public interface */
+int rd_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int rd_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int rd_init(void);
+int rd_open(uint8_t minor, uint16_t flag);
+
+#endif /* __DEVRD_DOT_H__ */
diff --git a/Kernel/platform-zeta-v2/devrd_hw.s b/Kernel/platform-zeta-v2/devrd_hw.s
new file mode 100644 (file)
index 0000000..65a1fd1
--- /dev/null
@@ -0,0 +1,59 @@
+       .module devrd_hw
+
+       ; imported symbols - from zeta-v2.s
+       .globl map_table
+
+       ; exported symbols (used by devrd.c)
+       .globl _page_copy
+       .globl _src_page, _src_offset, _dst_page, _dst_offset, _cpy_count
+
+       .include "kernel.def"
+
+       .area _COMMONMEM
+
+;=========================================================================
+; _page_copy - Copy data from one physical page to another
+; Inputs:
+;   _src_page - page number of the source page (uint8_t)
+;   _src_offset - offset in the source page (uint16_t)
+;   _dst_page - page number of the destination page (uint8_t)
+;   _dst_offset - offset in the destination page (uint16_t)
+;   _cpy_count - number of bytes to copy (uint16_t)
+;   map_table - current page register values, used to restore paging registers
+; Outputs:
+;   Data copied
+;   Destroys AF, BC, DE, HL
+;=========================================================================
+_page_copy:
+       ld a,(_src_page)
+       out (MPGSEL_1),a                ; map source page to bank #1
+       ld a,(_dst_page)
+       out (MPGSEL_2),a                ; map destination page to bank #2
+       ld hl,(_src_offset)             ; load offset in source page
+       ld a,#0x40                      ; add bank #1 offset - 0x4000
+       add h                           ; to the source offset
+       ld h,a
+       ld de,(_dst_offset)
+       ld a,#0x80                      ; add bank #2 offset - 0x8000
+       add d                           ; to the destination offset
+       ld d,a
+       ld bc,(_cpy_count)              ; bytes to copy
+       ldir                            ; do the copy
+       ld a,(map_table+1)
+       out (MPGSEL_1),a                ; restore the mapping of bank #1
+       ld a,(map_table+2)
+       out (MPGSEL_2),a                ; restore the mapping of bank #2
+       ret
+
+; variables
+_src_page:
+       .db     0
+_dst_page:
+       .db     0
+_src_offset:
+       .dw     0
+_dst_offset:
+       .dw     0
+_cpy_count:
+       .dw     0
+;=========================================================================
diff --git a/Kernel/platform-zeta-v2/devtty.c b/Kernel/platform-zeta-v2/devtty.c
new file mode 100644 (file)
index 0000000..f9ac01b
--- /dev/null
@@ -0,0 +1,87 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <tty.h>
+#include <devtty.h>
+#include <zeta-v2.h>
+
+char tbuf1[TTYSIZ];
+
+#ifdef CONFIG_PPP
+char tbufp[TTYSIZ];
+#endif
+
+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 },
+#ifdef CONFIG_PPP
+    {   tbufp,   tbufp,   tbufp,   TTYSIZ,   0,   TTYSIZ/2 },
+#endif
+};
+
+/* FIXME: implement */
+void tty_setup(uint8_t minor)
+{
+    minor;
+}
+
+/* FIXME: implement (although /DCD is hardwired to GND) */
+int tty_carrier(uint8_t minor)
+{
+    minor;
+    return 1;
+}
+
+void tty_interrupt(void)
+{
+       uint8_t reg = UART0_LSR;
+       if (reg & 0x01) {
+               /* data available */
+               reg = UART0_RBR;
+               tty_inproc(1, reg);
+       }
+}
+
+#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)
+{
+       if (minor == 1) {
+               while(!(UART0_LSR & 0x20));
+               UART0_THR = c;
+#ifdef CONFIG_PPP
+       } else if (minor = 2) {
+               /* FIXME: implement */
+#endif
+       }
+}
+
+void tty_sleeping(uint8_t minor)
+{
+       minor;
+}
+
+ttyready_t tty_writeready(uint8_t minor)
+{
+       uint8_t reg;
+       if (minor == 1) {
+               reg = UART0_LSR;
+               return (reg & 0x20) ? TTY_READY_NOW : TTY_READY_SOON;
+       }
+       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-zeta-v2/devtty.h b/Kernel/platform-zeta-v2/devtty.h
new file mode 100644 (file)
index 0000000..242631e
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef __DEVTTY_DOT_H__
+#define __DEVTTY_DOT_H__
+void tty_putc(uint8_t minor, unsigned char c);
+void tty_interrupt(void);
+
+#ifdef CONFIG_PPP
+void tty_poll_ppp(void);
+#endif
+#endif
diff --git a/Kernel/platform-zeta-v2/discard.c b/Kernel/platform-zeta-v2/discard.c
new file mode 100644 (file)
index 0000000..fca69f8
--- /dev/null
@@ -0,0 +1,26 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+#include "config.h"
+
+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_START; i++)
+        pagemap_add(i);
+
+    /* finally add the common area */
+    pagemap_add(32 + 3);
+}
+
+void map_init(void)
+{
+}
diff --git a/Kernel/platform-zeta-v2/ds1302-n8vem.s b/Kernel/platform-zeta-v2/ds1302-n8vem.s
new file mode 100644 (file)
index 0000000..d215b82
--- /dev/null
@@ -0,0 +1,76 @@
+; 2015-02-19 Sergey Kiselev
+; 2014-12-31 William R Sowerbutts
+; N8VEM SBC / Zeta SBC DS1302 real time clock interface code
+
+        .module ds1302-n8vem
+
+        ; exported symbols
+        .globl _ds1302_set_pin_ce
+        .globl _ds1302_set_pin_clk
+        .globl _ds1302_set_pin_data
+        .globl _ds1302_set_pin_data_driven
+        .globl _ds1302_get_pin_data
+
+        .include "kernel.def"
+        .include "../kernel.def"
+
+; -----------------------------------------------------------------------------
+; DS1302 interface
+; -----------------------------------------------------------------------------
+
+N8VEM_RTC       = 0x70
+PIN_CE          = 0x10
+PIN_DATA_HIZ    = 0x20
+PIN_CLK         = 0x40
+PIN_DATA_OUT    = 0x80
+PIN_DATA_IN     = 0x01
+
+.area _DATA
+
+rtc_shadow:     .db 0           ; we can't read back the latch contents, so we must keep a copy
+
+.area _CODE
+
+_ds1302_get_pin_data:
+        in a, (N8VEM_RTC)       ; read input register
+        and #PIN_DATA_IN        ; mask off data pin
+        ld l, a                 ; return result in L
+        ret
+
+_ds1302_set_pin_data_driven:
+        ld hl, #2               ; get address of function argument
+        add hl, sp
+        ld b, (hl)              ; load argument from stack
+        ld a, (rtc_shadow)
+        and #~PIN_DATA_HIZ      ; 0 - output pin
+        bit 0, b                ; test bit
+        jr nz, writereg
+        or #PIN_DATA_HIZ
+        jr writereg
+
+_ds1302_set_pin_data:
+        ld bc, #(((~PIN_DATA_OUT) << 8) | PIN_DATA_OUT)
+        jr setpin
+
+_ds1302_set_pin_ce:
+        ld bc, #(((~PIN_CE) << 8) | PIN_CE)
+        jr setpin
+
+_ds1302_set_pin_clk:
+        ld bc, #(((~PIN_CLK) << 8) | PIN_CLK)
+        jr setpin
+
+setpin:
+        ld a, (rtc_shadow)      ; load current register contents
+        and b                   ; unset the pin
+        ld hl, #2               ; get address of function argument
+        add hl, sp
+        ld b, (hl)              ; load argument from stack
+        bit 0, b                ; test bit
+        jr z, writereg          ; arg is false
+        or c                    ; arg is true
+writereg:
+        out (N8VEM_RTC), a      ; write out new register contents
+        ld (rtc_shadow), a      ; update our shadow copy
+        ret
+
diff --git a/Kernel/platform-zeta-v2/kernel.def b/Kernel/platform-zeta-v2/kernel.def
new file mode 100644 (file)
index 0000000..d723ee6
--- /dev/null
@@ -0,0 +1,60 @@
+; 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 an old good Z80
+;RAM_KB                        .equ    512
+RAM_KB                 .equ    256
+USE_FANCY_MONITOR      .equ    1       ; disabling this saves around approx 0.5KB
+
+PROGBASE               .equ    0x0000
+PROGLOAD               .equ    0x0100
+
+; Zeta SBC V2 mnemonics for I/O ports etc
+
+CONSOLE_RATE           .equ    38400
+
+; Z80 CTC ports
+CTC_CH0                .equ    0x20    ; CTC channel 0 and interrupt vector
+CTC_CH1                .equ    0x21    ; CTC channel 1 (periodic interrupts)
+CTC_CH2                .equ    0x22    ; CTC channel 2 (UART interrupt)
+CTC_CH3                .equ    0x23    ; CTC channel 3 (PPI interrupt)
+
+; 37C65 FDC ports
+FDC_CCR                .equ    0x28    ; Configuration Control Register (W/O)
+FDC_MSR                .equ    0x30    ; 8272 Main Status Register (R/O?)
+FDC_DATA       .equ    0x31    ; 8272 Data Port (R/W)
+FDC_DOR                .equ    0x38    ; Digital Output Register (W/O)
+FDC_TC         .equ    0x38    ; Pulse terminal count (R/O)
+
+; 8255 PPI ports
+PPI_BASE       .equ    0x60
+PPI_PORTA      .equ    PPI_BASE + 0    ; Port A
+PPI_PORTB      .equ    PPI_BASE + 1    ; Port B
+PPI_PORTC      .equ    PPI_BASE + 2    ; Port C
+PPI_CONTROL    .equ    PPI_BASE + 3    ; PPI Control Port
+
+; 16550 UART
+UART0_BASE     .equ    0x68
+UART0_RBR      .equ    UART0_BASE + 0  ; DLAB=0: Receiver buffer register (R/O)
+UART0_THR      .equ    UART0_BASE + 0  ; DLAB=0: Transmitter holding reg (W/O)
+UART0_IER      .equ    UART0_BASE + 1  ; DLAB=0: Interrupt enable register
+UART0_IIR      .equ    UART0_BASE + 2  ; Interrupt identification reg (R/0)
+UART0_FCR      .equ    UART0_BASE + 2  ; FIFO control register (W/O)
+UART0_LCR      .equ    UART0_BASE + 3  ; Line control register
+UART0_MCR      .equ    UART0_BASE + 4  ; Modem control register
+UART0_LSR      .equ    UART0_BASE + 5  ; Line status register
+UART0_MSR      .equ    UART0_BASE + 6  ; Modem status register
+UART0_SCR      .equ    UART0_BASE + 7  ; Scratch register 
+UART0_DLL      .equ    UART0_BASE + 0  ; DLAB=1: Divisor latch - low byte
+UART0_DLH      .equ    UART0_BASE + 1  ; DLAB=1: Divisor latch - high byte
+
+; DS1302 RTC
+N8VEM_RTC      .equ    0x70    ; RTC / bit banging (R/W)
+
+; 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)
diff --git a/Kernel/platform-zeta-v2/main.c b/Kernel/platform-zeta-v2/main.c
new file mode 100644 (file)
index 0000000..723a4a3
--- /dev/null
@@ -0,0 +1,33 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+#include "config.h"
+
+extern unsigned char irqvector;
+
+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;
+}
+
+void platform_interrupt(void)
+{
+       switch(irqvector) {
+               case 1:
+#ifdef CONFIG_PPP
+                       tty_poll_ppp()
+#endif
+                       timer_interrupt(); 
+                       return;
+               case 2:
+                       tty_interrupt();
+                       return;
+               default:
+                       return;
+       }
+}
diff --git a/Kernel/platform-zeta-v2/monitor.s b/Kernel/platform-zeta-v2/monitor.s
new file mode 100644 (file)
index 0000000..83af254
--- /dev/null
@@ -0,0 +1,37 @@
+; 2015-01-17 William R Sowerbutts
+
+                .module monitor
+                .include "kernel.def"
+                .globl _trap_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
+_trap_monitor:
+                di
+                call map_kernel
+                jp monitor_entry
+
+
+; -----------------------------------------------------------------------------
+.else ; MICRO MONITOR ---------------------------------------------------------
+                .globl outchar
+                .globl outnewline
+                .globl outhl
+
+                .area _COMMONMEM
+_trap_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-zeta-v2/target.mk b/Kernel/platform-zeta-v2/target.mk
new file mode 100644 (file)
index 0000000..3bffcde
--- /dev/null
@@ -0,0 +1 @@
+export CPU = z80
diff --git a/Kernel/platform-zeta-v2/tricks.s b/Kernel/platform-zeta-v2/tricks.s
new file mode 100644 (file)
index 0000000..413f9ea
--- /dev/null
@@ -0,0 +1,239 @@
+; 2013-12-21 William R Sowerbutts
+
+        .module tricks
+
+        .globl _ptab_alloc
+        .globl _newproc
+        .globl _chksigs
+        .globl _getproc
+        .globl _trap_monitor
+        .globl trap_illegal
+        .globl _inint
+        .globl _switchout
+        .globl _switchin
+        .globl _doexec
+        .globl _dofork
+        .globl _runticks
+        .globl unix_syscall_entry
+        .globl interrupt_handler
+       .globl map_kernel
+       .globl _ramtop
+
+        ; 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
+
+; 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().
+;
+; FIXME: make sure we optimise the switch to self case higher up the stack!
+; 
+; This function can have no arguments or auto variables.
+_switchout:
+        di
+        call _chksigs
+        ; 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
+
+        ; set inint to false
+        xor a
+        ld (_inint), a
+
+        ; find another process to run (may select this one again)
+        call _getproc
+
+        push hl
+        call _switchin
+
+        ; we should never get here
+        call _trap_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, (_inint)
+        or a
+        ret z ; 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 _trap_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
+       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-zeta-v2/zeta-v2.h b/Kernel/platform-zeta-v2/zeta-v2.h
new file mode 100644 (file)
index 0000000..dd71914
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef __ZETA_V2_DOT_H__
+#define __ZETA_V2_DOT_H__
+
+#include "config.h"
+
+#define UART0_BASE 0x68
+__sfr __at (UART0_BASE + 0) UART0_RBR; /* receive buffer register, R/O */
+__sfr __at (UART0_BASE + 0) UART0_THR; /* xmit holding register, W/O */
+__sfr __at (UART0_BASE + 1) UART0_IER;  /* interrupt enable register */
+__sfr __at (UART0_BASE + 2) UART0_IIR; /* interrupt ident. register, R/O */
+__sfr __at (UART0_BASE + 2) UART0_FCR; /* FIFO control register, W/O */
+__sfr __at (UART0_BASE + 3) UART0_LCR; /* Line control register */
+__sfr __at (UART0_BASE + 4) UART0_MCR; /* Modem control register */
+__sfr __at (UART0_BASE + 5) UART0_LSR; /* Line status register */
+__sfr __at (UART0_BASE + 6) UART0_MSR; /* Modem status register */
+__sfr __at (UART0_BASE + 7) UART0_SCR; /* Scratch register */
+__sfr __at (UART0_BASE + 0) UART0_DLL; /* Divisor latch - low byte */
+__sfr __at (UART0_BASE + 1) UART0_DLH; /* Divisor latch - high byte */
+
+#endif
diff --git a/Kernel/platform-zeta-v2/zeta-v2.s b/Kernel/platform-zeta-v2/zeta-v2.s
new file mode 100644 (file)
index 0000000..3cfa6ff
--- /dev/null
@@ -0,0 +1,335 @@
+; 2014-02-19 Sergey Kiselev
+; Zeta SBC V2 hardware specific code
+
+        .module zeta-v2
+
+        ; exported symbols
+        .globl init_early
+        .globl init_hardware
+       .globl _program_vectors
+       .globl map_kernel
+       .globl map_process
+       .globl map_process_always
+       .globl map_save
+       .globl map_restore
+       .globl _kernel_flag
+       .globl _irqvector
+        .globl platform_interrupt_all
+       .globl map_table
+       .globl _kernel_pages
+
+        ; imported symbols
+        .globl _ramsize
+        .globl _procmem
+        .globl outhl
+        .globl outnewline
+       .globl interrupt_handler
+       .globl unix_syscall_entry
+       .globl nmi_handler
+       .globl null_handler
+
+       ; 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)
+
+;=========================================================================
+; Initialization code
+;=========================================================================
+        .area _DISCARD
+
+init_early:
+       ret
+
+init_hardware:
+        ld hl, #RAM_KB                 ; set system RAM size
+        ld (_ramsize), hl
+        ld hl,#(RAM_KB-64)             ; 64K for kernel
+        ld (_procmem), hl
+
+       ; initialize UART0
+       ld a,#0x80                      ; LCR = DLAB ON
+       out (UART0_LCR),a               ; set LCR
+       ld a,#CONSOLE_DIVISOR_LOW       ; baud rate divisor - low byte
+       out (UART0_DLL),a               ; set low byte of divisor
+       ld a,#CONSOLE_DIVISOR_HIGH      ; baud rate divisor - high byte
+       out (UART0_DLH),a               ; set high byte of divisor
+       ld a,#3                         ; value for LCR and MCR
+       out (UART0_LCR),a               ; 8 bit data, 1 stop, no parity
+       out (UART0_MCR),a               ; DTR ON, RTS ON
+       ld a,#6                         ; disable and reset FIFOs
+       out (UART0_FCR),a
+       ld a,#1                         ; enable receive data available
+       out (UART0_IER),a               ; interrupt
+       ; initialize CTC
+       ld a,#0x47                      ; 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
+       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
+
+       ret
+
+;=========================================================================
+; 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
+
+_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
+
+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
+       ; Zeta SBC V2 uses IM 2 interrupts, so nothing should hit this vector
+       ; use null_handler just in case something causes it anyway
+       ld a,#0xC3                      ; JP instruction
+       ld (0x0038),a
+       ld hl,#null_handler
+       ld (0x0039),hl
+
+       ; set restart vector for UZI system calls
+       ld (0x0030),a                   ; rst 30h is unix function call vector
+       ld hl,#unix_syscall_entry
+       ld (0x0031),hl
+
+       ld (0x0000),a
+       ld hl,#null_handler             ; to Our Trap Handler
+       ld (0x0001),hl
+
+       ld (0x0066),a                   ; Set vector for NMI
+       ld hl,#nmi_handler
+       ld (0x0067),hl
+
+       jr map_kernel
+
+;=========================================================================
+; Memory management
+; - 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
+       call map_process_2
+       pop hl
+       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
+       call map_process_2
+       pop hl
+       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,#map_table                ; 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
+       call map_process_2
+       pop hl
+       ret
+
+;=========================================================================
+; map_save - save the current page mapping
+; Inputs: none
+; Outputs: none
+;=========================================================================
+map_save:
+       push hl
+       ld hl,(map_table)
+       ld (map_savearea),hl
+       ld hl,(map_table+2)
+       ld (map_savearea+2),hl
+       pop hl
+       ret
+
+map_table:
+       .db     32,33,34,35
+_kernel_pages:
+       .db     32,33,34,35
+map_savearea:
+       .db     32,33,34,35
+
+; has to live in common
+_kernel_flag:
+       .db     1
+
+;=========================================================================
+; Basic console I/O
+;=========================================================================
+
+;=========================================================================
+; outchar - Wait for UART TX idle, then print the char in A
+; Inputs: A - character to print
+; Outputs: none
+;=========================================================================
+outchar:
+       push af
+       ; wait for transmitter to be idle
+ocloop:
+       in a,(UART0_LSR)                ; read Line Status Register
+       and #0x20                       ; get THRE bit
+       jr z,ocloop
+       ; now output the char to serial port
+       pop af
+       out (UART0_THR),a
+       ret
+
+;=========================================================================
+; inchar - Wait for character on UART, return in A
+; Inputs: none
+; Outputs: A - received character, F destroyed
+;=========================================================================
+inchar:
+       in a,(UART0_LSR)                ; read Line Status Register
+       and #0x01                       ; test if data is in receive buffer
+       jp z,inchar                     ; no data, wait
+       in a,(UART0_RBR)                ; read the character from the UART
+       ret