Kernel: Add N8VEM Mark 4 and DX-Designs P112 platforms
authorWill Sowerbutts <will@sowerbutts.com>
Sat, 27 Dec 2014 02:38:45 +0000 (02:38 +0000)
committerWill Sowerbutts <will@sowerbutts.com>
Sat, 27 Dec 2014 11:40:19 +0000 (11:40 +0000)
29 files changed:
Kernel/dev/devide.c [new file with mode: 0644]
Kernel/dev/devide.h [new file with mode: 0644]
Kernel/platform-n8vem-mark4/Makefile [new file with mode: 0644]
Kernel/platform-n8vem-mark4/README [new file with mode: 0644]
Kernel/platform-n8vem-mark4/commonmem.s [new file with mode: 0644]
Kernel/platform-n8vem-mark4/config.h [new file with mode: 0644]
Kernel/platform-n8vem-mark4/cpmload.s [new file with mode: 0644]
Kernel/platform-n8vem-mark4/crt0.s [new file with mode: 0644]
Kernel/platform-n8vem-mark4/devices.c [new file with mode: 0644]
Kernel/platform-n8vem-mark4/devtty.c [new file with mode: 0644]
Kernel/platform-n8vem-mark4/devtty.h [new file with mode: 0644]
Kernel/platform-n8vem-mark4/kernel.def [new file with mode: 0644]
Kernel/platform-n8vem-mark4/main.c [new file with mode: 0644]
Kernel/platform-n8vem-mark4/mark4.s [new file with mode: 0644]
Kernel/platform-n8vem-mark4/uzi.lnk [new file with mode: 0644]
Kernel/platform-n8vem-mark4/z180.s [new file with mode: 0644]
Kernel/platform-p112/Makefile [new file with mode: 0644]
Kernel/platform-p112/README [new file with mode: 0644]
Kernel/platform-p112/commonmem.s [new file with mode: 0644]
Kernel/platform-p112/config.h [new file with mode: 0644]
Kernel/platform-p112/crt0.s [new file with mode: 0644]
Kernel/platform-p112/devices.c [new file with mode: 0644]
Kernel/platform-p112/devtty.c [new file with mode: 0644]
Kernel/platform-p112/devtty.h [new file with mode: 0644]
Kernel/platform-p112/kernel.def [new file with mode: 0644]
Kernel/platform-p112/main.c [new file with mode: 0644]
Kernel/platform-p112/p112.s [new file with mode: 0644]
Kernel/platform-p112/uzi.lnk [new file with mode: 0644]
Kernel/platform-p112/z180.s [new file with mode: 0644]

