mtx512: Initial port code
authorAlan Cox <alan@linux.intel.com>
Sat, 13 Dec 2014 22:49:38 +0000 (22:49 +0000)
committerAlan Cox <alan@linux.intel.com>
Sat, 13 Dec 2014 22:49:38 +0000 (22:49 +0000)
Not yet bootable.

Still to complete:
CTC setup
DART serial ports
CP/M tools scripts to spit out a memotech floppy disk

21 files changed:
Kernel/platform-mtx/Makefile [new file with mode: 0644]
Kernel/platform-mtx/README [new file with mode: 0644]
Kernel/platform-mtx/commonmem.s [new file with mode: 0644]
Kernel/platform-mtx/config.h [new file with mode: 0644]
Kernel/platform-mtx/crt0.s [new file with mode: 0644]
Kernel/platform-mtx/devfd.c [new file with mode: 0644]
Kernel/platform-mtx/devfd.h [new file with mode: 0644]
Kernel/platform-mtx/devices.c [new file with mode: 0644]
Kernel/platform-mtx/devlpr.c [new file with mode: 0644]
Kernel/platform-mtx/devlpr.h [new file with mode: 0644]
Kernel/platform-mtx/devsil.c [new file with mode: 0644]
Kernel/platform-mtx/devsil.h [new file with mode: 0644]
Kernel/platform-mtx/devtty.c [new file with mode: 0644]
Kernel/platform-mtx/devtty.h [new file with mode: 0644]
Kernel/platform-mtx/floppy.s [new file with mode: 0644]
Kernel/platform-mtx/kernel.def [new file with mode: 0644]
Kernel/platform-mtx/main.c [new file with mode: 0644]
Kernel/platform-mtx/mtx.s [new file with mode: 0644]
Kernel/platform-mtx/tricks.s [new file with mode: 0644]
Kernel/platform-mtx/uzi.lnk [new file with mode: 0644]
Kernel/platform-mtx/vdp.s [new file with mode: 0644]

