platform-sbcv2: N8VEM Mark 2
authorAlan Cox <alan@linux.intel.com>
Sat, 25 Aug 2018 14:21:53 +0000 (15:21 +0100)
committerAlan Cox <alan@linux.intel.com>
Sat, 25 Aug 2018 14:21:53 +0000 (15:21 +0100)
A nice simple tickless platform to use as a reference.

Supports the PPIDE and PropIOv2. Currently only works with PropIOv2 present
until I fix a bit of probing logic.

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

diff --git a/Kernel/platform-sbcv2/Makefile b/Kernel/platform-sbcv2/Makefile
new file mode 100644 (file)
index 0000000..67777c7
--- /dev/null
@@ -0,0 +1,52 @@
+CROSS_CCOPTS += -I../dev/
+
+
+CSRCS = devtty.c ppide.c
+CSRCS += devices.c main.c
+
+DISCSRCS = discard.c
+
+ASRCS = sbcv2.s crt0.s ds1302-n8vem.s
+ASRCS += tricks.s commonmem.s
+
+DISCARD_DSRCS = ../dev/devide_discard.c
+DSRCS = ../dev/blkdev.c ../dev/devide.c ../dev/mbr.c
+DSRCS += ../dev/propio2.c ../dev/ds1302.c
+
+NSRCS = 
+
+COBJS = $(CSRCS:.c=.rel)
+AOBJS = $(ASRCS:.s=.rel)
+NOBJS = $(patsubst ../dev/net/%.c,%.rel, $(NSRCS))
+DISCOBJS = $(DISCSRCS:.c=.rel)
+DISCARD_DOBJS = $(patsubst ../dev/%.c,%.rel, $(DISCARD_DSRCS))
+DOBJS = $(patsubst ../dev/%.c,%.rel, $(DSRCS))
+
+OBJS  = $(COBJS) $(AOBJS) $(NOBJS) $(DISCOBJS) $(DOBJS) $(DISCARD_DOBJS)
+
+JUNK =  *.lst *.asm *.sym *.rst *.lst
+
+all:   $(OBJS)
+
+$(COBJS): %.rel: %.c
+       $(CROSS_CC) $(CROSS_CCOPTS) -c $<
+
+$(DISCOBJS): %.rel: %.c
+       $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $<
+
+$(DOBJS): %.rel: ../dev/%.c
+       $(CROSS_CC) $(CROSS_CCOPTS) -c $<
+
+$(DISCARD_DOBJS): %.rel: ../dev/%.c
+       $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $<
+
+$(NOBJS): %.rel: ../dev/net/%.c
+       $(CROSS_CC) $(CROSS_CCOPTS) -c $<
+
+$(AOBJS): %.rel: %.s
+       $(CROSS_AS) $(ASOPTS) $<
+
+clean:
+       rm -f $(OBJS) $(JUNK)  core *~
+
+image:
diff --git a/Kernel/platform-sbcv2/README b/Kernel/platform-sbcv2/README
new file mode 100644 (file)
index 0000000..795a256
--- /dev/null
@@ -0,0 +1,116 @@
+N8VEM SBCv2
+
+This port is intended as a reference port for simple systems.
+
+The N8VEM mark 2 is a single board hobby Z80 based computer. It has 512K of
+RAM and 512K or 1MB of Flash. The upper 32K of the address space is fixed as
+the top 32K of the 512K RAM. The lower 32K can be switched to any 32K bank
+of the ROM or RAM.
+
+Onboard I/O is limited to a 16550A UART providing a serial port and some
+modem control lines, and an 8255 PIO that is normally used to connect a
+PPIDE adapter. A bitbanged DS1302 real time clock is also provided but no timer
+interrupt.
+
+The only interrupt available is either from the optional ECB backplane and add
+in cards, or from the 16550A, but not both.
+
+The onboard firmware (ROMWBW) provides a monitor, BIOS and also CP/M or
+ZSystem. For simplicity Fuzix is currently booted from the OS.
+
+Supported Hardware
+
+N8VEM SBC v2
+Optional PPIDE adapter for IDE disks or CF cards
+Optional ECB PropIOv2 for keyboard/VGA console/SD card interface
+
+(currently the PropIOv2 is required - this will get fixed soon)
+
+
+Implementation
+
+This platform uses the standard banked memory model. One lower 32K bank is
+assigned to the kernel (Bank 14). The upper memory is fixed at bank 15, and
+bank 0-13 are available to applications, one per bank.
+
+During execution the current per process data and stack (udata) live in the
+upper bank near the top of memory. When a process is switched out they are saved
+into the top of the low 32K space.
+
+Memory Layout
+
+Kernel
+0000-00FF      Interrupt vectors
+0100-7FFF      Kernel code
+
+User
+0000-00FF      Interrupt vectors
+0100-7DFF      User process    (currently 7CFF needs fixing)
+7E00-7FFF      Copy of task kernel stack and variables
+
+8000-????      Kernel
+????-EFFF      Disk buffers
+F000-FDFF      Kernel common area and stacks
+FE00-FFFF      Reserved for firmware
+
+
+Notes
+
+There are a variety of clever things that could be done to make this platform
+more useful but at a cost. Firstly there is a lot of space free in the top 32K
+so 8000-AFFF could probably be made user space and copied in and out each task
+switch. As a single user machine doesn't switch much the cost isn't too high
+and more becomes possible.
+
+As this is meant to be a porting reference nothing clever is done. There is
+no fast bank to bank copier, and no clever user to kernel copier. These can be
+taken from other ports if wanted.
+
+Oddities
+
+The SBCv2 by default has no timer interrupt. This means that time based
+pre-emption cannot be performed, and the terminal will only be responsive when
+the system is waiting for user activity (except the UART if it has interrupts
+enabled).
+
+The code supports connecting a 10Hz clock source to a serial control line to
+provide a real clock, and also routing the ECB interrupt using the same hack.
+
+Some ECB cards can provide a timer interrupt. These are not presently supported.
+
+Working With The Simulator
+
+The way I work is as follows
+
+Install cpmtools.
+Add the following to the /usr/share/cpmtools/diskdefs
+
+diskdef romwbwhd
+  seclen 128
+  tracks 1040
+  sectrk 64
+  blocksize 4096
+  maxdir 512
+  skew  0
+  boottrk 16
+  os 2.2
+end
+
+You can then create an sdcard image with
+
+dd if=/dev/zero of=sdcard.img bs=512 couunt=16384
+
+Run the simulator and in CP/M or ZSystem and (if G is the SD card drive letter)
+
+n8vem2 -p
+
+G:ERA *.*
+
+then exit the simulator
+
+Once this is done you can copy Fuzix images to it using
+
+cpmcp -T raw -f romwbwhd sdcard.img fuzix.bin 0:fuzix.com
+
+Then go back in the simulator and run FUZIX as a CP/M binary
+
diff --git a/Kernel/platform-sbcv2/commonmem.s b/Kernel/platform-sbcv2/commonmem.s
new file mode 100644 (file)
index 0000000..bafd590
--- /dev/null
@@ -0,0 +1,10 @@
+;
+;      We have no real common on the TRS80so just tuck it up at the top of
+;      memory leaving room for the keyboard and video (3K)
+;
+        .module commonmem
+
+        .area _COMMONMEM
+
+       .include "../cpu-z80/std-commonmem.s"
+
diff --git a/Kernel/platform-sbcv2/config.h b/Kernel/platform-sbcv2/config.h
new file mode 100644 (file)
index 0000000..4bdc894
--- /dev/null
@@ -0,0 +1,69 @@
+/* We have an RTC - well maybe (its optional) */
+#define CONFIG_RTC
+#define CONFIG_RTC_FULL
+#define CONFIG_NO_CLOCK
+/* 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
+/* Banked memory set up */
+#define CONFIG_BANK_FIXED
+#define MAX_MAPS       15              /* 512 KByte... minus the high one */
+#define MAP_SIZE       0x8000
+
+/* Set these two for networking - no point right now */
+//#define CONFIG_NET
+//#define CONFIG_NET_NATIVE
+
+/* PPIDE is present */
+#define CONFIG_IDE
+#define CONFIG_PPIDE
+
+#define CONFIG_DYNAMIC_BUFPOOL
+#define CONFIG_DYNAMIC_SWAP
+#define CONFIG_LARGE_IO_DIRECT
+
+#define MAX_BLKDEV     4
+
+#define CONFIG_BANKS   2       /* 2 x 32K */
+
+/* For now we don't support resizing */
+#define VT_WIDTH       80
+#define VT_HEIGHT      25
+#define VT_RIGHT       79
+#define VT_BOTTOM      24
+
+#define TICKSPERSEC 10     /* Ticks per second */
+#define PROGBASE    0x0000  /* Base of user  */
+#define PROGLOAD    0x0100  /* Load and run here */
+#define PROGTOP     0x7D00  /* Top of program, base of U_DATA stash */
+#define PROC_SIZE   32             /* Memory needed per process */
+
+#define SWAPDEV     (swap_dev)
+#define SWAP_SIZE   0x40       /* 32K in blocks */
+#define SWAPBASE    0x0000     /* We swap the lot in one, include the */
+#define SWAPTOP            0x8000      /* vectors so its a round number of sectors */
+
+#define MAX_SWAPS      16      /* Should be plenty */
+
+#define swap_map(x)    ((uint8_t *)(x))
+
+#define BOOT_TTY (512 + 1)      /* Set this to default device for stdio, stderr */
+                          /* In this case, the default is the first TTY device */
+
+/* We need a tidier way to do this from the loader */
+#define CMDLINE        NULL      /* Location of root dev name */
+
+/* Device parameters */
+#define NUM_DEV_TTY 2
+#define TTYDEV   BOOT_TTY /* Device used by kernel for messages, panics */
+#define NBUFS    5        /* Number of block buffers */
+#define NMOUNTS         4        /* Number of mounts at a time */
+
+extern unsigned int swap_dev;
diff --git a/Kernel/platform-sbcv2/crt0.s b/Kernel/platform-sbcv2/crt0.s
new file mode 100644 (file)
index 0000000..038c336
--- /dev/null
@@ -0,0 +1,87 @@
+               ; Ordering of segments for the linker.
+               .area _CODE
+               .area _CODE2
+               .area _HOME
+               .area _CONST
+               .area _INITIALIZED
+               .area _DATA
+               .area _BSEG
+               .area _BSS
+               .area _HEAP
+               .area _GSINIT
+               .area _GSFINAL
+               .area _BUFFERS
+               .area _DISCARD
+               .area _COMMONMEM
+               ; note that areas below here may be overwritten by the heap at runtime, so
+               ; put initialisation stuff in here
+               .area _INITIALIZER
+
+               ; imported symbols
+               .globl _fuzix_main
+               .globl init_early
+               .globl init_hardware
+               .globl s__DATA
+               .globl l__DATA
+               .globl s__DISCARD
+               .globl l__DISCARD
+               .globl s__BUFFERS
+               .globl l__BUFFERS
+               .globl s__COMMONMEM
+               .globl l__COMMONMEM
+               .globl s__INITIALIZER
+               .globl kstack_top
+               .globl map_kernel
+
+               ; startup code
+               .area _CODE
+
+               ; Load at 0x0100
+               ; We are executed as a CP/M task so live in bank 14/15
+               ; with CP/M under us and the HBIOS proxy at FE00
+start:
+               ld bc,#0x0100
+               ld e,#'*'
+               rst 8
+               di
+               ld sp, #kstack_top
+               ; move the common memory where it belongs    
+               ld hl, #s__DATA
+               ld de, #s__COMMONMEM
+               ld bc, #l__COMMONMEM
+               ldir
+               ; then the discard
+               ; Discard can just be linked in but is next to the buffers
+               ld de, #s__DISCARD
+               ld bc, #l__DISCARD
+               ldir
+               ld bc,#0x0100
+               ld e,#':'
+               rst 8
+               ; then zero the data area
+               ld hl, #s__DATA
+               ld de, #s__DATA + 1
+               ld bc, #l__DATA - 1
+               ld (hl), #0
+               ldir
+;              Zero buffers area
+               ld hl, #s__BUFFERS
+               ld de, #s__BUFFERS + 1
+               ld bc, #l__BUFFERS - 1
+               ld (hl), #0
+               ldir
+               ld bc,#0x0100
+               ld e,#'X'
+               rst 8
+               call init_early
+               ld bc,#0x0100
+               ld e,#'Y'
+               rst 8
+               call init_hardware
+               ld bc,#0x0100
+               ld e,#'Z'
+               rst 8
+               call _fuzix_main
+               di
+stop:          halt
+               jr stop
diff --git a/Kernel/platform-sbcv2/devices.c b/Kernel/platform-sbcv2/devices.c
new file mode 100644 (file)
index 0000000..a854830
--- /dev/null
@@ -0,0 +1,34 @@
+#include <kernel.h>
+#include <tty.h>
+#include <version.h>
+#include <kdata.h>
+#include <devsys.h>
+#include <devtty.h>
+#include <blkdev.h>
+#include <devide.h>
+#include <printf.h>
+
+struct devsw dev_tab[] =  /* The device driver switch table */
+{
+  /* 0: /dev/hd                Hard disc block devices */
+  {  blkdev_open, no_close,     blkdev_read,   blkdev_write,   blkdev_ioctl  },
+  /* 1: /dev/fd                Floppy disc block devices */
+  {  nxio_open,   no_close,     no_rdwr,       no_rdwr,        no_ioctl  },
+  /* 2: /dev/tty       TTY devices */
+  {  tty_open,    tty_close,    tty_read,      tty_write,      tty_ioctl },
+  /* 3: /dev/lpr       Printer devices */
+  {  nxio_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 },
+  /* Pack to 7 with nxio if adding private devices and start at 8 */
+};
+
+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) - 1)
+       return false;
+    else
+        return true;
+}
diff --git a/Kernel/platform-sbcv2/devtty.c b/Kernel/platform-sbcv2/devtty.c
new file mode 100644 (file)
index 0000000..6ea0ef9
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ *     We have a 16x50 UART at 0x68 and maybe a PropIO2 at A8
+ */
+
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <tty.h>
+#include <devtty.h>
+#include <propio2.h>
+
+__sfr __at 0x68 uart_tx;
+__sfr __at 0x68 uart_rx;
+__sfr __at 0x6D uart_lsr;
+
+static char tbuf1[TTYSIZ];
+static char tbuf2[TTYSIZ];
+
+/* Updated early in boot to 0,2,1 if PropIO present */
+uint8_t ttymap[NUM_DEV_TTY + 1] = {
+       0, 1, 2
+};
+
+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},
+};
+
+/* Write to system console */
+void kputchar(char c)
+{
+       /* Need to make console dynamic FIXME */
+       if (c == '\n')
+               tty_putc(1, '\r');
+       tty_putc(1, c);
+}
+
+uint8_t tty_writeready(uint8_t minor)
+{
+       minor;
+       /* FIXME: flow control */
+       if (ttymap[minor] == 1)
+               return uart_lsr & 0x20 ? TTY_READY_NOW : TTY_READY_SOON;
+       return prop_tty_writeready();
+}
+
+void tty_putc(uint8_t minor, unsigned char c)
+{
+       minor;
+       if (ttymap[minor] == 1)
+               uart_tx = c;
+       else
+               prop_tty_write(c);
+}
+
+void tty_setup(uint8_t minor)
+{
+       minor;
+}
+
+void tty_sleeping(uint8_t minor)
+{
+       minor;
+}
+
+int tty_carrier(uint8_t minor)
+{
+        minor;
+       return 1;
+}
+
+void tty_data_consumed(uint8_t minor)
+{
+}
+
+void tty_poll(void)
+{      
+       /* Should be IRQ driven for this */
+       if (uart_lsr & 0x01)
+               tty_inproc(ttymap[1], uart_rx);
+       prop_tty_poll(ttymap[2]);
+}
diff --git a/Kernel/platform-sbcv2/devtty.h b/Kernel/platform-sbcv2/devtty.h
new file mode 100644 (file)
index 0000000..f4803a1
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _DEVTTY_H
+#define _DEVTTY_H
+
+extern void tty_poll(void);
+
+#endif
diff --git a/Kernel/platform-sbcv2/discard.c b/Kernel/platform-sbcv2/discard.c
new file mode 100644 (file)
index 0000000..784017a
--- /dev/null
@@ -0,0 +1,52 @@
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+#include <blkdev.h>
+#include <devide.h>
+#include <propio2.h>
+
+extern int strcmp(const char *, const char *);
+
+void map_init(void)
+{
+}
+
+/* Kernel in bank 0, user in banks 1-14, high 32K is bank 15 */
+void pagemap_init(void)
+{
+       uint8_t i;
+       for (i = 1; i < 15; i++)
+               pagemap_add(i);
+}
+
+uint8_t platform_param(char *p)
+{
+       if (strcmp(p, "compumuse") == 0) {
+               return 1;
+       }
+       return 0;
+}
+
+void platform_swap_found(uint8_t letter, uint8_t m)
+{
+  blkdev_t *blk = blk_op.blkdev;
+  uint16_t n;
+  if (swap_dev != 0xFFFF)
+    return;
+  letter -= 'a';
+  kputs("(swap) ");
+  swap_dev = letter << 4 | m;
+  n = blk->lba_count[m - 1] / SWAP_SIZE;
+  if (n > MAX_SWAPS)
+    n = MAX_SWAPS;
+  while(n)
+    swapmap_add(n--);
+}
+
+void device_init(void)
+{
+       devide_init();
+       prop_sd_probe();
+}
diff --git a/Kernel/platform-sbcv2/ds1302-n8vem.s b/Kernel/platform-sbcv2/ds1302-n8vem.s
new file mode 100644 (file)
index 0000000..87a95bc
--- /dev/null
@@ -0,0 +1,79 @@
+; 2015-02-19 Sergey Kiselev
+; 2014-12-31 William R Sowerbutts
+; N8VEM SBC / Zeta SBC DS1302 real time clock interface code
+;
+;      FIXME: belongs in dev/
+;
+
+        .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-sbcv2/fuzix.lnk b/Kernel/platform-sbcv2/fuzix.lnk
new file mode 100644 (file)
index 0000000..5a3530c
--- /dev/null
@@ -0,0 +1,45 @@
+-mwxuy
+-i fuzix.ihx
+-b _CODE=0x0100
+-b _COMMONMEM=0xF000
+-b _INITIALIZER=0xFD00
+-l z80
+platform-sbcv2/crt0.rel
+platform-sbcv2/commonmem.rel
+platform-sbcv2/sbcv2.rel
+start.rel
+version.rel
+lowlevel-z80.rel
+usermem.rel
+usermem_std-z80.rel
+platform-sbcv2/tricks.rel
+platform-sbcv2/main.rel
+platform-sbcv2/discard.rel
+timer.rel
+kdata.rel
+platform-sbcv2/devices.rel
+devio.rel
+filesys.rel
+process.rel
+inode.rel
+syscall_exec16.rel
+syscall_fs.rel
+syscall_fs2.rel
+syscall_fs3.rel
+syscall_proc.rel
+syscall_other.rel
+tty.rel
+mm.rel
+swap.rel
+bankfixed.rel
+devsys.rel
+platform-sbcv2/devtty.rel
+platform-sbcv2/blkdev.rel
+platform-sbcv2/mbr.rel
+platform-sbcv2/devide.rel
+platform-sbcv2/devide_discard.rel
+platform-sbcv2/propio2.rel
+platform-sbcv2/ppide.rel
+platform-sbcv2/ds1302.rel
+platform-sbcv2/ds1302-n8vem.rel
+-e
diff --git a/Kernel/platform-sbcv2/kernel.def b/Kernel/platform-sbcv2/kernel.def
new file mode 100644 (file)
index 0000000..ad02967
--- /dev/null
@@ -0,0 +1,17 @@
+; 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.
+
+U_DATA_STASH               .equ 0x7D00       ; 7D00-7FFF
+
+PROGBASE                   .equ 0x0000
+PROGLOAD                   .equ 0x0100
+
+Z80_TYPE                   .equ 1            ; NMOS (IRQ bugs) Z80
+
+Z80_MMU_HOOKS              .equ 0
+
+CONFIG_SWAP                .equ 1
+
+NBUFS                      .equ 5
diff --git a/Kernel/platform-sbcv2/main.c b/Kernel/platform-sbcv2/main.c
new file mode 100644 (file)
index 0000000..2cae50c
--- /dev/null
@@ -0,0 +1,139 @@
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+#include <rtc.h>
+#include <ds1302.h>
+
+uint16_t ramtop = PROGTOP;
+uint16_t swap_dev = 0xFFFF;
+
+/* On idle we spin checking for the terminals. Gives us more responsiveness
+   for the polled ports */
+void platform_idle(void)
+{
+       irqflags_t irq = di();
+       sync_clock();
+       tty_poll();
+       irqrestore(irq);
+}
+
+void platform_interrupt(void)
+{
+       /* TODO */
+       tty_poll();
+}
+
+struct blkbuf *bufpool_end = bufpool + NBUFS;
+
+/*
+ *     We pack discard into the memory image is if it were just normal
+ *     code but place it at the end after the buffers. When we finish up
+ *     booting we turn everything from the buffer pool to common into
+ *     buffers.
+ */
+void platform_discard(void)
+{
+       uint16_t discard_size = (uint16_t)udata - (uint16_t)bufpool_end;
+       bufptr bp = bufpool_end;
+
+       discard_size /= sizeof(struct blkbuf);
+
+       kprintf("%d buffers added\n", discard_size);
+
+       bufpool_end += discard_size;
+
+       memset( bp, 0, discard_size * sizeof(struct blkbuf) );
+
+       for( bp = bufpool + NBUFS; bp < bufpool_end; ++bp ){
+               bp->bf_dev = NO_DEVICE;
+               bp->bf_busy = BF_FREE;
+       }
+}
+
+static uint8_t rtc_buf[8];
+
+int platform_rtc_read(void)
+{
+       uint16_t len = sizeof(struct cmos_rtc);
+       uint16_t y;
+       struct cmos_rtc cmos;
+       uint8_t *p = cmos.data.bytes;
+
+       if (udata.u_count < len)
+               len = udata.u_count;
+
+       ds1302_read_clock(rtc_buf, 7);
+
+       y = rtc_buf[6];
+       if (y > 0x70)
+               y = 0x1900 | y;
+       else
+               y = 0x2000 | y;
+       *p++ = y >> 8;
+       *p++ = y;
+       rtc_buf[4]--;           /* 0 based */
+       if ((rtc_buf[4] & 0x0F) > 9)    /* Overflow case */
+               rtc_buf[4] -= 0x06;
+       *p++ = rtc_buf[4];      /* Month */
+       *p++ = rtc_buf[3];      /* Day of month */
+       if ((rtc_buf[2] & 0x90) == 0x90) {      /* 12hr mode, PM */
+               /* Add 12 BCD */
+               rtc_buf[2] += 0x12;
+               if ((rtc_buf[2] & 0x0F) > 9)    /* Overflow case */
+                       rtc_buf[2] += 0x06;
+       }
+       *p++ = rtc_buf[2];      /* Hour */
+       *p++ = rtc_buf[1];      /* Minute */
+       *p = rtc_buf[0];        /* Second */
+       cmos.type = CMOS_RTC_BCD;
+       if (uput(&cmos, udata.u_base, len) == -1)
+               return -1;
+       return len;
+}
+
+int platform_rtc_write(void)
+{
+       udata.u_error = -EOPNOTSUPP;
+       return -1;
+}
+
+static uint8_t newticks = 0xFF;
+static uint8_t oldticks;
+
+static uint8_t re_enter;
+
+void sync_clock_read(void)
+{
+       uint8_t s;
+       oldticks = newticks;
+       ds1302_read_clock(&s, 1);
+       s = (s & 0x0F) + (((s & 0xF0) >> 4) * 10);
+       newticks = s;
+}
+
+void sync_clock(void)
+{
+       irqflags_t irq = di();
+       int16_t tmp;
+       if (!re_enter++) {
+               sync_clock_read();
+               if (oldticks != 0xFF) {
+                       tmp = newticks - oldticks;
+                       if (tmp < 0)
+                               tmp += 60;
+                       tmp *= 10;
+                       while(tmp--) {
+                               timer_interrupt();
+                       }
+                       platform_interrupt();
+               }
+               re_enter--;
+       } 
+       irqrestore(irq);
+}
+
+void update_sync_clock(void)
+{
+}
diff --git a/Kernel/platform-sbcv2/platform_ide.h b/Kernel/platform-sbcv2/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-sbcv2/ppide.c b/Kernel/platform-sbcv2/ppide.c
new file mode 100644 (file)
index 0000000..1d89cb7
--- /dev/null
@@ -0,0 +1,123 @@
+/* 2015-04-24 WRS: devide glue functions for PPIDE */
+/* FIXME: move to dev */
+
+#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_port_c = regaddr | PPIDE_RD_LINE; /* begin /RD pulse */
+    r = ppi_port_a;
+    ppi_port_c = regaddr;       /* 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_port_c = regaddr | PPIDE_WR_LINE;
+    /* FIXME: check timing */
+    ppi_port_c = regaddr;
+    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-sbcv2/sbcv2.s b/Kernel/platform-sbcv2/sbcv2.s
new file mode 100644 (file)
index 0000000..925713b
--- /dev/null
@@ -0,0 +1,246 @@
+;
+;          SBC v2 support
+;
+
+            .module sbcv2
+
+            ; exported symbols
+            .globl init_early
+            .globl init_hardware
+            .globl interrupt_handler
+            .globl _program_vectors
+           .globl map_kernel
+           .globl map_process
+           .globl map_process_a
+           .globl map_process_always
+           .globl map_save
+           .globl map_restore
+           .globl map_for_swap
+           .globl platform_interrupt_all
+           .globl _kernel_flag
+
+            ; exported debugging tools
+            .globl _platform_monitor
+            .globl _platform_reboot
+            .globl outchar
+
+            ; imported symbols
+            .globl _ramsize
+            .globl _procmem
+            .globl istack_top
+            .globl istack_switched_sp
+            .globl unix_syscall_entry
+            .globl trap_illegal
+            .globl outcharhex
+           .globl null_handler
+
+           .globl s__COMMONMEM
+           .globl l__COMMONMEM
+
+            .include "kernel.def"
+            .include "../kernel.def"
+
+;
+; Buffers (we use asm to set this up as we need them in a special segment
+; so we can recover the discard memory into the buffer pool
+;
+
+           .globl _bufpool
+           .area _BUFFERS
+
+_bufpool:
+           .ds BUFSIZE * NBUFS
+;
+; COMMON MEMORY BANK (kept even when we task switch)
+;
+            .area _COMMONMEM
+
+platform_interrupt_all:
+           ret
+
+; FIXME: map ROM and jump into it
+_platform_monitor:
+_platform_reboot:
+           di
+           xor a
+           out (0x7C),a
+           rst 0
+
+; -----------------------------------------------------------------------------
+; KERNEL MEMORY BANK (may be below 0x8000, only accessible when the kernel is
+; mapped)
+; -----------------------------------------------------------------------------
+           .area _CODE
+
+;
+;      We will address this one better when we do some ROMWBW integration
+;
+           .globl _ttymap
+init_early:
+           ; FIXME: code goes here to check for PropIO v2 nicely
+           ; Passes the minimal checking
+           ld hl,#0x0102
+           ld (_ttymap+1), hl          ; set tty map to 0,2,1 for prop
+           ret
+
+           .area _DISCARD
+
+init_hardware:
+           ld hl,#512
+            ld (_ramsize), hl
+           ld hl,#448
+            ld (_procmem), hl
+
+            ; set up interrupt vectors for the kernel (also sets up common memory in page 0x000F which is unused)
+            ld hl, #0
+            push hl
+            call _program_vectors
+            pop hl
+
+            im 1 ; set CPU interrupt mode
+
+            ret
+
+;------------------------------------------------------------------------------
+; COMMON MEMORY PROCEDURES FOLLOW
+
+            .area _COMMONMEM
+
+mapreg:    .db 0
+mapsave:   .db 0
+
+_kernel_flag:
+           .db 1       ; We start in kernel mode
+
+_program_vectors:
+            ; we are called, with interrupts disabled, by both newproc() and crt0
+           ; will exit with interrupts off
+            di ; just to be sure
+            pop de ; temporarily store return address
+            pop hl ; function argument -- base page number
+            push hl ; put stack back as it was
+            push de
+
+           call map_process
+
+            ; now install the interrupt vector at 0x0038
+            ld a, #0xC3 ; JP instruction
+            ld (0x0038), a
+            ld hl, #interrupt_handler
+            ld (0x0039), hl
+
+            ; set restart vector for FUZIX system calls
+            ld (0x0030), a   ;  (rst 30h is unix function call vector)
+            ld hl, #unix_syscall_entry
+            ld (0x0031), hl
+
+            ld (0x0000), a   
+            ld hl, #null_handler   ;   to Our Trap Handler
+            ld (0x0001), hl
+
+;
+;      Mapping set up for the SBCv2
+;
+;      The top 32K bank holds kernel code and pieces of common memory
+;      The lower 32K is switched between the various user banks.
+;
+;      We know the ROM mapping is already off
+;
+map_kernel:
+           push af
+           ; ROMWBW TPA is last but one bank (last bank is high space)
+           ; so for now we hardcode this. We should ask ROMWBW at boot
+           ld a,#14
+           ld (mapreg),a
+           out (0x78), a
+           pop af
+           ret
+map_process:
+           ld a, h
+           or l
+           jr z, map_kernel
+map_process_hl:
+           ld a, (hl)
+map_for_swap:
+map_process_a:                 ; used by bankfork
+           dec a               ; We bias by 1 because 0 is a valid user
+           ld (mapreg), a      ; bank
+           out (0x78), a
+           inc a               ; cheaper than push/pop
+            ret
+
+map_process_always:
+           push af
+           push hl
+           ld hl, #U_DATA__U_PAGE
+           call map_process_hl
+           pop hl
+           pop af
+           ret
+
+map_save:   push af
+           ld a, (mapreg)
+           ld (mapsave), a
+           pop af
+           ret
+
+map_restore:
+           push af
+           ld a, (mapsave)
+           ld (mapreg), a
+           out (0x78), a
+           pop af
+           ret
+           
+outchar:
+           push af
+twait:     in a,(0x6D)
+           bit 5,a
+           jr z, twait
+           pop af
+           out (0x68),a
+            ret
+
+;
+;      PropIO v2 block transfers
+;
+
+; FIXME: Move these somewhere better
+BLKPARAM_ADDR_OFFSET           .equ    0
+BLKPARAM_IS_USER_OFFSET                .equ    2
+BLKPARAM_SWAP_PAGE             .equ    3
+
+           .globl _platform_prop_sd_read
+           .globl _platform_prop_sd_write
+
+           .globl _blk_op
+
+_platform_prop_sd_read:
+           ld a,(_blk_op + BLKPARAM_IS_USER_OFFSET)
+           ld hl, (_blk_op + BLKPARAM_ADDR_OFFSET)
+           or a
+           jr z, do_read
+           dec a
+           ld a, (_blk_op + BLKPARAM_SWAP_PAGE)
+           jr nz, do_read_a
+           ld a, (U_DATA__U_PAGE)
+do_read_a:  call map_process_a
+do_read:   ld bc,#0xAB
+           inir
+           inir
+           jp map_kernel
+
+_platform_prop_sd_write:
+           ld a,(_blk_op + BLKPARAM_IS_USER_OFFSET)
+           ld hl, (_blk_op + BLKPARAM_ADDR_OFFSET)
+           or a
+           jr z, do_write
+           dec a
+           ld a, (_blk_op + BLKPARAM_SWAP_PAGE)
+           jr nz, do_write_a
+           ld a, (U_DATA__U_PAGE)
+do_write_a: call map_process_a
+do_write:   ld bc,#0xAB
+           otir
+           otir
+           jp map_kernel
diff --git a/Kernel/platform-sbcv2/target.mk b/Kernel/platform-sbcv2/target.mk
new file mode 100644 (file)
index 0000000..3bffcde
--- /dev/null
@@ -0,0 +1 @@
+export CPU = z80
diff --git a/Kernel/platform-sbcv2/tricks.s b/Kernel/platform-sbcv2/tricks.s
new file mode 100644 (file)
index 0000000..ee50c07
--- /dev/null
@@ -0,0 +1,5 @@
+
+       .include "../kernel.def"
+       .include "kernel.def"
+
+       .include "../lib/z80fixedbank.s"