diff --git a/Kernel/dev/devide.c b/Kernel/dev/devide.c
new file mode 100644 (file)
index 0000000..7dac82d
--- /dev/null
@@ -0,0 +1,373 @@
+/*-----------------------------------------------------------------------*/
+/* IDE interface driver                                                  */
+/* 2014-11-02 Will Sowerbutts (unreleased UZI-mark4)                     */
+/* 2014-12-22 WRS ported to Fuzix                                        */
+/* 2014-12-25 WRS updated to also support P112 GIDE                      */
+/*-----------------------------------------------------------------------*/
+
+/* Minor numbers
+
+   The kernel identifies our storage devices with an 8-bit minor number.
+
+   The top two bits of the minor identify the drive, allowing a maximum of four
+   drives, the current hardware supports only two but future controllers may
+   support more.
+   
+   The bottom six bits of the minor identify the slice number. Slice 0
+   addresses "the whole drive", with no translation. Due to limitations within
+   the kernel only the first 32MB can currently be accessed through slice 0.
+
+   Slice 0 is intended to be used primarily for writing a partition table to
+   the drive, although it can also be used to store a single Fuzix filesystem
+   on an unpartitioned disk.
+   
+   Slices 1+ are stored in a partition on the drive. The partition is stored in
+   a PC-style MBR partition table and must be a primary partition of type 0x5A.
+   Only the first suitable partition is found. Multiple filesystems are stored
+   in this partition by dividing it into 32MB slices.
+
+   To create the required device nodes, use:
+
+       mknod /dev/hda 60660 0
+       mknod /dev/hdb 60660 64
+       mknod /dev/hdc 60660 128
+       mknod /dev/hdd 60660 192
+
+       mknod /dev/hda1 60660 1
+       mknod /dev/hda2 60660 2
+       mknod /dev/hda3 60660 3
+       ...
+       mknod /dev/hda63 60660 63
+
+       mknod /dev/hdb1 60660 65
+       mknod /dev/hdb2 60660 66
+       mknod /dev/hdb3 60660 67
+       ...
+       mknod /dev/hdb63 60660 127
+
+       mknod /dev/hdc1 60660 129
+       mknod /dev/hdc2 60660 130
+       mknod /dev/hdc3 60660 131
+       ...
+       mknod /dev/hdc63 60660 191
+
+       mknod /dev/hdd1 60660 193
+       mknod /dev/hdd2 60660 194
+       mknod /dev/hdd3 60660 195
+       ...
+       mknod /dev/hdd63 60660 255
+*/
+
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <timer.h>
+#include "devide.h"
+
+typedef struct {
+    unsigned char status;
+    unsigned char chs_first[3];
+    unsigned char type;
+    unsigned char chs_last[3];
+    unsigned long lba_first;
+    unsigned long lba_count;
+} partition_table_entry_t;
+
+#define MBR_ENTRY_COUNT 4
+typedef struct {
+    unsigned char bootcode[446];
+    partition_table_entry_t partition[MBR_ENTRY_COUNT];
+    unsigned int signature;
+} master_boot_record_t;
+
+#define DRIVE_COUNT 2
+static unsigned char ide_drives_present; /* bitmap */
+static unsigned long ide_partition_start[DRIVE_COUNT];
+static unsigned int  ide_slice_count[DRIVE_COUNT];
+
+__sfr __at IDE_REG_ALTSTATUS ide_reg_altstatus;
+__sfr __at IDE_REG_COMMAND   ide_reg_command;
+__sfr __at IDE_REG_CONTROL   ide_reg_control;
+__sfr __at IDE_REG_DATA      ide_reg_data;
+__sfr __at IDE_REG_DEVHEAD   ide_reg_devhead;
+__sfr __at IDE_REG_ERROR     ide_reg_error;
+__sfr __at IDE_REG_FEATURES  ide_reg_features;
+__sfr __at IDE_REG_LBA_0     ide_reg_lba_0;
+__sfr __at IDE_REG_LBA_1     ide_reg_lba_1;
+__sfr __at IDE_REG_LBA_2     ide_reg_lba_2;
+__sfr __at IDE_REG_LBA_3     ide_reg_lba_3;
+__sfr __at IDE_REG_SEC_COUNT ide_reg_sec_count;
+__sfr __at IDE_REG_STATUS    ide_reg_status;
+
+static void devide_read_data(void *buffer, unsigned char ioport) __naked
+{
+    buffer; ioport; /* silence compiler warning */
+    __asm
+            pop de              ; return address
+            pop hl              ; buffer address
+            pop bc              ; IO port number (in c)
+            push bc             ; restore stack
+            push hl
+            push de
+
+            ld b, #0            ; setup count
+            inir                ; first 256 bytes
+            inir                ; second 256 bytes
+            ret
+    __endasm;
+}
+
+static void devide_write_data(void *buffer, unsigned char ioport) __naked
+{
+    buffer; ioport; /* silence compiler warning */
+    __asm
+            pop de              ; return address
+            pop hl              ; buffer address
+            pop bc              ; IO port number (in c)
+            push bc             ; restore stack
+            push hl
+            push de
+
+            ld b, #0            ; setup count
+            otir                ; first 256 bytes
+            otir                ; second 256 bytes
+            ret
+    __endasm;
+}
+
+static void devide_delay(void)
+{
+    timer_t timeout;
+
+    timeout = set_timer_ms(25);
+
+    while(!timer_expired(timeout))
+        platform_idle();
+}
+
+static bool devide_wait(unsigned char bits)
+{
+    unsigned char status;
+    timer_t timeout;
+
+    timeout = set_timer_ms(500);
+
+    while(true){
+        status = ide_reg_status;
+
+        if((status & (IDE_STATUS_BUSY | IDE_STATUS_ERROR | bits)) == bits)
+            return true;
+
+        if((status & (IDE_STATUS_BUSY | IDE_STATUS_ERROR)) == IDE_STATUS_ERROR){
+            kprintf("ide error, status=%x\n", status);
+            return false;
+        }
+
+        if(timer_expired(timeout)){
+            kprintf("ide timeout, status=%x\n", status);
+            return false;
+        }
+    };
+}
+
+static bool devide_read_sector(unsigned char *buffer)
+{
+    if(!devide_wait(IDE_STATUS_DATAREQUEST))
+        return false;
+
+    devide_read_data(buffer, IDE_REG_DATA);
+
+    return true;
+}
+
+static bool devide_write_sector(unsigned char *buffer)
+{
+    if(!devide_wait(IDE_STATUS_DATAREQUEST))
+        return false;
+
+    devide_write_data(buffer, IDE_REG_DATA);
+
+    if(!devide_wait(IDE_STATUS_READY))
+        return false;
+
+    return true;
+}
+
+static int devide_transfer(uint8_t minor, bool is_read, uint8_t rawflag)
+{
+    unsigned char *target, *p;
+    unsigned long lba;
+    unsigned char drive;
+
+    drive = minor >> 6;
+    minor = minor & 0x3F;
+
+    if(rawflag == 0) {
+        target = udata.u_buf->bf_data;
+        lba = udata.u_buf->bf_blk;
+    }else
+        goto xferfail;
+
+    /* minor 0 is the whole disk and requires no translation */
+    if(minor > 0){
+        /* minor 1+ are slices located within the partition */
+        lba += (ide_partition_start[drive]);
+        lba += ((unsigned long)(minor-1) << 16);
+    }
+
+#if 0
+    ide_reg_lba_3 = ((lba >> 24) & 0xF) | ((drive == 0) ? 0xE0 : 0xF0); // select drive, start loading LBA
+    ide_reg_lba_2 = (lba >> 16);
+    ide_reg_lba_1 = (lba >> 8);
+    ide_reg_lba_0 = lba;
+#else
+    /* sdcc sadly unable to figure this out for itself yet */
+    p = (unsigned char *)&lba;
+    ide_reg_lba_3 = (p[3] & 0x0F) | ((drive == 0) ? 0xE0 : 0xF0); // select drive, start loading LBA
+    ide_reg_lba_2 = p[2];
+    ide_reg_lba_1 = p[1];
+    ide_reg_lba_0 = p[0];
+#endif
+    ide_reg_sec_count = 1;
+
+    if(is_read){
+        ide_reg_command = IDE_CMD_READ_SECTOR;
+        if(!devide_read_sector(target))
+            goto xferfail;
+    }else{
+        ide_reg_command = IDE_CMD_WRITE_SECTOR;
+        if(!devide_write_sector(target))
+            goto xferfail;
+    }
+
+    return 1;
+xferfail:
+    udata.u_error = EIO;
+    return -1;
+}
+
+int devide_open(uint8_t minor, uint16_t flags)
+{
+    unsigned char drive;
+    flags; /* not used */
+
+    drive = minor >> 6;
+    minor = minor & 0x3F;
+
+    if(ide_drives_present & (1 << drive) && (minor == 0 || minor < ide_slice_count[drive]))
+        return 0;
+
+    udata.u_error = ENODEV;
+    return -1;
+}
+
+int devide_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag; /* not used */
+    return devide_transfer(minor, true, rawflag);
+}
+
+int devide_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag; /* not used */
+    return devide_transfer(minor, false, rawflag);
+}
+
+void devide_init_drive(unsigned char drive)
+{
+    unsigned char *buffer, i, select;
+    master_boot_record_t *mbr;
+
+    switch(drive){
+        case 0: select = 0xE0; break;
+        case 1: select = 0xF0; break;
+        default: return;
+    }
+
+    kprintf("hd%c: ", 'a' + drive);
+    ide_partition_start[drive] = 0;
+    ide_slice_count[drive] = 0;
+
+    /* reset the drive */
+    ide_reg_devhead = select;
+    ide_reg_control = 0x06; /* assert reset, no interrupts */
+    devide_delay();
+    ide_reg_control = 0x02; /* release reset, no interruptst */
+    devide_delay();
+    if(!devide_wait(IDE_STATUS_READY))
+        return;
+
+#ifdef IDE_8BIT_ONLY
+    /* set 8-bit mode -- mostly only supported by CF cards */
+    ide_reg_devhead = select;
+    if(!devide_wait(IDE_STATUS_READY))
+        return;
+    ide_reg_features = 0x01;
+    ide_reg_command = IDE_CMD_SET_FEATURES;
+#endif
+
+    /* confirm drive has LBA support */
+    if(!devide_wait(IDE_STATUS_READY))
+        return;
+    ide_reg_command = IDE_CMD_IDENTIFY;
+
+    /* allocate temporary sector buffer memory */
+    buffer = (unsigned char *)tmpbuf();
+
+    if(!devide_read_sector(buffer))
+        goto failout;
+
+    if(!(buffer[99] & 0x02)){
+        kputs("LBA unsupported.\n");
+        goto failout;
+    }
+
+    /* read first sector (looking for the partition table) */
+    if(!devide_wait(IDE_STATUS_READY))
+        goto failout;
+
+    ide_reg_devhead = select;
+    ide_reg_lba_2 = 0;
+    ide_reg_lba_1 = 0;
+    ide_reg_lba_0 = 0;
+    ide_reg_sec_count = 1;
+    ide_reg_command = IDE_CMD_READ_SECTOR;
+
+    if(!devide_read_sector(buffer))
+        goto failout;
+
+    /* if we get this far the drive is apparently present and functioning */
+    ide_drives_present |= (1 << drive);
+
+    /* check for MBR table signature */
+    mbr = (master_boot_record_t*)buffer;
+    if(mbr->signature != 0xaa55){
+        kputs("no partition table\n");
+        goto failout;
+    }
+
+    /* look for a fuzix partition (type 0x5A) */
+    for(i=0; i<MBR_ENTRY_COUNT; i++){
+        if(mbr->partition[i].type == 0x5A){
+            ide_partition_start[drive] = mbr->partition[i].lba_first;
+            ide_slice_count[drive] = mbr->partition[i].lba_count >> 16;
+            break;
+        }
+    }
+
+    kprintf("%d slices\n", ide_slice_count[drive]);
+
+failout:
+    brelse((bufptr)buffer);
+}
+
+void devide_init(void)
+{
+    unsigned char d;
+
+    ide_drives_present = 0;
+
+    for(d=0; d<DRIVE_COUNT; d++)
+        devide_init_drive(d);
+}
diff --git a/Kernel/dev/devide.h b/Kernel/dev/devide.h
new file mode 100644 (file)
index 0000000..75409f0
--- /dev/null
@@ -0,0 +1,73 @@
+#ifndef __DEVIDE_DOT_H__
+#define __DEVIDE_DOT_H__
+
+#include "config.h"
+
+/* IDE Drive Configuration (in config.h)
+   Define DEVICE_IDE if IDE hardware is present on your platform.
+
+   Define IDE_8BIT_ONLY if the system implements only half of the 16-bit data
+   bus (eg N8VEM Mark IV).
+
+   If the IDE registers appear in one contiguous block then define IDE_REG_BASE
+   and either IDE_REG_CS0_FIRST or IDE_REG_CS1_FIRST.
+
+   If the IDE registers appear in two non-contiguous blocks then define both
+   IDE_REG_CS0_BASE and IDE_REG_CS1_BASE.
+
+   If neither of these is suitable just define the address of each register
+   ie IDE_REG_DATA, IDE_REG_ERROR, etc.
+*/
+
+void devide_init(void);
+int  devide_open(uint8_t minor, uint16_t flags);
+int  devide_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int  devide_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+
+#ifdef IDE_REG_BASE
+#ifdef IDE_REG_CS0_FIRST
+#define IDE_REG_CS0_BASE   (IDE_REG_BASE+0x00)
+#define IDE_REG_CS1_BASE   (IDE_REG_BASE+0x08)
+#endif
+#ifdef IDE_REG_CS1_FIRST
+#define IDE_REG_CS0_BASE   (IDE_REG_BASE+0x08)
+#define IDE_REG_CS1_BASE   (IDE_REG_BASE+0x00)
+#endif
+#endif
+
+#ifdef IDE_REG_CS0_BASE
+#define IDE_REG_ALTSTATUS (IDE_REG_CS0_BASE + 0x06) 
+#define IDE_REG_CONTROL   (IDE_REG_CS0_BASE + 0x06) 
+#endif
+#ifdef IDE_REG_CS1_BASE
+#define IDE_REG_DATA      (IDE_REG_CS1_BASE + 0x00) 
+#define IDE_REG_ERROR     (IDE_REG_CS1_BASE + 0x01) 
+#define IDE_REG_FEATURES  (IDE_REG_CS1_BASE + 0x01) 
+#define IDE_REG_SEC_COUNT (IDE_REG_CS1_BASE + 0x02) 
+#define IDE_REG_LBA_0     (IDE_REG_CS1_BASE + 0x03) 
+#define IDE_REG_LBA_1     (IDE_REG_CS1_BASE + 0x04) 
+#define IDE_REG_LBA_2     (IDE_REG_CS1_BASE + 0x05) 
+#define IDE_REG_LBA_3     (IDE_REG_CS1_BASE + 0x06) 
+#define IDE_REG_DEVHEAD   (IDE_REG_CS1_BASE + 0x06) 
+#define IDE_REG_STATUS    (IDE_REG_CS1_BASE + 0x07) 
+#define IDE_REG_COMMAND   (IDE_REG_CS1_BASE + 0x07) 
+#endif
+
+/* IDE status register bits */
+#define IDE_STATUS_BUSY         0x80
+#define IDE_STATUS_READY        0x40
+#define IDE_STATUS_DEVFAULT     0x20
+#define IDE_STATUS_SEEKCOMPLETE 0x10 // not important
+#define IDE_STATUS_DATAREQUEST  0x08
+#define IDE_STATUS_CORRECTED    0x04 // not important
+#define IDE_STATUS_INDEX        0x02 // not important
+#define IDE_STATUS_ERROR        0x01
+
+/* IDE command codes */
+#define IDE_CMD_READ_SECTOR     0x20
+#define IDE_CMD_WRITE_SECTOR    0x30
+#define IDE_CMD_IDENTIFY        0xEC
+#define IDE_CMD_SET_FEATURES    0xEF
+
+#endif
diff --git a/Kernel/platform-n8vem-mark4/Makefile b/Kernel/platform-n8vem-mark4/Makefile
new file mode 100644 (file)
index 0000000..572519b
--- /dev/null
@@ -0,0 +1,33 @@
+CSRCS += devices.c main.c devtty.c
+DSRCS = ../dev/devide.c
+
+ASRCS = crt0.s z180.s mark4.s commonmem.s
+
+AOBJS = $(ASRCS:.s=.rel)
+COBJS = $(CSRCS:.c=.rel)
+DOBJS = $(patsubst ../dev/%.c,%.rel, $(DSRCS))
+
+OBJS  = $(AOBJS) $(COBJS) $(DOBJS)
+
+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 $<
+
+clean:
+       rm -f $(OBJS) $(JUNK)  core *~ fuzix.com makecpmloader
+
+z180.rel:              z180.s kernel.def ../cpu-z180/z180.s
+
+image:
+       ../cpm-loader/makecpmloader ../cpm-loader/cpmload.bin ../fuzix.bin 0x88 fuzix.com
diff --git a/Kernel/platform-n8vem-mark4/README b/Kernel/platform-n8vem-mark4/README
new file mode 100644 (file)
index 0000000..914c5a6
--- /dev/null
@@ -0,0 +1,11 @@
+This is UZI for the N8VEM Mark IV SBC
+By Will Sowerbutts <will@sowerbutts.com>
+
+Assumes an N8VEM Mark IV SBC fitted with 512KB RAM, with the RS232 port as
+tty1, and the RS422 port as tty2. Does not yet support any ECB peripheral
+boards.
+
+To build, edit ../Makefile to read:
+
+export TARGET= n8vem-mark4
+export CPU = z180
diff --git a/Kernel/platform-n8vem-mark4/commonmem.s b/Kernel/platform-n8vem-mark4/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-n8vem-mark4/config.h b/Kernel/platform-n8vem-mark4/config.h
new file mode 100644 (file)
index 0000000..e56ad57
--- /dev/null
@@ -0,0 +1,55 @@
+/* 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
+/* Fixed banking */
+#define CONFIG_BANK_FIXED
+/* 8 60K banks, 1 is kernel */
+#define MAX_MAPS       8
+#define MAP_SIZE       0xF000U
+
+/* Banks as reported to user space */
+#define CONFIG_BANKS   1
+
+#define TICKSPERSEC 100U   /* 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. */
+
+#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        (0x0081)  /* Location of root dev name */
+
+/* Device parameters */
+#define NUM_DEV_TTY 2
+
+#define TTYDEV   BOOT_TTY /* Device used by kernel for messages, panics */
+//#define SWAPDEV  (256 + 1)  /* Device for swapping. (z80pack drive J) */
+#define NBUFS    10       /* Number of block buffers */
+#define NMOUNTS         4        /* Number of mounts at a time */
+
+/* Hardware parameters */
+#define Z180_IO_BASE       0x40
+
+#define DEVICE_IDE                  /* enable if IDE interface present */
+#define IDE_REG_BASE       0x80
+#define IDE_8BIT_ONLY
+#define IDE_REG_CS1_FIRST
diff --git a/Kernel/platform-n8vem-mark4/cpmload.s b/Kernel/platform-n8vem-mark4/cpmload.s
new file mode 100644 (file)
index 0000000..7d1dfa2
--- /dev/null
@@ -0,0 +1,36 @@
+.module cpmload
+.area _LOADER (ABS)
+
+    ; CP/M will load us at 0x0100
+    ; We want to relocate our payload (the kernel) and jump into it.
+    ; We put a small stub at the very bottom of memory, copy the kernel into
+    ; place above us, then jump into it.
+
+    .org 0x100
+    di
+    ; copy ourselves to the very bottom of memory -- 0x00 upwards
+    ld de, #0
+    ld hl, #(doload)                ; start of loader code
+    ld bc, #(endloader-doload)      ; length of our loader
+    ldir                            ; copy copy copy!
+    ld hl, (load_address)
+    ld sp, hl                       ; stash copy of entry vector in SP for now
+    ex de, hl                       ; load_address to de
+    ld hl, #payload_start
+    ld bc, (load_length)
+    jp 0                            ; jump and perform copy in low memory
+
+    ; this code gets copied to .org 0
+doload:
+    ldir                            ; copy image into correct place
+    ld hl, #0
+    add hl, sp                      ; recover entry vector
+    jp (hl)                         ; run image
+endloader:                          ; end of code to copy
+
+    ; the data is in a trailer, with a 6-byte header:
+load_address:
+    .ds 2
+load_length:
+    .ds 2
+payload_start:
diff --git a/Kernel/platform-n8vem-mark4/crt0.s b/Kernel/platform-n8vem-mark4/crt0.s
new file mode 100644 (file)
index 0000000..98ac696
--- /dev/null
@@ -0,0 +1,72 @@
+; 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 _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
+
+        ; 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
+
+        ; Configure memory map
+        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-n8vem-mark4/devices.c b/Kernel/platform-n8vem-mark4/devices.c
new file mode 100644 (file)
index 0000000..2e861aa
--- /dev/null
@@ -0,0 +1,39 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <tty.h>
+#include <devsys.h>
+#include <devtty.h>
+#include <devide.h>
+
+struct devsw dev_tab[] =  /* The device driver switch table */
+{
+// minor    open         close        read      write       ioctl
+// -----------------------------------------------------------------
+  /* 0: /dev/hd                IDE-8 interface */
+  {  devide_open, no_close, devide_read, devide_write, no_ioctl },
+  /* 1: /dev/sd                SD interface */
+  {  no_open,     no_close,    no_rdwr,   no_rdwr,   no_ioctl },
+  /* 2: /dev/tty       serial ports */
+  {  tty_open,     tty_close,   tty_read,  tty_write,  tty_ioctl },
+  /* 3: /dev/lpr       Unused slot (pad to keep system devices at index 4) */
+  {  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  },
+  /* 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) + 255)
+       return false;
+    else
+        return true;
+}
+
+void device_init(void)
+{
+    devide_init();
+}
diff --git a/Kernel/platform-n8vem-mark4/devtty.c b/Kernel/platform-n8vem-mark4/devtty.c
new file mode 100644 (file)
index 0000000..ed2a231
--- /dev/null
@@ -0,0 +1,72 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <tty.h>
+#include <devtty.h>
+#include "config.h"
+#include <z180.h>
+
+char tbuf1[TTYSIZ];
+char tbuf2[TTYSIZ];
+
+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 },
+};
+
+void tty_setup(uint8_t minor)
+{
+    minor;
+}
+
+/* For the moment */
+int tty_carrier(uint8_t minor)
+{
+    minor;
+    return 1;
+}
+
+void tty_pollirq_asci0(void)
+{
+    while(ASCI_STAT0 & 0x80){
+        tty_inproc(1, ASCI_RDR0);
+    }
+}
+
+void tty_pollirq_asci1(void)
+{
+    while(ASCI_STAT1 & 0x80){
+        tty_inproc(2, ASCI_RDR1);
+    }
+}
+
+void tty_putc(uint8_t minor, unsigned char c)
+{
+    switch(minor){
+        case 1:
+            while(!(ASCI_STAT0 & 2));
+            ASCI_TDR0 = c;
+            break;
+        case 2:
+            while(!(ASCI_STAT1 & 2));
+            ASCI_TDR1 = c;
+            break;
+    }
+}
+
+bool tty_writeready(uint8_t minor)
+{
+    minor;
+    return 1;
+}
+
+/* kernel writes to system console -- never sleep! */
+void kputchar(char c)
+{
+    tty_putc(1, c);
+    if(c == '\n')
+        tty_putc(1, '\r');
+}
+
diff --git a/Kernel/platform-n8vem-mark4/devtty.h b/Kernel/platform-n8vem-mark4/devtty.h
new file mode 100644 (file)
index 0000000..3a499c0
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __DEVTTY_DOT_H__
+#define __DEVTTY_DOT_H__
+void tty_putc(uint8_t minor, unsigned char c);
+bool tty_writeready(uint8_t minor);
+void tty_pollirq_asci0(void);
+void tty_pollirq_asci1(void);
+#endif
diff --git a/Kernel/platform-n8vem-mark4/kernel.def b/Kernel/platform-n8vem-mark4/kernel.def
new file mode 100644 (file)
index 0000000..e9606c0
--- /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.
+NMOS_Z80                    .equ 0
+
+OS_BANK                     .equ 0x00         ; value from include/kernel.h
+
+; N8VEM Mark IV mnemonics
+FIRST_RAM_BANK              .equ 0x80         ; low 512K of physical memory is ROM/ECB window.
+RAM_KB                      .equ 512
+Z180_IO_BASE                .equ 0x40
+MARK4_IDE_BASE              .equ 0x80
+MARK4_IDE_DATA              .equ MARK4_IDE_BASE
+
+; No standard clock speed for the Mark IV board, but this is a common choice.
+CPU_CLOCK_KHZ               .equ 36864        ; 18.432MHz * 2
diff --git a/Kernel/platform-n8vem-mark4/main.c b/Kernel/platform-n8vem-mark4/main.c
new file mode 100644 (file)
index 0000000..49aaed3
--- /dev/null
@@ -0,0 +1,67 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+#include "config.h"
+#include <z180.h>
+
+uint16_t ramtop = PROGTOP;
+extern unsigned char irqvector;
+
+void z180_timer_interrupt(void)
+{
+    unsigned char a;
+
+    /* we have to read both of these registers in order to reset the timer */
+    a = TIME_TMDR0L;
+    a = TIME_TCR;
+
+    timer_interrupt();
+}
+
+
+void pagemap_init(void)
+{
+    int i;
+
+    /* N8VEM SBC Mark IV has RAM in the top 512K of physical memory. 
+     * First 64K is used by the kernel. 
+     * Each process gets the full 64K for now.
+     * Page size is 4KB. */
+    for(i = 0x90; i < 0x100; i+=0x10)
+        pagemap_add(i);
+}
+
+void platform_idle(void)
+{
+    /* Let's go to sleep while we wait for something to interrupt us;
+     * Makes the Mark IV's run LED go red, which amuses me greatly. */
+    __asm
+        halt
+    __endasm;
+}
+
+void platform_interrupt(void)
+{
+    switch(irqvector){
+        case Z180_INT_TIMER0:
+            z180_timer_interrupt(); 
+            return;
+        case Z180_INT_ASCI0:
+            tty_pollirq_asci0();
+            return;
+        case Z180_INT_ASCI1:
+            tty_pollirq_asci1();
+            return;
+        default:
+            return;
+    }
+}
+
+void map_init(void)
+{
+    /* clone udata and stack into a regular process bank, return with common memory
+       for the new process loaded */
+    copy_and_map_process(&init_process->p_page);
+    /* kernel bank udata (0x300 bytes) is never used again -- could be reused? */
+}
diff --git a/Kernel/platform-n8vem-mark4/mark4.s b/Kernel/platform-n8vem-mark4/mark4.s
new file mode 100644 (file)
index 0000000..8d9bdcc
--- /dev/null
@@ -0,0 +1,178 @@
+; 2014-12-16 William R Sowerbutts
+; N8VEM Mark IV SBC hardware specific code
+
+        .module mark4
+        .z180
+
+        ; exported symbols
+        .globl init_early
+        .globl init_hardware
+        .globl outchar
+        .globl outcharhex
+        .globl platform_interrupt_all
+        .globl _trap_monitor
+
+        .globl map_kernel
+        .globl map_process_always
+        .globl map_save
+        .globl map_restore
+        ;.globl map_process_only
+
+        ; imported symbols
+        .globl z180_init_hardware
+        .globl z180_init_early
+        .globl _ramsize
+        .globl _procmem
+        .globl outhl
+        .globl outnewline
+
+        .include "kernel.def"
+        .include "../cpu-z180/z180.def"
+        .include "../kernel.def"
+
+; -----------------------------------------------------------------------------
+; Initialisation code
+; -----------------------------------------------------------------------------
+        .area _DISCARD
+
+init_early:
+        jp z180_init_early
+
+init_hardware:
+        ; set system RAM size
+        ld hl, #RAM_KB
+        ld (_ramsize), hl
+        ld hl, #(RAM_KB-64)        ; 64K for kernel
+        ld (_procmem), hl
+
+        ; enable ASCI interrupts
+        in0 a, (ASCI_STAT0)
+        or #0x08                ; enable ASCI0 receive interrupts
+        out0 (ASCI_STAT0), a
+        in0 a, (ASCI_ASEXT0)
+        and #0x7f               ; disable RDRF interrupt inhibit
+        out0 (ASCI_ASEXT0), a
+        in0 a, (ASCI_STAT1)
+        or #0x08                ; enable ASCI1 receive interrupts
+        out0 (ASCI_STAT1), a
+        in0 a, (ASCI_ASEXT1)
+        and #0x7f               ; disable RDRF interrupt inhibit
+        out0 (ASCI_ASEXT1), a
+
+        jp z180_init_hardware
+
+; -----------------------------------------------------------------------------
+; COMMON MEMORY BANK (0xF000 upwards)
+; -----------------------------------------------------------------------------
+        .area _COMMONMEM
+
+; outchar: Wait for UART TX idle, then print the char in A
+; destroys: AF
+outchar:
+        push bc
+        ld b, a
+        ; wait for transmitter to be idle
+ocloop: in0 a, (ASCI_STAT0)
+        bit 1, a        ; and 0x02
+        jr z, ocloop    ; loop while busy
+        ; now output the char to serial port
+        ld a, b
+        out0 (ASCI_TDR0), a
+        pop bc
+        ret
+
+platform_interrupt_all:
+        ret
+
+map_kernel: ; map the kernel into the low 60K, leaves common memory unchanged
+        push af
+.if DEBUGBANK
+        ld a, #'K'
+        call outchar
+.endif
+        ld a, #(OS_BANK + FIRST_RAM_BANK)
+        out0 (MMU_BBR), a
+        pop af
+        ret
+
+; this "map_process" business makes no sense on mark4 since we'd switch stacks
+; and the RET would thus lose its return address. oh damn. I suppose we could
+; pop the stack address into hl, then jp (hl) or whatever. let's try and get by
+; without it.
+;
+; map_process: ; if HL=0 call map_kernel, else map the full 64K in bank pointed to by HL
+;             ld a, h
+;             or l
+;             jr z, map_kernel
+;             ld a, (hl)
+;             out0 (MMU_BBR), a
+;             out0 (MMU_CBR), a
+;             ret
+
+; map_process_only: ; as map_process, but does not modify common memory
+;             ld a, h
+;             or l
+;             jr z, map_kernel
+;             ld a, (hl)
+;             out0 (MMU_BBR), a
+;             ret
+
+map_process_always: ; map the process into the low 60K based on current common mem (which is unchanged)
+        push af
+.if DEBUGBANK
+        ld a, #'='
+        call outchar
+.endif
+        ld a, (U_DATA__U_PAGE)
+        out0 (MMU_BBR), a
+.if DEBUGBANK
+        call outcharhex
+.endif
+        ; MMU_CBR is left unchanged
+        pop af
+        ret
+
+map_save:   ; save the current process/kernel mapping
+        push af
+        in0 a, (MMU_BBR)
+        ld (map_store), a
+        pop af
+        ret
+
+map_restore: ; restore the saved process/kernel mapping
+        push af
+.if DEBUGBANK
+        ld a, #'-'
+        call outchar
+.endif
+        ld a, (map_store)
+        out0 (MMU_BBR), a
+.if DEBUGBANK
+        call outcharhex
+.endif
+        pop af
+        ret
+
+_trap_monitor:
+        di
+        call outnewline
+        pop hl
+        call outhl
+        call outnewline
+        pop hl
+        call outhl
+        call outnewline
+        pop hl
+        call outhl
+        call outnewline
+        pop hl
+        call outhl
+        call outnewline
+        pop hl
+        call outhl
+        call outnewline
+        halt
+        jr _trap_monitor
+
+map_store:  ; storage for map_save/map_restore
+        .db 0
diff --git a/Kernel/platform-n8vem-mark4/uzi.lnk b/Kernel/platform-n8vem-mark4/uzi.lnk
new file mode 100644 (file)
index 0000000..c881d86
--- /dev/null
@@ -0,0 +1,36 @@
+-mwxuy
+-i uzi.ihx
+-b _CODE=0x0088
+-b _COMMONMEM=0xF000
+-b _DISCARD=0xE000
+-l z180
+platform-n8vem-mark4/crt0.rel
+platform-n8vem-mark4/commonmem.rel
+platform-n8vem-mark4/z180.rel
+platform-n8vem-mark4/mark4.rel
+platform-n8vem-mark4/main.rel
+start.rel
+version.rel
+lowlevel-z180.rel
+usermem_std-z180.rel
+timer.rel
+kdata.rel
+usermem.rel
+platform-n8vem-mark4/devices.rel
+devio.rel
+filesys.rel
+process.rel
+inode.rel
+syscall_exec.rel
+syscall_fs.rel
+syscall_fs2.rel
+syscall_proc.rel
+syscall_other.rel
+tty.rel
+mm.rel
+bankfixed.rel
+swap.rel
+devsys.rel
+platform-n8vem-mark4/devtty.rel
+platform-n8vem-mark4/devide.rel
+-e
diff --git a/Kernel/platform-n8vem-mark4/z180.s b/Kernel/platform-n8vem-mark4/z180.s
new file mode 100644 (file)
index 0000000..7371295
--- /dev/null
@@ -0,0 +1 @@
+.include "../cpu-z180/z180.s"
diff --git a/Kernel/platform-p112/Makefile b/Kernel/platform-p112/Makefile
new file mode 100644 (file)
index 0000000..702be27
--- /dev/null
@@ -0,0 +1,33 @@
+CSRCS += devices.c main.c devtty.c
+DSRCS = ../dev/devide.c
+
+ASRCS = crt0.s z180.s p112.s commonmem.s
+
+AOBJS = $(ASRCS:.s=.rel)
+COBJS = $(CSRCS:.c=.rel)
+DOBJS = $(patsubst ../dev/%.c,%.rel, $(DSRCS))
+
+OBJS  = $(AOBJS) $(COBJS) $(DOBJS)
+
+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 $<
+
+clean:
+       rm -f $(OBJS) $(JUNK)  core *~ fuzix.com
+
+z180.rel:              z180.s kernel.def ../cpu-z180/z180.s
+
+image:
+       ../cpm-loader/makecpmloader ../cpm-loader/cpmload.bin ../fuzix.bin 0x88 fuzix.com
diff --git a/Kernel/platform-p112/README b/Kernel/platform-p112/README
new file mode 100644 (file)
index 0000000..2b4b910
--- /dev/null
@@ -0,0 +1,11 @@
+This is UZI for the DX-Designs P112
+By Will Sowerbutts <will@sowerbutts.com>
+
+Assumes a P112 fitted with 1024KB RAM and G-IDE
+
+Only supported storage device at this time is the G-IDE
+
+To build, edit ../Makefile to read:
+
+export TARGET= p112
+export CPU = z180
diff --git a/Kernel/platform-p112/commonmem.s b/Kernel/platform-p112/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-p112/config.h b/Kernel/platform-p112/config.h
new file mode 100644 (file)
index 0000000..c5985ce
--- /dev/null
@@ -0,0 +1,56 @@
+/* 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
+/* Fixed banking */
+#define CONFIG_BANK_FIXED
+/* 8 60K banks, 1 is kernel */
+#define MAX_MAPS       16
+#define MAP_SIZE       0xF000U
+
+/* Banks as reported to user space */
+#define CONFIG_BANKS   1
+
+#define TICKSPERSEC 100U   /* 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. */
+
+#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        (0x0081)  /* Location of root dev name */
+
+/* Device parameters */
+#define NUM_DEV_TTY 4
+
+#define TTYDEV   BOOT_TTY /* Device used by kernel for messages, panics */
+//#define SWAPDEV  (256 + 1)  /* Device for swapping. (z80pack drive J) */
+#define NBUFS    10       /* Number of block buffers */
+#define NMOUNTS         4        /* Number of mounts at a time */
+
+/* Hardware parameters */
+#define Z180_IO_BASE       0x00
+
+#define DEVICE_IDE                  /* enable if IDE interface present */
+#define IDE_REG_BASE       0x50
+#define IDE_REG_CS0_FIRST
+#define IDE_REG_CS0_BASE   (IDE_REG_BASE+0x00)
+#define IDE_REG_CS1_BASE   (IDE_REG_BASE+0x08)
diff --git a/Kernel/platform-p112/crt0.s b/Kernel/platform-p112/crt0.s
new file mode 100644 (file)
index 0000000..98ac696
--- /dev/null
@@ -0,0 +1,72 @@
+; 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 _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
+
+        ; 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
+
+        ; Configure memory map
+        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-p112/devices.c b/Kernel/platform-p112/devices.c
new file mode 100644 (file)
index 0000000..2e861aa
--- /dev/null
@@ -0,0 +1,39 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <tty.h>
+#include <devsys.h>
+#include <devtty.h>
+#include <devide.h>
+
+struct devsw dev_tab[] =  /* The device driver switch table */
+{
+// minor    open         close        read      write       ioctl
+// -----------------------------------------------------------------
+  /* 0: /dev/hd                IDE-8 interface */
+  {  devide_open, no_close, devide_read, devide_write, no_ioctl },
+  /* 1: /dev/sd                SD interface */
+  {  no_open,     no_close,    no_rdwr,   no_rdwr,   no_ioctl },
+  /* 2: /dev/tty       serial ports */
+  {  tty_open,     tty_close,   tty_read,  tty_write,  tty_ioctl },
+  /* 3: /dev/lpr       Unused slot (pad to keep system devices at index 4) */
+  {  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  },
+  /* 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) + 255)
+       return false;
+    else
+        return true;
+}
+
+void device_init(void)
+{
+    devide_init();
+}
diff --git a/Kernel/platform-p112/devtty.c b/Kernel/platform-p112/devtty.c
new file mode 100644 (file)
index 0000000..51e126d
--- /dev/null
@@ -0,0 +1,102 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <tty.h>
+#include <devtty.h>
+#include "config.h"
+#include <z180.h>
+
+char tbuf1[TTYSIZ];
+char tbuf2[TTYSIZ];
+char tbuf3[TTYSIZ];
+char tbuf4[TTYSIZ];
+
+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 },
+    {   tbuf3,   tbuf2,   tbuf2,   TTYSIZ,   0,   TTYSIZ/2 },
+    {   tbuf4,   tbuf2,   tbuf2,   TTYSIZ,   0,   TTYSIZ/2 },
+};
+
+void tty_setup(uint8_t minor)
+{
+    minor;
+}
+
+/* For the moment */
+int tty_carrier(uint8_t minor)
+{
+    minor;
+    return 1;
+}
+
+void tty_pollirq_asci0(void)
+{
+    while(ASCI_STAT0 & 0x80){
+        tty_inproc(1, ASCI_RDR0);
+    }
+}
+
+void tty_pollirq_asci1(void)
+{
+    while(ASCI_STAT1 & 0x80){
+        tty_inproc(2, ASCI_RDR1);
+    }
+}
+
+void tty_pollirq_escc(void)
+{
+    unsigned char rr3;
+    ESCC_CTRL_A = 0x03; /* select read register 3 */
+    rr3 = ESCC_CTRL_A;
+
+    if(rr3 & 0x20){ /* channel A RX pending */
+        tty_inproc(1, ESCC_DATA_A);
+    }
+    if(rr3 & 0x04){ /* channel B RX pending */
+        tty_inproc(2, ESCC_DATA_B);
+    }
+    if(rr3 & (~0x24)){
+        kputs("[escc hurts]");
+    }
+
+    ESCC_CTRL_A = 0x38; /* reset interrupt under service */
+}
+
+void tty_putc(uint8_t minor, unsigned char c)
+{
+    switch(minor){
+        case 1:
+            while(!(ESCC_CTRL_A & 4));
+            ESCC_DATA_A = c;
+            break;
+        case 2:
+            while(!(ESCC_CTRL_B & 4));
+            ESCC_DATA_B = c;
+            break;
+        case 3:
+            while(!(ASCI_STAT0 & 2));
+            ASCI_TDR0 = c;
+            break;
+        case 4:
+            while(!(ASCI_STAT1 & 2));
+            ASCI_TDR1 = c;
+            break;
+    }
+}
+
+bool tty_writeready(uint8_t minor)
+{
+    minor;
+    return 1;
+}
+
+/* kernel writes to system console -- never sleep! */
+void kputchar(char c)
+{
+    tty_putc(1, c);
+    if(c == '\n')
+        tty_putc(1, '\r');
+}
diff --git a/Kernel/platform-p112/devtty.h b/Kernel/platform-p112/devtty.h
new file mode 100644 (file)
index 0000000..2a428de
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __DEVTTY_DOT_H__
+#define __DEVTTY_DOT_H__
+void tty_putc(uint8_t minor, unsigned char c);
+bool tty_writeready(uint8_t minor);
+void tty_pollirq_escc(void);
+void tty_pollirq_asci0(void);
+void tty_pollirq_asci1(void);
+#endif
diff --git a/Kernel/platform-p112/kernel.def b/Kernel/platform-p112/kernel.def
new file mode 100644 (file)
index 0000000..e204fe8
--- /dev/null
@@ -0,0 +1,18 @@
+; 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.
+NMOS_Z80                    .equ 0
+
+OS_BANK                     .equ 0x00         ; value from include/kernel.h
+
+; P112
+FIRST_RAM_BANK              .equ 0x00         ; all memory is RAM on P112
+RAM_KB                      .equ 1024
+Z180_IO_BASE                .equ 0x00
+P112_IDE_BASE               .equ 0x50
+P112_IDE_DATA               .equ (P112_IDE_BASE+0x08)
+
+; Believe most P112 kits shipped with 16MHz oscillators, I have tried faster 
+; (18.432MHz) but this made the machine unstable.
+CPU_CLOCK_KHZ               .equ 16000        ; 16MHz is the stock crystal
diff --git a/Kernel/platform-p112/main.c b/Kernel/platform-p112/main.c
new file mode 100644 (file)
index 0000000..baf4da2
--- /dev/null
@@ -0,0 +1,72 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+#include <z180.h>
+#include "config.h"
+
+uint16_t ramtop = PROGTOP;
+extern unsigned char irqvector;
+
+void z180_timer_interrupt(void)
+{
+    unsigned char a;
+
+    /* we have to read both of these registers in order to reset the timer */
+    a = TIME_TMDR0L;
+    a = TIME_TCR;
+
+    timer_interrupt();
+}
+
+
+void pagemap_init(void)
+{
+    int i;
+
+    /* N8VEM SBC Mark IV has RAM in the top 512K of physical memory. 
+     * First 64K is used by the kernel. 
+     * Each process gets the full 64K for now.
+     * Page size is 4KB. */
+    for(i = 0x10; i < 0x100; i+=0x10){
+        pagemap_add(i);
+    }
+}
+
+void platform_idle(void)
+{
+    /* Let's go to sleep while we wait for something to interrupt us;
+     * Makes the Mark IV's run LED go red, which amuses me greatly. */
+    __asm
+        halt
+    __endasm;
+}
+
+void platform_interrupt(void)
+{
+    switch(irqvector){
+        case Z180_INT0:
+            tty_pollirq_escc();
+            return;
+        case Z180_INT_TIMER0:
+            z180_timer_interrupt(); 
+            return;
+        case Z180_INT_ASCI0:
+            tty_pollirq_asci0();
+            return;
+        case Z180_INT_ASCI1:
+            tty_pollirq_asci1();
+            return;
+        default:
+            kprintf("[int:%d?]", irqvector);
+            return;
+    }
+}
+
+void map_init(void)
+{
+    /* clone udata and stack into a regular process bank, return with common memory
+       for the new process loaded */
+    copy_and_map_process(&init_process->p_page);
+    /* kernel bank udata (0x300 bytes) is never used again -- could be reused? */
+}
diff --git a/Kernel/platform-p112/p112.s b/Kernel/platform-p112/p112.s
new file mode 100644 (file)
index 0000000..0f9579c
--- /dev/null
@@ -0,0 +1,202 @@
+; 2014-12-24 William R Sowerbutts
+; P112 hardware specific code
+
+        .module p112
+        .z180
+
+        ; exported symbols
+        .globl init_early
+        .globl init_hardware
+        .globl outchar
+        .globl outstring
+        .globl outcharhex
+        .globl platform_interrupt_all
+        .globl _trap_monitor
+
+        .globl map_kernel
+        .globl map_process_always
+        .globl map_save
+        .globl map_restore
+        ;.globl map_process_only
+
+        ; imported symbols
+        .globl z180_init_hardware
+        .globl z180_init_early
+        .globl _ramsize
+        .globl _procmem
+        .globl outhl
+        .globl outnewline
+
+        .include "kernel.def"
+        .include "../cpu-z180/z180.def"
+        .include "../kernel.def"
+
+; -----------------------------------------------------------------------------
+; Initialisation code
+; -----------------------------------------------------------------------------
+        .area _DISCARD
+
+init_early:
+        ; P112: stop the floppy motor in case it is running
+        ld a, #0x0c
+        out0 (0x92), a
+
+        ; unmap ROM
+        xor a
+        out0 (Z182_ROMBR), a
+
+        in0 a, (Z182_SYSCONFIG)
+        or #0x08            ; disable ROM chip select (is this required as well as setting Z182_ROMBR?)
+        out0 (Z182_SYSCONFIG), a
+
+        jp z180_init_early
+
+init_hardware:
+        ; set system RAM size
+        ld hl, #RAM_KB
+        ld (_ramsize), hl
+        ld hl, #(RAM_KB-64)        ; 64K for kernel
+        ld (_procmem), hl
+
+        ; enable ASCI interrupts
+        ; in0 a, (ASCI_STAT0)
+        ; or #0x08                ; enable ASCI0 receive interrupts
+        ; out0 (ASCI_STAT0), a
+        ; in0 a, (ASCI_ASEXT0)
+        ; and #0x7f               ; disable RDRF interrupt inhibit
+        ; out0 (ASCI_ASEXT0), a
+        ; in0 a, (ASCI_STAT1)
+        ; or #0x08                ; enable ASCI1 receive interrupts
+        ; out0 (ASCI_STAT1), a
+        ; in0 a, (ASCI_ASEXT1)
+        ; and #0x7f               ; disable RDRF interrupt inhibit
+        ; out0 (ASCI_ASEXT1), a
+
+        ; enable ESCC interrupts
+        ld bc, #0x0114 ; write register 1, 0x14: enable receive interrupts only
+        call write_escc
+        ld bc, #0x0908 ; write register 9, 0x08: master interrupt enable
+        call write_escc
+
+        jp z180_init_hardware
+
+write_escc:
+        out0 (ESCC_CTRL_A), b
+        out0 (ESCC_CTRL_A), c
+        out0 (ESCC_CTRL_B), b
+        out0 (ESCC_CTRL_B), c
+        ret
+
+; -----------------------------------------------------------------------------
+; COMMON MEMORY BANK (0xF000 upwards)
+; -----------------------------------------------------------------------------
+        .area _COMMONMEM
+
+; outchar: Wait for UART TX idle, then print the char in A
+; destroys: AF
+outchar:
+        push bc
+        ld b, a
+        ; wait for transmitter to be idle
+ocloop:     in0 a, (ESCC_CTRL_A)
+        and #0x04       ; test transmit buffer empty
+        jr z, ocloop
+        out0 (ESCC_DATA_A), b
+        pop bc
+        ret
+
+platform_interrupt_all:
+        ret
+
+map_kernel: ; map the kernel into the low 60K, leaves common memory unchanged
+        push af
+.if DEBUGBANK
+        ld a, #'K'
+        call outchar
+.endif
+        ld a, #(OS_BANK + FIRST_RAM_BANK)
+        out0 (MMU_BBR), a
+        pop af
+        ret
+
+; this "map_process" business makes no sense on mark4 since we'd switch stacks
+; and the RET would thus lose its return address. oh damn. I suppose we could
+; pop the stack address into hl, then jp (hl) or whatever. let's try and get by
+; without it.
+;
+; map_process: ; if HL=0 call map_kernel, else map the full 64K in bank pointed to by HL
+;             ld a, h
+;             or l
+;             jr z, map_kernel
+;             ld a, (hl)
+;             out0 (MMU_BBR), a
+;             out0 (MMU_CBR), a
+;             ret
+
+; map_process_only: ; as map_process, but does not modify common memory
+;             ld a, h
+;             or l
+;             jr z, map_kernel
+;             ld a, (hl)
+;             out0 (MMU_BBR), a
+;             ret
+
+map_process_always: ; map the process into the low 60K based on current common mem (which is unchanged)
+        push af
+.if DEBUGBANK
+        ld a, #'='
+        call outchar
+.endif
+        ld a, (U_DATA__U_PAGE)
+        out0 (MMU_BBR), a
+.if DEBUGBANK
+        call outcharhex
+.endif
+        ; MMU_CBR is left unchanged
+        pop af
+        ret
+
+map_save:   ; save the current process/kernel mapping
+        push af
+        in0 a, (MMU_BBR)
+        ld (map_store), a
+        pop af
+        ret
+
+map_restore: ; restore the saved process/kernel mapping
+        push af
+.if DEBUGBANK
+        ld a, #'-'
+        call outchar
+.endif
+        ld a, (map_store)
+        out0 (MMU_BBR), a
+.if DEBUGBANK
+        call outcharhex
+.endif
+        pop af
+        ret
+
+_trap_monitor:
+        di
+        call outnewline
+        pop hl
+        call outhl
+        call outnewline
+        pop hl
+        call outhl
+        call outnewline
+        pop hl
+        call outhl
+        call outnewline
+        pop hl
+        call outhl
+        call outnewline
+        pop hl
+        call outhl
+        call outnewline
+        halt
+        jr _trap_monitor
+
+map_store:  ; storage for map_save/map_restore
+        .db 0
diff --git a/Kernel/platform-p112/uzi.lnk b/Kernel/platform-p112/uzi.lnk
new file mode 100644 (file)
index 0000000..42407da
--- /dev/null
@@ -0,0 +1,36 @@
+-mwxuy
+-i uzi.ihx
+-b _CODE=0x0088
+-b _COMMONMEM=0xF000
+-b _DISCARD=0xE000
+-l z180
+platform-p112/crt0.rel
+platform-p112/commonmem.rel
+platform-p112/z180.rel
+platform-p112/p112.rel
+platform-p112/main.rel
+start.rel
+version.rel
+lowlevel-z180.rel
+usermem_std-z180.rel
+timer.rel
+kdata.rel
+usermem.rel
+platform-p112/devices.rel
+devio.rel
+filesys.rel
+process.rel
+inode.rel
+syscall_exec.rel
+syscall_fs.rel
+syscall_fs2.rel
+syscall_proc.rel
+syscall_other.rel
+tty.rel
+mm.rel
+bankfixed.rel
+swap.rel
+devsys.rel
+platform-p112/devtty.rel
+platform-p112/devide.rel
+-e
diff --git a/Kernel/platform-p112/z180.s b/Kernel/platform-p112/z180.s
new file mode 100644 (file)
index 0000000..7371295
--- /dev/null
@@ -0,0 +1 @@
+.include "../cpu-z180/z180.s"