diff --git a/Kernel/platform-mtx/Makefile b/Kernel/platform-mtx/Makefile
new file mode 100644 (file)
index 0000000..3bf371e
--- /dev/null
@@ -0,0 +1,34 @@
+
+CSRCS = devlpr.c devtty.c devfd.c devsil.c
+CSRCS += devices.c main.c
+
+ASRCS = crt0.s mtx.s vdp.s floppy.s
+ASRCS += tricks.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
+
+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 *~ 
+
+image:
+       cp ../fuzix.bin fuzix.com
diff --git a/Kernel/platform-mtx/README b/Kernel/platform-mtx/README
new file mode 100644 (file)
index 0000000..ff969d1
--- /dev/null
@@ -0,0 +1,33 @@
+The MTX512 has the following relevant features
+
+- "FDX" WD1791 floppy (and an actual DMA controller) at 0x40
+  SASI interface for floppies
+  (Not in emulator)
+- "SDX" WD1791 style floppy (and no DMA controller) at 0x10
+- 9918/29 VDP graphics (equivalent to MSX1 but on ports 1/2) - interrupts
+  are fed to the CTC however
+- Separate 80 column card (text mode only) (6845 on port 0x38/39)
+  this has its own memory port poked via port 30,31 (set 31 
+  bits 2-0 to the high address bits, bit 5 for attr, 6 for ascii, 7 for write
+  then port 30 for the low bits. Port 32 is the data port (read after write
+  before), port 33 for read/write is the attribute byte
+- "silicon disc" (aka RAM discs) on 0x50-53 54-57 58-5b 5c-5f
+- CTC timer (at CPU speed so can support single step)
+- RS232 (Z80 DART)
+- Sound (SN76489A) on I/O port 6, (strobe on port 3, 32uS reqired post
+  strobe)
+
+Memory is split into four banks the decode for which is dependent upon
+whether the box is in "ROM based" or "RAM based" mode. The memory is then
+switched in 48K banks with a 16K true common.
+
+All memory management is controlled by the page port (port 0). Bit 7 is set
+to 1 to turn the ROMs off, bit 4-6 detemine the rom page address, bits 0-3
+select the RAM bank.
+
+Note that Rememorizer is different, it allows 0x0f to be written to the
+low 3 bits of port 0, then port 0xd2, d0, d1 control the 3 16K banks and also
+has an SD card. Not supported, if you want it supported fix MEMU ;-)
+
+
+
diff --git a/Kernel/platform-mtx/commonmem.s b/Kernel/platform-mtx/commonmem.s
new file mode 100644 (file)
index 0000000..8c9f406
--- /dev/null
@@ -0,0 +1,10 @@
+;
+;      Common is at 0xC000. We don't actually have any choice about that
+;      the platform is wired this way.
+;
+
+        .module commonmem
+
+        .area _COMMONMEM
+
+       .include "../cpu-z80/std-commonmem.s"
diff --git a/Kernel/platform-mtx/config.h b/Kernel/platform-mtx/config.h
new file mode 100644 (file)
index 0000000..e4364b5
--- /dev/null
@@ -0,0 +1,53 @@
+/* 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) */
+#define CONFIG_PROFIL
+/* Multiple processes in memory at once */
+#define CONFIG_MULTI
+/* Single tasking */
+#undef CONFIG_SINGLETASK
+/* CP/M emulation */
+#define CONFIG_CPM_EMU
+/* Video terminal, not a serial tty */
+#define CONFIG_VT
+/* Fixed banking */
+#define CONFIG_BANK_FIXED
+/* 10 48K banks, 1 is kernel */
+#define MAX_MAPS       10
+#define MAP_SIZE       0xC000U
+
+/* Banks as reported to user space */
+#define CONFIG_BANKS   1
+
+#define TICKSPERSEC 50      /* Ticks per second */
+#define PROGBASE    0x0000  /* also data base */
+#define PROGLOAD    0x0100  /* also data base */
+#define PROGTOP     0xBD00  /* Top of program, base of U_DATA copy */
+#define PROC_SIZE   48     /* Memory needed per process */
+
+#define SWAP_SIZE   0x60       /* 48K in blocks */
+#define SWAPBASE    0x0000     /* We swap the lot in one, include the */
+#define SWAPTOP            0xC000      /* vectors so its a round number of sectors */
+#define MAX_SWAPS   64         /* How many swaps per disc */
+
+#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  /* Will be 4 two monitors, two serial */
+
+#define TTYDEV   BOOT_TTY /* Device used by kernel for messages, panics */
+#define SWAPDEV  ((8*256) + 0)  /* Device for swapping. - first silicon disk */
+#define NBUFS    16       /* Number of block buffers */
+#define NMOUNTS         4        /* Number of mounts at a time */
+
+/* Terminal definitions */
+#define VT_WIDTH       40
+#define VT_HEIGHT      24
+#define VT_RIGHT       39
+#define VT_BOTTOM      23
diff --git a/Kernel/platform-mtx/crt0.s b/Kernel/platform-mtx/crt0.s
new file mode 100644 (file)
index 0000000..d26bf28
--- /dev/null
@@ -0,0 +1,72 @@
+        .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__DATA
+        .globl l__DATA
+        .globl s__DISCARD
+        .globl l__DISCARD
+        .globl s__COMMONMEM
+        .globl l__COMMONMEM
+
+        .globl kstack_top
+
+        ; startup code
+        .area _CODE
+init:
+        di
+        ld sp, #kstack_top
+
+        ; Configure memory map
+        call init_early
+
+       ; 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
+
+        ; Hardware setup
+        call init_hardware
+
+        ; Call the C main routine
+        call _fuzix_main
+    
+        ; main shouldn't return, but if it does...
+        di
+stop:   halt
+        jr stop
+
diff --git a/Kernel/platform-mtx/devfd.c b/Kernel/platform-mtx/devfd.c
new file mode 100644 (file)
index 0000000..122c7ca
--- /dev/null
@@ -0,0 +1,97 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devfd.h>
+
+/* Two drives but minors 2,3 are single density mode */
+#define MAX_FD 4
+
+#define OPDIR_NONE     0
+#define OPDIR_READ     1
+#define OPDIR_WRITE    2
+
+#define FD_READ                0x88    /* 2797 needs 0x88, 1797 needs 0x80 */
+#define FD_WRITE       0xA8    /* Likewise A8 v A0 */
+
+static uint8_t motorct;
+static uint8_t fd_selected = 0xFF;
+static uint8_t fd_tab[MAX_FD];
+
+/*
+ *     We only support normal block I/O
+ */
+
+static int fd_transfer(uint8_t minor, bool is_read, uint8_t rawflag)
+{
+    blkno_t block;
+    uint16_t dptr;
+    int ct = 0;
+    int tries;
+    uint8_t err = 0;
+    uint8_t *driveptr = fd_tab + minor;
+    uint8_t cmd[6];
+
+    if(rawflag)
+        goto bad2;
+
+    if (fd_selected != minor) {
+        uint8_t err = fd_motor_on(minor|(minor > 1 ? 0: 0x10));
+        if (err)
+            goto bad;
+    }
+
+    dptr = (uint16_t)udata.u_buf->bf_data;
+    block = udata.u_buf->bf_blk;
+
+//    kprintf("Issue command: drive %d\n", minor);
+    cmd[0] = is_read ? FD_READ : FD_WRITE;
+    cmd[1] = block / 8;                /* 2 sectors per block */
+    cmd[2] = ((block & 7) << 1) + 1;
+    cmd[3] = is_read ? OPDIR_READ: OPDIR_WRITE;
+    cmd[4] = dptr & 0xFF;
+    cmd[5] = dptr >> 8;
+
+    while (ct < 2) {
+        for (tries = 0; tries < 4 ; tries++) {
+            err = fd_operation(cmd, driveptr);
+            if (err == 0)
+                break;
+            if (tries > 1)
+                fd_reset(driveptr);
+        }
+        /* FIXME: should we try the other half and then bale out ? */
+        if (tries == 3)
+            goto bad;
+        cmd[5]++;
+        cmd[2]++;      /* Next sector for next block */
+        ct++;
+    }
+    return 1;
+bad:
+    kprintf("fd%d: error %x\n", minor, err);
+bad2:
+    udata.u_error = EIO;
+    return -1;
+}
+
+int fd_open(uint8_t minor, uint16_t flag)
+{
+    flag;
+    if(minor >= MAX_FD) {
+        udata.u_error = ENODEV;
+        return -1;
+    }
+    return 0;
+}
+
+int fd_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;
+    return fd_transfer(minor, true, rawflag);
+}
+
+int fd_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;
+    return fd_transfer(minor, false, rawflag);
+}
diff --git a/Kernel/platform-mtx/devfd.h b/Kernel/platform-mtx/devfd.h
new file mode 100644 (file)
index 0000000..5f94507
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef __DEVFD_DOT_H__
+#define __DEVFD_DOT_H__
+
+/* public interface */
+int fd_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int fd_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int fd_open(uint8_t minor, uint16_t flag);
+
+/* low level interface */
+uint16_t fd_reset(uint8_t *driveptr);
+uint16_t fd_operation(uint8_t *cmd, uint8_t *driveptr);
+uint16_t fd_motor_on(uint16_t drivesel);
+uint16_t fd_motor_off(uint16_t driveptr);
+
+#endif /* __DEVFD_DOT_H__ */
diff --git a/Kernel/platform-mtx/devices.c b/Kernel/platform-mtx/devices.c
new file mode 100644 (file)
index 0000000..8fa0f48
--- /dev/null
@@ -0,0 +1,48 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <tty.h>
+#include <devfd.h>
+#include <devsil.h>
+#include <devsys.h>
+#include <devlpr.h>
+#include <devtty.h>
+
+struct devsw dev_tab[] =  /* The device driver switch table */
+{
+// minor    open         close        read      write       ioctl
+// -----------------------------------------------------------------
+  /* 0: /dev/fd                Floppy disc block devices  */
+  {  fd_open,      no_close,    fd_read,  fd_write,   no_ioctl  },
+  /* 1: /dev/hd                Hard disc block devices (hdx - not supported yet) */
+  {  no_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 */
+  {  lpr_open,     lpr_close,   no_rdwr,  lpr_write,  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 */
+  {  no_open,      no_close,    no_rdwr,  no_rdwr,    no_ioctl  },
+  {  no_open,      no_close,    no_rdwr,  no_rdwr,    no_ioctl  },
+  {  no_open,      no_close,    no_rdwr,  no_rdwr,    no_ioctl  },
+  /* 8: /dev/sild      Silicon disc block devices  */
+  {  sil_open,     no_close,    sil_read, sil_write,  no_ioctl  },
+};
+
+bool validdev(uint16_t dev)
+{
+    /* This is a bit uglier than needed but the right hand side is
+       a constant this way */
+    if(dev > ((sizeof(dev_tab)/sizeof(struct devsw)) << 8) + 255)
+       return false;
+    else
+        return true;
+}
+
+void device_init(void)
+{
+//  int i;
+//  for (i = 0; i < MAX_SWAPS; i++)
+//   swapmap_add(i);
+}
diff --git a/Kernel/platform-mtx/devlpr.c b/Kernel/platform-mtx/devlpr.c
new file mode 100644 (file)
index 0000000..6068384
--- /dev/null
@@ -0,0 +1,69 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <devlpr.h>
+
+__sfr __at 0x00 lpstrobel;
+__sfr __at 0x04 lpdata;                /* Data on write, status+strobe clr on read */
+
+int lpr_open(uint8_t minor, uint16_t flag)
+{
+       minor;
+       flag;                   // shut up compiler
+       return 0;
+}
+
+int lpr_close(uint8_t minor)
+{
+       minor;                  // shut up compiler
+       return 0;
+}
+
+int lpr_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+       int c = udata.u_count;
+       char *p = udata.u_base;
+       uint16_t ct;
+       uint8_t reg;
+
+       minor;
+       rawflag;
+       flag;                   // shut up compiler
+
+       while (c-- > 0) {
+               ct = 0;
+
+               /* Try and balance polling and sleeping */
+               while ((reg = lpdata) & 1) {
+                       reg ^= 2;
+                       if (reg & 6) {
+                               if (c == udata.u_count) {
+                                       if (reg & 4)
+                                               udata.u_error = ENOSPC;
+                                        else
+                                               udata.u_error = EIO;
+                                }
+                                return udata.u_count - c;
+                        }
+                       ct++;
+                       if (ct == 10000) {
+                               udata.u_ptab->p_timeout = 3;
+                               if (psleep_flags(NULL, flag)) {
+                                       if (c != udata.u_count)
+                                               udata.u_error = 0;
+                                       return udata.u_count - c;
+                               }
+                               ct = 0;
+                       }
+               }
+               /* Data */
+               lpdata = ugetc(p++);
+               /* Strobe - FIXME: should be 1uS */
+               for (reg = 0; reg < 128; reg++);
+               reg = lpstrobel;
+               for (reg = 0; reg < 128; reg++);
+               /* Strobe back high */
+               reg = lpdata;
+       }
+       return udata.u_count - c;
+}
diff --git a/Kernel/platform-mtx/devlpr.h b/Kernel/platform-mtx/devlpr.h
new file mode 100644 (file)
index 0000000..7765c18
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __DEVLPR_DOT_H__
+#define __DEVLPR_DOT_H__
+
+int lpr_open(uint8_t minor, uint16_t flag);
+int lpr_close(uint8_t minor);
+int lpr_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+
+#endif
diff --git a/Kernel/platform-mtx/devsil.c b/Kernel/platform-mtx/devsil.c
new file mode 100644 (file)
index 0000000..3f6e97f
--- /dev/null
@@ -0,0 +1,70 @@
+/* 
+ * Memotech Silicon Disk Driver
+ *
+ * FIXME: would be sensible to add swap support to this driver
+ */
+
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devsil.h>
+
+#define NUM_SIL                4
+
+static int sil_transfer(uint8_t minor, bool is_read, uint8_t rawflag)
+{
+    blkno_t block;
+    int block_xfer;
+    uint16_t dptr;
+    int dlen;
+    int ct = 0;
+    int map;
+
+    if(rawflag) {
+        dlen = udata.u_count;
+        dptr = (uint16_t)udata.u_base;
+        if (dptr & 0x1FF) {
+            udata.u_error = EIO;
+            return -1;
+        }
+        block = udata.u_offset >> 9;
+        block_xfer = dlen >> 9;
+        map = udata.u_page;
+    } else { /* rawflag == 0 */
+        dlen = 512;
+        dptr = (uint16_t)udata.u_buf->bf_data;
+        block = udata.u_buf->bf_blk;
+        block_xfer = 1;
+        map = 0;
+    }
+        
+    while (ct < block_xfer) {
+        sil_memcpy(is_read, map, dptr, block, 0x50 + 4 * minor);
+        block++;
+        ct++;
+    }
+    return ct;
+}
+
+int sil_open(uint8_t minor, uint16_t flag)
+{
+    flag;
+    if(minor >= NUM_SIL) {
+        udata.u_error = ENODEV;
+        return -1;
+    }
+    return 0;
+}
+
+int sil_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;minor;
+    return sil_transfer(minor, true, rawflag);
+}
+
+int sil_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;minor;
+    return sil_transfer(minor, false, rawflag);
+}
+
diff --git a/Kernel/platform-mtx/devsil.h b/Kernel/platform-mtx/devsil.h
new file mode 100644 (file)
index 0000000..e14d2aa
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __DEVSIL_DOT_H__
+#define __DEVSIL_DOT_H__
+
+/* public interface */
+int sil_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int sil_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int sil_open(uint8_t minor, uint16_t flag);
+
+/* asm banking helper */
+void sil_memcpy(uint8_t isread, uint8_t map, uint16_t dptr, uint16_t block, uint16_t dev);
+
+#endif /* __DEVRD_DOT_H__ */
+
diff --git a/Kernel/platform-mtx/devtty.c b/Kernel/platform-mtx/devtty.c
new file mode 100644 (file)
index 0000000..12ae04b
--- /dev/null
@@ -0,0 +1,166 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <devtty.h>
+#include <vt.h>
+#include <tty.h>
+
+#undef  DEBUG                  /* UNdefine to delete debug code sequences */
+
+__sfr __at 0x0C serialAd;
+__sfr __at 0x0D serialAc;
+__sfr __at 0x0E serialBd;
+__sfr __at 0x0F serialBc;
+
+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}
+};
+
+/* tty1 is the screen tty2 is the debug port */
+
+/* Output for the system console (kprintf etc) */
+void kputchar(char c)
+{
+       /* Debug port for bringup */
+       if (c == '\n')
+               tty_putc(2, '\r');
+       tty_putc(2, c);
+}
+
+/* Both console and debug port are always ready */
+bool tty_writeready(uint8_t minor)
+{
+       minor;
+       return 1;
+}
+
+void tty_putc(uint8_t minor, unsigned char c)
+{
+       minor;
+
+       if (minor == 1) {
+               vtoutput(&c, 1);
+               return;
+       }
+       serialAd = c;
+}
+
+int tty_carrier(uint8_t minor)
+{
+       minor;
+       return 1;
+}
+
+void tty_setup(uint8_t minor)
+{
+       minor;
+}
+
+static uint16_t keymap[8];
+static uint16_t keyin[8];
+static uint8_t keybyte, keybit;
+static uint8_t newkey;
+static int keysdown = 0;
+static uint16_t shiftmask[8] = {
+       0, 0, 1, 0, 1, 0, 63, 0
+};
+__sfr __at 0x05 keyport;
+__sfr __at 0x06 keyporth;
+
+static void keyproc(void)
+{
+       int i;
+       uint8_t key;
+
+       for (i = 0; i < 8; i++) {
+               /* Set the row */
+               keyport = 0xff - (1 << i);
+               /* Read the matrix lines - 10 bit wide */
+               keyin[i] = (keyport | ((uint16_t)keyporth << 8)) ^ 0xffff;
+               key = keyin[i] ^ keymap[i];
+               if (key) {
+                       int n;
+                       int m = 1;
+                       for (n = 0; n < 10; n++) {
+                               if ((key & m) && (keymap[i] & m)) {
+                                       if (!(shiftmask[i] & m))
+                                               keysdown--;
+                               }
+                               if ((key & m) && !(keymap[i] & m)) {
+                                       if (!(shiftmask[i] & m))
+                                               keysdown++;
+                                       keybyte = i;
+                                       keybit = n;
+                                       newkey = 1;
+                               }
+                               m += m;
+
+                       }
+               }
+               keymap[i] = keyin[i];
+       }
+}
+
+static uint8_t keyboard[8][10] = {
+       {'1', '3', '5', '7', '9' , '-', '\\', 0/*page */, 3/*brk*/, 0/*f1*/},
+       { 27, '2', '4', '6', '8', '0', '^', 0/*eol*/, 8, 0/*f5*/},
+       { 0/*ctrl*/, 'w', 'r', 'y', 'i', 'p', '[', 0/*up*/, 9, 0/*f2*/ },
+       {'q', 'e', 't' , 'u', 'o', '@', 10, 8/*left*/, 127, 0 /* f6 */ },
+       { 0/*capsl*/, 's', 'f', 'h', 'k', ';', ']', 0/*right*/, 0, 0/*f7*/ },
+       { 'a', 'd', 'g', 'j', 'l', ':', 13, 12/*home*/, 0, 0 /*f3 */ },
+       { 0/*shift*/, 'x', 'v', 'n', ',', '/', 0/*shift*/, 0/*down*/,0 , 0 /*f8 */},
+       {'z', 'c', 'b', 'm', '.', '_', 0/*ins*/, 0/*cls*/, ' ', 0 /* f4 */ }
+};
+
+static uint8_t shiftkeyboard[8][10] = {
+       {'!', '#', '%', '\'', ')' , '=', '|', 0/*page */, 3/*brk*/, 0/*f1*/},
+       { 27, '"', '$', '&', '(', 0, '~', 0/*eol*/, 8, 0/*f5*/},
+       { 0/*ctrl*/, 'w', 'r', 'y', 'i', 'p', '{', 0/*up*/, 9, 0/*f2*/ },
+       {'q', 'e', 't' , 'u', 'o', '`', 10, 8/*left*/, 127, 0 /* f6 */ },
+       { 0/*capsl*/, 's', 'f', 'h', 'k', '+', '}', 0/*right*/, 0, 0/*f7*/ },
+       { 'a', 'd', 'g', 'j', 'l', '*', 13, 12/*home*/, 0, 0 /*f3 */ },
+       { 0/*shift*/, 'x', 'v', 'n', '>', '/', 0/*shift*/, 0/*down*/,0 , 0 /*f8 */},
+       {'z', 'c', 'b', 'm', '<', '_', 0/*ins*/, 0/*cls*/, ' ', 0 /* f4 */ }
+};
+
+static uint8_t capslock = 0;
+
+static void keydecode(void)
+{
+       uint8_t c;
+
+       if (keybyte == 4 && keybit == 0) {
+               capslock = 1 - capslock;
+               return;
+       }
+
+       if (keymap[6] & 65)     /* shift */
+               c = shiftkeyboard[keybyte][keybit];
+       else
+               c = keyboard[keybyte][keybit];
+       if (keymap[2] & 1) {    /* control */
+               if (c > 31 && c < 96)
+                       c &= 31;
+       }
+       if (capslock && c >= 'a' && c <= 'z')
+               c -= 'a' - 'A';
+       tty_inproc(1, c);
+}
+
+void kbd_interrupt(void)
+{
+       newkey = 0;
+       keyproc();
+       if (keysdown < 3 && newkey)
+               keydecode();
+}
+
+/* This is used by the vt asm code, but needs to live in the kernel */
+uint16_t cursorpos;
+
diff --git a/Kernel/platform-mtx/devtty.h b/Kernel/platform-mtx/devtty.h
new file mode 100644 (file)
index 0000000..f3fa258
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __DEVTTY_DOT_H__
+#define __DEVTTY_DOT_H__
+
+extern void kbd_interrupt(void);
+
+#endif
diff --git a/Kernel/platform-mtx/floppy.s b/Kernel/platform-mtx/floppy.s
new file mode 100644 (file)
index 0000000..ac1e4a1
--- /dev/null
@@ -0,0 +1,364 @@
+;
+;      Core floppy routines for the Memotech SDX (WD17xx)
+;      Based on the 6809 code
+;
+;      FIXME: better drive spin up wait
+;      FIXME: double sided media
+;      FIXME: correct step rates (per drive ?)
+;      FIXME: precompensation
+;
+;
+       .module floppy
+
+       .globl _fd_reset
+       .globl _fd_operation
+       .globl _fd_motor_on
+       .globl _fd_motor_off
+
+FDCREG .equ    0x10
+FDCTRK .equ    0x11
+FDCSEC .equ    0x12
+FDCDATA        .equ    0x13
+FDCCTRL        .equ    0x14
+;
+;      interrupt register reports 0x80 for interrut, 0x40 for drq
+;      (0x20 is the unrelated reset button)
+;
+
+;
+;      Structures we use
+;
+;      Command issue
+;
+CMD    .equ    0
+TRACK  .equ    1
+SECTOR .equ    2
+DIRECT .equ    3               ; 0 = read 2 = write 1 = status
+DATA   .equ    4
+
+       .area   _COMMONMEM
+;
+;      Simple routine for pauses
+;
+nap:   dec     bc
+       ld      a, b
+       or      c
+       jr      nz, nap
+       ret
+
+;
+;      Wait for the drive controller to become ready
+;      Preserve HL, DE
+;
+waitdisk:
+       ld      bc, #0
+waitdisk_l:
+       in      a, (FDCREG)
+       bit     0, a
+       ret     z
+       ;
+       ;       Keep poking fdcctrl to avoid a hardware motor timeout
+       ;
+       djnz    waitdisk_l
+       dec     c
+       jr      nz, waitdisk_l
+       ld      a, #0xD0        ; reset
+       out     (FDCREG), a
+       ex      (sp),hl
+       ex      (sp),hl
+       ex      (sp),hl
+       ex      (sp),hl
+       in      a, (FDCREG)             ; read to reset int status
+       bit     0, a
+       ret
+;
+;      Set up and perform a disk operation
+;
+;      IX points to the command block
+;      HL points to the buffer
+;      DE points to the track reg copy
+;
+fdsetup:
+       ld      a, (de)
+       out     (FDCTRK), a
+       cp      TRACK(ix)
+       jr      z, fdiosetup
+
+       ;
+       ;       So we can verify
+       ;
+       ld      a, SECTOR(ix)
+       out     (FDCSEC), a
+       ;
+       ;       Need to seek the disk
+       ;
+       ld      a, #0x14        ; seek
+       out     (FDCREG), a
+       ex      (sp),hl
+       ex      (sp),hl
+       ex      (sp),hl
+       ex      (sp),hl
+       call    waitdisk
+       jr      nz, setuptimeout
+       and     #0x18           ; error bits
+       jr      z, fdiosetup
+       ; seek failed, not good
+setuptimeout:                  ; NE = bad
+       ld      a, #0xff        ; we have no idea where we are, force a seek
+       ld      (de), a         ; zap track info
+       ret
+;
+;      Head in the right place
+;
+fdiosetup:
+       ld      a, TRACK(ix)
+       ld      (de), a         ; save track
+;      cmp     #22             ; FIXME
+;      jr      nc, noprecomp
+;      ld      a, (fdcctrl)
+;      or      #0x10           ; Precomp on
+;      jr      precomp1
+;noprecomp:
+       ld      a, (fdcctrl)
+;precomp1:
+       bit     3, SECTOR(ix)   ; check if we need side 1
+       jr      nz, fdio_s1
+       res     1, a
+       jr      fdio_setsec
+fdio_s1:set    1, a
+fdio_setsec:
+       out     (FDCCTRL), a
+       ld      a, SECTOR(ix)
+       and     #7              ; remove side bit
+       out     (FDCSEC), a
+       in      a, (FDCREG)     ; Clear any pending status
+
+       ld      a, CMD(ix)
+
+       ld      de, #0          ; timeout handling
+       
+       out     (FDCREG), a     ; issue the command
+       ex      (sp),hl ; give the FDC a moment to think
+       ex      (sp),hl
+       ex      (sp),hl
+       ex      (sp),hl
+       ld      a, DIRECT(ix)
+       dec     a
+       ld      a, (fdcctrl)
+       ld      d, a                    ; we need this in a register
+                                       ; to meet timing
+       set     6,d                     ; halt mode bit
+       jr      z, fdio_in
+       jr      nc, fdio_out
+;
+;      Status registers
+;
+fdxferdone:
+       ei
+fdxferdone2:
+       in      a, (FDCREG)
+       and     #0x19           ; Error bits + busy
+       bit     0, a            ; Wait for busy to drop, return in a
+       ret     z
+       ld      a, (fdcctrl)
+       out     (FDCCTRL), a
+       jr      fdxferdone2
+;
+;      Write to the disk - HL points to the target buffer
+;
+fdio_in:
+       ld      e, #0x16                ; bits to check
+       ld      bc, #FDCDATA            ; 256 bytes/sector, c is our port
+fdio_inl:
+       in      a, (FDCREG)             ; wait for data ready
+       and     e
+       jr      z, fdio_inl
+       di
+       ini                             ; grab and go
+fdio_inl2:
+       in      a, (FDCREG)
+       and     e
+       jr      z, fdio_inl2
+       ini
+       jr      nz, fdio_inl2
+       jr      fdxferdone
+
+;
+;      Read from the disk - HL points to the target buffer
+;
+fdio_out:
+       ld      bc, #FDCDATA            ; 256 bytes/sector, c is our port
+       ld      e, #0x76
+fdio_outl:
+       in      a, (FDCREG)             ; Wait for DRQ (or error)
+       and     e
+       jr      z, fdio_outl
+       outi                            ; Stuff byte into FDC while we think
+       di
+       in      a, (FDCREG)             ; No longer busy ??
+       bit     0,a
+       jr      nz, fdio_outbyte
+fdxferbad:                             ; Bugger... 
+       ld      a, #0xff
+       ret
+fdio_outbyte:
+       in      a, (FDCREG)
+       and     e
+       jr      z, fdio_outbyte
+       outi
+       jr      nz, fdio_outbyte
+       jr      fdxferdone
+
+
+;
+;      C glue interface.
+;
+;      Because of the brain dead memory paging we dump the bits into
+;      kernel space always. The thought of taking an NMI while in the
+;      user memory and bank flipping to recover is just too odious !
+;
+
+;
+;      Reset to track 0, wait for the command then idle
+;
+;      fd_reset(uint8_t *drvptr)
+;
+_fd_reset:
+       pop     de
+       pop     hl
+       push    hl
+       push    de
+       ld      a, (fdcctrl)
+       out     (FDCCTRL), a
+       ld      a, #1
+       out     (FDCSEC), a
+       xor     a
+       out     (FDCTRK), a
+       out     (FDCREG), a     ; restore
+       dec     a
+       ld      (hl), a         ; Zap track pointer
+       ex      (sp),hl         ; give the FDC a moment to think
+       ex      (sp),hl
+       ex      (sp),hl
+       ex      (sp),hl
+       
+       call    waitdisk
+       cp      #0xff
+       ret     z
+       and     #0x10           ; Error bit from the reset
+       ret     nz
+       ld      (hl), a         ; Track 0 correctly hit
+       ret
+;
+;      fd_operation(uint16_t *cmd, uint16_t *drive)
+;
+;      The caller must ensure the drive has been selected and the motor is
+;      running.
+;
+_fd_operation:
+       pop     bc              ; return address
+       pop     hl              ; command
+       pop     de              ; drive track ptr
+       push    de
+       push    hl
+       push    bc
+       push    ix
+       push    hl
+       pop     ix
+       ld      l, DATA(ix)
+       ld      h, DATA+1(ix)
+       call    fdsetup         ; Set up for a command
+       ld      l, a
+       ld      h, #0
+       pop     ix
+       ret
+;
+;      C interface fd_motor_on(uint16_t drivesel)
+;
+;      Selects this drive and turns on the motors. Also pass in the
+;      choice of density
+;
+;      bit 0: drive select
+;      bit 1: side select
+;      bit 2: motor on
+;      bit 3: motor ready
+;      bit 4:
+;
+;
+_fd_motor_on:
+       pop     de
+       pop     hl
+       push    hl
+       push    de
+       ;
+       ;       Select drive B, turn on motor if needed
+       ;
+       ld      a,(motor_running)       ; nothing selected
+       or      a
+       jr      z, notsel
+
+       cp      l
+       jr      z,  motor_was_on
+;
+;      Select our drive
+;
+notsel:
+       ld      h, a            ; save state as it was
+       or      l
+       out     (FDCCTRL), a
+       ld      (fdcctrl), a
+       bit     2, h            ; FIXME - motor bit
+       jr      nz, motor_was_on
+       ld      bc, #8000
+motorwait:
+       in      a, (FDCCTRL)
+       bit     3, a
+       jr      nz, motor_good
+       dec     bc
+       ld      a, b
+       or      c
+       jr      nz, motorwait
+;
+;      Timed out
+;
+       ld      hl, #-1
+       ret
+;
+;      All is actually good ? 
+;
+;      If we find the motor is not good try spinning up
+;
+motor_was_on:
+       in      a, (FDCCTRL)
+       bit     3,a
+       jr      z, notsel
+       
+motor_good:
+       ld      hl, #0
+       ret
+
+;
+;      C interface fd_motor_off(void)
+;
+;      Turns off the drive motors, deselects all drives
+;
+_fd_motor_off:
+       ld      a, (motor_running)
+       or      a
+       ret     z
+       ; Should we seek to track 0 ?
+       in      a, (FDCCTRL)
+       res     2,a
+       out     (FDCCTRL), a
+       xor     a
+       ld      (motor_running), a
+       ret
+
+       .area _COMMONDATA
+curdrive:
+       .db     0xff
+motor_running:
+       .db     0
+fdcctrl:
+       .db     0
+  
\ No newline at end of file
diff --git a/Kernel/platform-mtx/kernel.def b/Kernel/platform-mtx/kernel.def
new file mode 100644 (file)
index 0000000..66cb6d4
--- /dev/null
@@ -0,0 +1,12 @@
+; UZI mnemonics for memory addresses etc
+
+U_DATA                      .equ 0xC000       ; (this is struct u_data from kernel.h)
+U_DATA__TOTALSIZE           .equ 0x300        ; 256+256+256 bytes.
+
+U_DATA_STASH               .equ 0xBD00       ; BD00-BFFF
+
+NMOS_Z80                   .equ 0
+
+VRAM_CH                            .equ 3            ; font data 0x1800-1BFF ?
+
+
diff --git a/Kernel/platform-mtx/main.c b/Kernel/platform-mtx/main.c
new file mode 100644 (file)
index 0000000..9265022
--- /dev/null
@@ -0,0 +1,41 @@
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+
+uint16_t ramtop = PROGTOP;
+uint16_t vdpport = 0x01 + 256 * 40;    /* port and width */
+
+void pagemap_init(void)
+{
+ int i;
+ /* Ten banks (should check memory size) FIXME */
+ for (i = 0x81; i < 0x8A; i++)
+  pagemap_add(i);
+}
+
+/* On idle we spin checking for the terminals. Gives us more responsiveness
+   for the polled ports */
+void platform_idle(void)
+{
+  /* We don't want an idle poll and IRQ driven tty poll at the same moment */
+  irqflags_t irq = di();
+//  tty_pollirq(); 
+  irqrestore(irq);
+}
+
+void platform_interrupt(void)
+{
+ kbd_interrupt();
+ timer_interrupt();
+}
+
+/* Nothing to do for the map of init */
+void map_init(void)
+{
+}
+
+void do_beep(void)
+{
+}
diff --git a/Kernel/platform-mtx/mtx.s b/Kernel/platform-mtx/mtx.s
new file mode 100644 (file)
index 0000000..bf73df8
--- /dev/null
@@ -0,0 +1,229 @@
+;
+;      Z80Pack hardware support
+;
+;
+;      This goes straight after udata for common. Because of that the first
+;      256 bytes get swapped to and from disk with the uarea (512 byte disk
+;      blocks). This isn't a problem but don't put any variables in here.
+;
+;      If you make this module any shorter, check what follows next
+;
+
+
+            .module mtx
+
+            ; exported symbols
+            .globl init_early
+            .globl init_hardware
+            .globl _program_vectors
+            .globl _system_tick_counter
+           .globl platform_interrupt_all
+
+           .globl map_kernel
+           .globl map_process
+           .globl map_process_always
+           .globl map_save
+           .globl map_restore
+
+           .globl _sil_memcpy
+
+           .globl _kernel_flag
+
+            ; exported debugging tools
+            .globl _trap_monitor
+            .globl outchar
+
+            ; imported symbols
+            .globl _ramsize
+            .globl _procmem
+
+           .globl unix_syscall_entry
+            .globl null_handler
+           .globl nmi_handler
+            .globl interrupt_handler
+
+            .globl outcharhex
+            .globl outhl, outde, outbc
+            .globl outnewline
+            .globl outstring
+            .globl outstringhex
+
+            .include "kernel.def"
+            .include "../kernel.def"
+
+; -----------------------------------------------------------------------------
+; COMMON MEMORY BANK (0xC000 upwards)
+; -----------------------------------------------------------------------------
+            .area _COMMONMEM
+
+_trap_monitor:
+           di
+           halt
+
+_trap_reboot:
+           di
+           xor a
+           out (0),a           ; ROM mode, we are in common so survive
+           rst 0               ; kaboom
+
+; -----------------------------------------------------------------------------
+; KERNEL MEMORY BANK (below 0xC000, only accessible when the kernel is mapped)
+; -----------------------------------------------------------------------------
+            .area _CODE
+
+init_early:
+            ret
+
+init_hardware:
+           ; FIXME: do proper size checker
+            ; set system RAM size (hardcoded for now)
+            ld hl, #480
+            ld (_ramsize), hl
+            ld hl, #(480-48)           ; 64K for kernel
+            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
+
+           ; FIXME: set up interrupt timer on the CTC
+           ; 08 is channel 0, which is input for vdp
+            ; 09 is channel 1, output for DART ser 0 } fed 4MHz/13
+            ; 0A is channel 2, output for DATA ser 1 }
+           ; 0B is channel 3, counting CSTTE edges (cpu clocks) at 4MHz
+           ; 0C-0F are A data, B data, A ctrl, B ctrl 
+
+            im 1 ; set CPU interrupt mode
+            ret
+
+_sil_memcpy:
+           push ix
+           ld ix, #0
+           add ix, sp
+           ld l, 6(ix) ; dptr
+           ld h, 7(ix)
+           ld a, 5(ix) ; map
+           ld e, 8(ix) ; block
+           ld d, 9(ix)
+           call map_process_a  ; map in the user space we want
+           ld c, 11(ix) ; port base
+           out (c), e   ; block low
+           inc c
+           out (c), d   ; block high
+           inc c
+           inc c
+           ld b, #0
+           bit 0, 4(ix) ; read ? 
+           jr z, sil_mwrite
+           inir         ; load 256 bytes
+           inir         ; load 256 bytes
+sil_copydone:
+           call map_kernel
+           pop ix
+           ret
+sil_mwrite:
+           otir        ; write 256 bytes
+           otir        ; write 256 bytes
+           jr sil_copydone
+
+;------------------------------------------------------------------------------
+; COMMON MEMORY PROCEDURES FOLLOW
+
+            .area _COMMONMEM
+
+
+_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
+
+            ; write zeroes across all vectors
+            ld hl, #0
+            ld de, #1
+            ld bc, #0x007f ; program first 0x80 bytes only
+            ld (hl), #0x00
+            ldir
+
+            ; now install the interrupt vector at 0x0038
+            ld a, #0xC3 ; JP instruction
+            ld (0x0038), a
+            ld hl, #interrupt_handler
+            ld (0x0039), hl
+
+            ; set restart vector for UZI system calls
+            ld (0x0030), a   ;  (rst 30h is unix function call vector)
+            ld hl, #unix_syscall_entry
+            ld (0x0031), hl
+
+            ; Set vector for jump to NULL
+            ld (0x0000), a   
+            ld hl, #null_handler  ;   to Our Trap Handler
+            ld (0x0001), hl
+
+            ld (0x0066), a  ; Set vector for NMI
+            ld hl, #nmi_handler
+            ld (0x0067), hl
+
+           ; our platform has a "true" common area, if it did not we would
+           ; need to copy the "common" code into the common area of the new
+           ; process.
+
+           ; falls through
+
+            ; put the paging back as it was -- we're in kernel mode so this is predictable
+map_kernel:
+           push af
+           ld a, #0x80         ; ROM off bank 0
+           ; the map port is write only, so keep a local stash
+           ld (map_save), a
+           out (0), a
+           pop af
+            ret
+map_process:
+           ld a, h
+           or l
+           jr z, map_kernel
+           ld a, (hl)
+map_process_a:
+           ld (map_copy), a
+           out (0), a
+           ret
+map_process_always:
+           push af
+           ld a, (U_DATA__U_PAGE)
+           ld (map_copy), a
+           out (0), a
+           pop af
+           ret
+map_save:
+           push af
+           ld a, (map_copy)
+           ld (map_store), a
+           pop af
+           ret     
+map_restore:
+           push af
+           ld a, (map_store)
+           out (0), a
+           pop af
+           ret     
+map_store:
+           .db 0
+map_copy:
+           .db 0
+_kernel_flag:
+           .db 1
+
+; outchar: Wait for UART TX idle, then print the char in A
+; destroys: AF
+outchar:
+           out (0x0c), a
+            ret
diff --git a/Kernel/platform-mtx/tricks.s b/Kernel/platform-mtx/tricks.s
new file mode 100644 (file)
index 0000000..afeb1ab
--- /dev/null
@@ -0,0 +1,318 @@
+;
+;      This is heavily based on the Z80Pack platform code. Only the
+; constants have changed.
+;
+        .module tricks
+
+        .globl _ptab_alloc
+        .globl _newproc
+        .globl _chksigs
+        .globl _getproc
+        .globl _trap_monitor
+        .globl trap_illegal
+        .globl _inint
+        .globl _switchout
+        .globl _switchin
+        .globl _doexec
+        .globl _dofork
+        .globl _runticks
+        .globl unix_syscall_entry
+        .globl interrupt_handler
+        .globl dispatch_process_signal
+       .globl _swapper
+
+        ; imported debug symbols
+        .globl outstring, outde, outhl, outbc, outnewline, outchar, outcharhex
+
+        .include "kernel.def"
+        .include "../kernel.def"
+
+        .area _COMMONMEM
+
+; Switchout switches out the current process, finds another that is READY,
+; possibly the same process, and switches it in.  When a process is
+; restarted after calling switchout, it thinks it has just returned
+; from switchout().
+; 
+; This function can have no arguments or auto variables.
+_switchout:
+        di
+        call _chksigs
+        ; save machine state
+
+        ld hl, #0 ; return code set here is ignored, but _switchin can 
+        ; return from either _switchout OR _dofork, so they must both write 
+        ; U_DATA__U_SP with the following on the stack:
+        push hl ; return code
+        push ix
+        push iy
+        ld (U_DATA__U_SP), sp ; this is where the SP is restored in _switchin
+
+        ; set inint to false
+        xor a
+        ld (_inint), a
+
+       ; Stash the uarea back into process memory
+       ld hl, (U_DATA__U_PAGE)
+       ld a, l
+       out (0), a
+       ld hl, #U_DATA
+       ld de, #U_DATA_STASH
+       ld bc, #U_DATA__TOTALSIZE
+       ldir
+       ld a, #0x80             ; kernel
+       out (0), a
+
+        ; find another process to run (may select this one again)
+        call _getproc
+
+        push hl
+        call _switchin
+
+        ; we should never get here
+        call _trap_monitor
+
+badswitchmsg: .ascii "_switchin: FAIL"
+            .db 13, 10, 0
+swapped: .ascii "_switchin: SWAPPED"
+            .db 13, 10, 0
+
+_switchin:
+        di
+        pop bc  ; return address
+        pop de  ; new process pointer
+;
+;      FIXME: do we actually *need* to restore the stack !
+;
+        push de ; restore stack
+        push bc ; restore stack
+
+       ld a, #0x80
+       out (0), a      ; kernel
+
+       push de
+        ld hl, #P_TAB__P_PAGE_OFFSET
+       add hl, de      ; process ptr
+       pop de
+
+        ld a, (hl)
+
+       or a
+       jr nz, not_swapped
+
+       ;
+       ;       We are still on the departing processes stack, which is
+       ;       fine for now.
+       ;
+       ld sp, #_swapstack
+       push hl
+       push de
+       call _swapper
+       pop de
+       pop hl
+       ld a, (hl)
+
+not_swapped:
+       ; Pages please !
+       out (0), a
+
+        ; bear in mind that the stack will be switched now, so we can't use it
+       ; to carry values over this point
+
+       exx                     ; thank goodness for exx 8)
+       ld hl, #U_DATA_STASH
+       ld de, #U_DATA
+       ld bc, #U_DATA__TOTALSIZE
+       ldir
+       exx
+
+       ld a, #0x80             ; kernel back please
+       out (0), a
+        
+        ; check u_data->u_ptab matches what we wanted
+        ld hl, (U_DATA__U_PTAB) ; u_data->u_ptab
+        or a                    ; clear carry flag
+        sbc hl, de              ; subtract, result will be zero if DE==IX
+        jr nz, switchinfail
+
+       ; wants optimising up a bit
+       ld ix, (U_DATA__U_PTAB)
+        ; next_process->p_status = P_RUNNING
+        ld P_TAB__P_STATUS_OFFSET(ix), #P_RUNNING
+
+       ; Fix the moved page pointers
+       ; Just do one byte as that is all we use on this platform
+       ld a, P_TAB__P_PAGE_OFFSET(ix)
+       ld (U_DATA__U_PAGE), a
+        ; runticks = 0
+        ld hl, #0
+        ld (_runticks), hl
+
+        ; restore machine state -- note we may be returning from either
+        ; _switchout or _dofork
+        ld sp, (U_DATA__U_SP)
+
+        pop iy
+        pop ix
+        pop hl ; return code
+
+        ; enable interrupts, if the ISR isn't already running
+        ld a, (_inint)
+        or a
+        ret z ; in ISR, leave interrupts off
+        ei
+        ret ; return with interrupts on
+
+switchinfail:
+       call outhl
+        ld hl, #badswitchmsg
+        call outstring
+       ; something went wrong and we didn't switch in what we asked for
+        jp _trap_monitor
+
+fork_proc_ptr: .dw 0 ; (C type is struct p_tab *) -- address of child process p_tab entry
+
+;
+;      Called from _fork. We are in a syscall, the uarea is live as the
+;      parent uarea. The kernel is the mapped object.
+;
+_dofork:
+        ; always disconnect the vehicle battery before performing maintenance
+        di ; should already be the case ... belt and braces.
+
+        pop de  ; return address
+        pop hl  ; new process p_tab*
+        push hl
+        push de
+
+        ld (fork_proc_ptr), hl
+
+        ; prepare return value in parent process -- HL = p->p_pid;
+        ld de, #P_TAB__P_PID_OFFSET
+        add hl, de
+        ld a, (hl)
+        inc hl
+        ld h, (hl)
+        ld l, a
+
+        ; Save the stack pointer and critical registers.
+        ; When this process (the parent) is switched back in, it will be as if
+        ; it returns with the value of the child's pid.
+        push hl ; HL still has p->p_pid from above, the return value in the parent
+        push ix
+        push iy
+
+        ; save kernel stack pointer -- when it comes back in the parent we'll be in
+        ; _switchin which will immediately return (appearing to be _dofork()
+       ; returning) and with HL (ie return code) containing the child PID.
+        ; Hurray.
+        ld (U_DATA__U_SP), sp
+
+        ; now we're in a safe state for _switchin to return in the parent
+       ; process.
+
+       ; Need to write a new 47.25K bank copy here, then copy the live uarea
+       ; into the stash of the new process
+
+        ; --------- copy process ---------
+
+        ld hl, (fork_proc_ptr)
+        ld de, #P_TAB__P_PAGE_OFFSET
+        add hl, de
+        ; load p_page
+        ld c, (hl)
+       ; load existing page ptr
+       push af
+       ld a, c
+       call outcharhex
+       pop af
+       ld a, (U_DATA__U_PAGE)
+
+       call bankfork                   ;       do the bank to bank copy
+
+       ; Copy done
+
+       ld a, (U_DATA__U_PAGE)  ; parent memory
+       out (0), a              ; Switch context to parent
+
+       ; We are going to copy the uarea into the parents uarea stash
+       ; we must not touch the parent uarea after this point, any
+       ; changes only affect the child
+       ld hl, #U_DATA          ; copy the udata from common into the
+       ld de, #U_DATA_STASH    ; target process
+       ld bc, #U_DATA__TOTALSIZE
+       ldir
+       ; Return to the kernel mapping
+       ld a, #0x80
+       out (0), a
+        ; now the copy operation is complete we can get rid of the stuff
+        ; _switchin will be expecting from our copy of the stack.
+        pop bc
+        pop bc
+        pop bc
+
+        ; Make a new process table entry, etc.
+        ld  hl, (fork_proc_ptr)
+        push hl
+        call _newproc
+        pop bc 
+
+        ; runticks = 0;
+        ld hl, #0
+        ld (_runticks), hl
+        ; in the child process, fork() returns zero.
+       ;
+       ; And we exit, with the kernel mapped, the child now being deemed
+       ; to be the live uarea. The parent is frozen in time and space as
+       ; if it had done a switchout().
+        ret
+
+;
+;      This is related so we will keep it here. Copy the process memory
+;      for a fork. a is the page base of the parent, c of the child
+;
+;      Assumption - fits into a fixed number of whole 256 byte blocks
+;
+bankfork:
+;      ld bc, #(0xC000 - 768)          ;       48K minus the uarea stash
+
+       ld b, #0xBD             ; C0 x 256 minus 3 sets for the uarea stash
+       ld hl, #0               ; base of memory to fork (vectors included)
+bankfork_1:
+       push bc                 ; Save our counter and also child offset
+       push hl
+       out (0), a              ; switch to parent bank
+       ld de, #bouncebuffer
+       ld bc, #256
+       ldir                    ; copy into the bounce buffer
+       pop de                  ; recover source of copy to bounce
+                               ; as destination in new bank
+       pop bc                  ; recover child page number
+       push bc
+       ld b, a                 ; save the parent bank id
+       ld a, c                 ; switch to the child
+       out (0), a
+       push bc                 ; save the bank pointers
+       ld hl, #bouncebuffer
+       ld bc, #256
+       ldir                    ; copy into the child
+       pop bc                  ; recover the bank pointers
+       ex de, hl               ; destination is now source for next bank
+       ld a, b                 ; parent bank is wanted in a
+       pop bc
+       djnz bankfork_1         ; rinse, repeat
+       ret
+
+;
+;      For the moment
+;
+bouncebuffer:
+       .ds 256
+;
+;      We can keep a stack in common because we will complete our
+;      use of it before we switch common block. In this case we have
+;      a true common so it's even easier. This can share with the bounce
+;      buffer used by bankfork as we won't switchin mid way through the
+;      banked fork() call.
+;
+_swapstack:
diff --git a/Kernel/platform-mtx/uzi.lnk b/Kernel/platform-mtx/uzi.lnk
new file mode 100644 (file)
index 0000000..45c2417
--- /dev/null
@@ -0,0 +1,40 @@
+-mwxuy
+-i uzi.ihx
+-b _CODE=0x0100
+-b _COMMONMEM=0xC000
+-l z80
+platform-mtx/crt0.rel
+platform-mtx/commonmem.rel
+platform-mtx/mtx.rel
+platform-mtx/main.rel
+start.rel
+version.rel
+lowlevel-z80.rel
+usermem_std-z80.rel
+platform-mtx/tricks.rel
+timer.rel
+kdata.rel
+usermem.rel
+platform-mtx/devfd.rel
+platform-mtx/floppy.rel
+platform-mtx/devsil.rel
+platform-mtx/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
+vt.rel
+platform-mtx/vdp.rel
+mm.rel
+bankfixed.rel
+swap.rel
+devsys.rel
+platform-mtx/devlpr.rel
+platform-mtx/devtty.rel
+-e
diff --git a/Kernel/platform-mtx/vdp.s b/Kernel/platform-mtx/vdp.s
new file mode 100644 (file)
index 0000000..dd7dd3b
--- /dev/null
@@ -0,0 +1,16 @@
+            .module vdp
+
+            .include "kernel.def"
+            .include "../kernel.def"
+
+           .include "../dev/vdp1.s"
+
+
+           .area _COMMONMEM
+
+;
+;      FIXME: should use vdpport, but right now vdpport is in data not
+;      common space.
+;
+platform_interrupt_all:
+           ret