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.
--- /dev/null
+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:
--- /dev/null
+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
+
--- /dev/null
+;
+; 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"
+
--- /dev/null
+/* 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;
--- /dev/null
+ ; 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
--- /dev/null
+#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;
+}
--- /dev/null
+/*
+ * 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]);
+}
--- /dev/null
+#ifndef _DEVTTY_H
+#define _DEVTTY_H
+
+extern void tty_poll(void);
+
+#endif
--- /dev/null
+#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();
+}
--- /dev/null
+; 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
+
--- /dev/null
+-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
--- /dev/null
+; 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
--- /dev/null
+#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)
+{
+}
--- /dev/null
+#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()
--- /dev/null
+/* 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;
+}
--- /dev/null
+;
+; 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
--- /dev/null
+export CPU = z80
--- /dev/null
+
+ .include "../kernel.def"
+ .include "kernel.def"
+
+ .include "../lib/z80fixedbank.s"