px4plus: Further updates
authorAlan Cox <alan@linux.intel.com>
Fri, 27 Mar 2015 20:13:00 +0000 (20:13 +0000)
committerAlan Cox <alan@linux.intel.com>
Fri, 27 Mar 2015 20:13:00 +0000 (20:13 +0000)
This fleshes out the task switching, splits up the various ROM and cartridge
logic and begins to put the rest of the system together

15 files changed:
Kernel/platform-px4plus/Makefile
Kernel/platform-px4plus/README
Kernel/platform-px4plus/config.h
Kernel/platform-px4plus/crt0.s
Kernel/platform-px4plus/devfd.c
Kernel/platform-px4plus/devfd.h
Kernel/platform-px4plus/devices.c
Kernel/platform-px4plus/fuzix.lnk
Kernel/platform-px4plus/main.c
Kernel/platform-px4plus/px4plus.s
Kernel/platform-px4plus/romdisc.s [new file with mode: 0644]
Kernel/platform-px4plus/sio.c [new file with mode: 0644]
Kernel/platform-px4plus/sio.h [new file with mode: 0644]
Kernel/platform-px4plus/swapdev.s [new file with mode: 0644]
Kernel/platform-px4plus/tricks.s

index 068d17b..7bb6c68 100644 (file)
@@ -1,5 +1,5 @@
 
-CSRCS = devlpr.c devtty.c devfd.c
+CSRCS = devlpr.c devtty.c devfd.c sio.c
 CSRCS += devices.c
 
 CCSRCS = main.c
@@ -7,7 +7,7 @@ CCSRCS = main.c
 CDSRCS = init.c
 
 ASRCS = crt0.s px4plus.s video.s
-ASRCS += tricks.s commonmem.s
+ASRCS += tricks.s commonmem.s swapdev.s romdisc.s
 
 COBJS = $(CSRCS:.c=.rel)
 CCOBJS = $(CCSRCS:.c=.rel)
index 87db925..ad5d2ba 100644 (file)
@@ -3,44 +3,42 @@ A FUZIX target for the PX4plus (and PX4 with 128K RAM disc)
 Just playing to see if we can make it fit.
 
 The PX4Plus has 64K of RAM, and can overlay 6000-DFFF with one of two
-different ROMpacks (usually 'basic' and 'utility'). We build the kernel
-at 0x6000 but for now plonk it into RAM so we can debug it. The small 8K
-top window is awkward as we need to get udata and our kernel data/common in
-that space if possible. We can hide the font/video below that under the top of
-the ROM however.
+different ROMpacks (usually 'basic' and 'utility'). Our kernel is a two
+ROM set of 'P' type ROMs that can be plugged into the ROMpack sockets to
+give a resident CP/M app that can be run as "B:FUZIX"
+
 
 Banked Memory Map
 -----------------
 
 0x0000-0x00FF          Vectors (which IM ? PX8 is IM2)
-0x0100-0x5FFF          Kernel mappings
+0x0100-0x01FF          Needed by resident OS (or could rewrite bits and
+                       save them)
+0x0200-0x5FFF          Kernel mappings
 0x6000-0xDFFF          Switched segments 8/16/32K ROM x 2 or RAM
        0x6000-0xDFFF   Application space (32K) [need to use a bit under
                        as 120K not 128K of swap]
-       0x6000-0xDFFF   CODE1/CODE2 } Both with copies of some of common
-       0x6000-0xDFFF   CODE3/Video } and rodata at same address range
-       [ Do we want to generate interleaved banking ? ]
-
-0xE000-0xFCFF          Writable kernel data
-                       Framebuffer (4K)
-0xFD00-0xFFFF          UDATA
+       0x6000-0xDFFF   CODE1/CODE2
+       0x6000-0xDFFF   CODE3/Video/FONT
+       [ Do we want to generate interleaved banking or stubs in all banks ? ]
+       [ Could also save space by putting CONST at the top of both ROM
+         images ? ]
 
-We also need to put a catalogue in the middle of one of the two ROM blocks
-annoyingly. However that plays into our hands in other ways as we can
-minimally fake a disk rom holding a CP/M app which in fact runs the OS.
+0xE000-0xFBFF          Currently unused
+0xFC00-0xFFFF          Framebuffer (2K)
 
+We need to keep EF28 clear so we can set it to 1 for resident mode warm
+start when we do suspend/resume.
 
-Applications are swapped to/from the PX4Plus RAM disc (120K) allowing about
-4 apps of just under 32K each. Storage I/O is via the serial floppy and/or
-optional RAM/ROM cartriges. External 128K cartridges would also work for
-swap with floppy for OS. If the swap is custom handled in switching then
-we can switch the 32K rather than copy and gain another process, plus real
-floppy swap option.
+Applications are switched to/from the 128K side car or built in 128K ramdisc
+on the plus. Alternatively they can be switched to/from the 32K or 64K
+cartridge module on the PX4 (or in theory both).
 
-CP/M BIOS can be used (it's another 32K map over 0-7FFF, but as that maps
-over the vectors we must ensure its always called with interrupts off).
+Storage I/O is via the serial floppy and/or optional ROM cartriges. The
+floppy interface will also be usable for swap (once it works)
 
 The PX-8 is different: There is only a single 32K system ROM, but no video
 overhead. In theory its sufficient if we are replacing the OS ROM, and using
 the intelligent RAM disc, or the homebrew 512K one, plus floppies
 
+The PX4 has a parallel port, can we run an SD card off it ?
index da94d3c..b08190c 100644 (file)
 #define CONFIG_FONT8X8
 /* CP/M emulation */
 #undef CONFIG_CPM_EMU
-/* Fixed banking */
-#undef CONFIG_BANK_FIXED
+/* Fixed banking (although we must do magic in tricks.s to fake banking */
+#define CONFIG_BANK_FIXED
+#define MAX_MAPS       7
+#define MAP_SIZE       0x8000
 /* Swap only */
-#define CONFIG_SWAP_ONLY
-/* Simple user copies for now (change when ROM the kernel) */
-#define CONFIG_USERMEM_C
-#define BANK_KERNEL
-#define BANK_PROCESS
+#undef CONFIG_SWAP_ONLY
 
 /* Banks as reported to user space */
 #define CONFIG_BANKS   1
 
 /* FIXME: treat the banks of the ramdisc as memory not swap, also trim
    to 30K as only have 120K of RAMdisc */
-#define SWAP_SIZE   0x3C       /* 30K in blocks (with uarea means 29.25K max app size) */
+#define SWAP_SIZE   0x40       /* 32K in blocks (with uarea means 31.25K max app size) */
 #define SWAPBASE    (uint8_t *)0x5D00  /* We swap the lot in one, include the */
 #define SWAPTOP            (uint8_t *)0xDD00   /* vectors so its a round number of sectors */
-#define MAX_SWAPS      4       /* We have a whopping 120K of RAMDISC! */
+#define MAX_SWAPS      4       /* We have a whopping 128K of RAMDISC! */
 
 #define BOOT_TTY (512 + 1)/* Set this to default device for stdio, stderr */
                           /* In this case, the default is the first TTY device */
index 558ed26..e3f3dac 100644 (file)
         .globl l__DATA
         .globl kstack_top
 
-        ; startup code
         .area _CODE
-init:
-        di
+       ; Special headers for the type 'P' ROM
+
+       ; Entry 0 is a dummy directory entry holding the volume info
+       .db 0xE5                ; Empty
+       .db 0x50                ; Program
+       .db 0xA0                ; 2 x 32K ROM
+       .dw 0xFFFF              ; Checksum (but unused) - FIXME set this
+       .ascii 'H80'            ; Magic string
+       .ascii '*FUZIX OS ROM*'
+       .db 0x04                ; Four directory entries
+       .ascii 'V01'            ; Version
+       .ascii '032615'         ; so much for Y2K
+
+       ; Entry 1
+       .db 0x00                ; Directory entry
+       .ascii 'FUZIX   COM'    ; name of executable
+       .dw 0x00                ; Extents
+       .db 0x00                ; Reserved
+       .db 0x01                ; 1 record
+       .db 0x01,0x00,0x00,0x00 ; 16 blocks
+       .db 0x00,0x00,0x00,0x00
+       .db 0x00,0x00,0x00,0x00
+       .db 0x00,0x00,0x00,0x00
+
+       ; Entry 2
+       .db 0xE5
+       .ds 31                  ; 32 bytes per entry
+       ; Entry 3
+       .db 0xE5
+       .ds 31
+
+       ; Header of first block of "code"
+       .db 0xDD                ; indicate "run from ROM"
+       .db 0xDE
+       .db 0xC3, 0x0B, 0x01
+       jp coldstart
+       jp warmstart
+       ;
+       ;       Reference code
+       ;
+       .db 0x0E, 0x1A, 0x11, 0x3A, 0xF9, 0xCD, 0x05, 0x00
+       .db 0x21, 0x5C, 0x00, 0x11, 0x5D, 0x00, 0x01, 0x23
+       .db 0x00, 0xAF, 0x77, 0xED, 0xB0, 0x21, 0x59, 0x01
+       .db 0x11, 0x67, 0x00, 0x0E, 0x0B, 0xED, 0xB8, 0xCD
+       .db 0x99, 0xFF, 0x0E, 0x09, 0x11, 0x3E, 0x01, 0xCD
+       .db 0x05, 0x00, 0xAF, 0x32, 0x28, 0xEF, 0x0E, 0x00
+       .db 0xCD, 0x05, 0x00, 0x52, 0x4F, 0x4D, 0x20, 0x41
+       .db 0x43, 0x43, 0x49, 0x44, 0x45, 0x4E, 0x54, 0x20
+       .db 0x21, 0x21, 0x07, 0x24
+       ; Name
+       .ascii 'FUZIX   COM'
+
+
+
+        ; startup codeinit:
+coldstart:
+warmstart:                     ; Until we have suspend/resume done
         ld sp, #kstack_top
 
         ; Configure memory map
@@ -71,4 +125,4 @@ stop:   halt
 
        .area _STUBS
 stubs:
-       .ds 768
+       .ds 512
index e6778dc..f7bd4cc 100644 (file)
-/* 
+/*
  *     Disk driver
  */
 
 #include <kernel.h>
 #include <kdata.h>
 #include <printf.h>
+#include <devices.h>
 #include <devfd.h>
+#include <sio.h>
 
-static int fd_transfer(bool is_read, uint8_t minor, uint8_t rawflag);
-static int hd_transfer(bool is_read, uint8_t minor, uint8_t rawflag);
+#define FD_RESET       0x0D
+#define FD_READ                0x77
+#define FD_WRITE       0x78
+#define FD_WRITEHST    0x79    /* Flush buffer */
+#define FD_COPY                0x7A    /* Offline copy */
+/* 0x7B appears to have been redacted from docs ? */
+#define FD_FORMAT      0x7C    /* Format disk */
+
+#define FD_OK          0x00
+#define FD_ERR_READ    0xFA
+#define FD_ERR_WRITE   0xFB
+#define FD_ERR_DRIVESEL        0xFC
+#define FD_ERR_WPROT   0xFD
+
+/* Worst case size */
+static uint8_t buf[0x89];
+
+static void fd_reset(uint8_t minor)
+{
+    buf[0] = 0x00;
+    buf[1] = 0x30 + minor >> 1;
+    buf[2] = 0x23;
+    buf[3] = 0x0D;
+    buf[4] = 0x00;
+    buf[5] = 0x00;
+    sio_write(buf, 6);
+    sio_read(buf, 6);
+    if (buf[5])
+        kprintf("fd%d: reset error %d\n", minor, buf[5]);
+}
+
+int fd_transfer(uint8_t minor, bool is_read, uint8_t rawflag)
+{
+    blkno_t block;
+    uint16_t dptr;
+    uint16_t ct;
+    uint8_t tries;
+    uint16_t nblock;
+    staticfast uint8_t page;
+    staticfast int old_sio;
+    staticfast int err;
+
+    ct = 0;
+
+    if (rawflag == 0) {
+       dptr = (uint16_t)udata.u_buf->bf_data;
+       block = udata.u_buf->bf_blk << 2 ;
+       nblock = 4;
+       page = 0;               /* Kernel */
+    } else if (rawflag == 1) {
+       if (((uint16_t)udata.u_offset|udata.u_count) & BLKMASK)
+               goto bad2;
+       dptr = (uint16_t)udata.u_base;
+       nblock = udata.u_count >> 7;
+       block = udata.u_offset >> 7;    /* 128 bytes/sector */
+       page = udata.u_page;            /* User */
+    } else if (rawflag == 2) {
+       nblock = swapcnt >> 7;  /* in 128 byte chunks */
+       dptr = (uint16_t)swapbase;
+       page = swapproc->p_page;
+       block = swapblk << 2;
+    } else
+       goto bad;
+
+
+    old_sio = select_sio();
+
+    /* Loop over each 128 byte chunk */
+    while (ct < nblock) {
+        buf[0] = 0x00;
+        buf[1] = 0x31 + minor >> 1;    /* Which FDD ? */
+        buf[2] = 0x23;
+        buf[6] = (block >> 6);         /* 64 logical sectors/track */
+        buf[7] = (block & 63) + 1;     /* Sectors are 1 based */
+
+        for (tries = 0; tries < 4; tries ++) {
+            if (is_read) {
+                /* Write command to the drive, wait for reply */
+                buf[3] = FD_READ;
+                buf[4] = 0x02;
+                sio_write(buf, 8);
+                err = sio_read(buf, 0x86);
+                if (!err) {
+                    err = buf[0x86];
+                    if (!err)
+                        /* Buffer goes to user space for this process or
+                           to kernel. We always page in ourself */
+                        if (rawflag)
+                            _uput(buf + 0x05, (uint8_t *)dptr, 128);
+                        else
+                            memcpy((uint8_t *)dptr, buf + 0x05, 128);
+                }
+            } else {
+                /* Write the buffer and data, then wait for an ack */
+                buf[3] = FD_WRITE;
+                buf[4] = 0x83;
+                buf[8] = (((uint8_t)block) & 3) == 3 ? 0x00 : 0x02;
+                /* We need a special I/O helper for swapping out as we may
+                   be swapping memory from an I/O mapped ram device to
+                   the floppy disc */
+                read_from_bank(page, dptr, buf + 0x09, 128);
+                sio_write(buf, 0x89);
+                err = sio_read(buf, 0x06);
+                if (!err)
+                    err = buf[0x05];
+            }
+            /* If it worked no more retries */
+            if (err == 0)
+                break;
+            /* Errors not worth a retry */
+            if (err >= FD_ERR_DRIVESEL)
+                goto bad2;
+            /* Failed ? */
+            if (tries == 3)
+                goto bad2;
+            if (tries > 1)
+                fd_reset(minor);
+        }
+        /* Move on 128 bytes */
+        block++;
+        dptr += 128;
+        ct++;
+    }
+    deselect_sio(old_sio);
+    return ct >> 2;
+bad2:
+    deselect_sio(old_sio);
+bad:
+    kprintf("fd%d: I/O error %d.\n", minor, err);
+    udata.u_error = EIO;
+    return -1;
+}
 
 int fd_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
 {
-    flag;
-    return fd_transfer(true, minor, rawflag);
+    used(flag);
+    return fd_transfer(minor, true, rawflag);
 }
 
 int fd_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
 {
-    flag;
-    return fd_transfer(false, minor, rawflag);
+    used(flag);
+    return fd_transfer(minor, false, rawflag);
 }
 
-/* hd is only used for swapping */
-int hd_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+int fd_open(uint8_t minor, uint16_t flag)
 {
     flag;
-    return hd_transfer(true, minor, rawflag);
+    if(minor >= 3) {
+        udata.u_error = ENODEV;
+        return -1;
+    }
+    return 0;
 }
 
-int hd_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+static void mdelay(uint16_t d)
 {
-    flag;
-    return hd_transfer(false, minor, rawflag);
+    used(d);
+    /* FIXME */
 }
 
-static int fd_transfer(bool is_read, uint8_t minor, uint8_t rawflag)
+__sfr __at 0x19 rom_ctrl;
+
+static void rom_on(void)
 {
-    /* Serial floppy driver - to write */
-    is_read;
-    minor;
-    rawflag;
-    return -EIO;
+    mod_ioctrlr(0x08,0x00);    /* Cartridge out of reset */
+    mdelay(10);
+    rom_ctrl = 1;              /* Power on */
+    mdelay(60);
 }
 
-/* Easier to use statics as is this is single threaded and talking to asm
-   code in a critical path */
-
-uint16_t ramd_off;
-uint16_t ramd_size;
-uint16_t ramd_uaddr;
+static void rom_off(void)
+{
+    rom_ctrl = 0;
+    mod_ioctrlr(0x00,0x08);
+}
 
-/* Really only ever used for swap */
-static int hd_transfer(bool is_read, uint8_t minor, uint8_t rawflag)
+/* hd is actually the ROM image files */
+int rom_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
 {
-    minor;
+    used(flag);
 
     if(rawflag == 1) {
-        ramd_size = udata.u_count;
-        ramd_uaddr = (uint16_t)udata.u_base;
-        ramd_off = udata.u_offset << 1;
+        romd_size = udata.u_count;
+        romd_addr = (uint16_t)udata.u_base;
+        romd_off = udata.u_offset >> 8;
         /* Should check this higher up ? */
-        if (((uint16_t)ramd_size | ramd_off) & BLKMASK)
-            return -EIO;
-    } else if (rawflag == 2) {         /* Swap device special */
-        ramd_size = swapcnt << 9;
-        ramd_uaddr = (uint16_t)swapbase;
-        ramd_off = swapblk << 1;
+        if (((uint16_t)udata.u_offset | romd_size) & BLKMASK)
+            goto bad;
+    } else if (rawflag == 2) {
+        goto bad;
     } else { /* rawflag == 0 */
-        ramd_uaddr = (uint16_t)udata.u_buf->bf_data;
-        ramd_off = udata.u_buf->bf_blk << 8;
-        ramd_size = 512;
+        romd_addr = (uint16_t)udata.u_buf->bf_data;
+        romd_off = udata.u_buf->bf_blk << 1;
+        romd_size = 512;
+    }
+    romd_mode = rawflag;
+    if (minor == 0)
+        rom_sidecar_read();
+    else {
+        rom_on();
+        rom_cartridge_read();
+        rom_off();
     }
-    /* Block copy to/from the RAM disc I/O */
-    if (is_read)
-        hd_xferin();
-    else
-        hd_xferout();
-    return ramd_size;
+    return romd_size;
+bad:
+    udata.u_error = EIO;
+    return -1;
 }
 
-int fd_open(uint8_t minor, uint16_t flag)
+
+int rom_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
 {
-    flag;
-    if(minor >= 3) {
-        udata.u_error = ENODEV;
-        return -1;
-    }
-    return 0;
+    used(minor);
+    used(rawflag);
+    used(flag);
+
+    udata.u_error = EIO;
+    return -1;
 }
 
-int hd_open(uint8_t minor, uint16_t flag)
+int rom_open(uint8_t minor, uint16_t flag)
 {
     flag;
-    if(minor) {
-        udata.u_error = ENODEV;
-        return -1;
+    switch (minor) {
+        case 0:
+            if (sidecar)
+                return 0;
+            break;
+        case 1:
+            if (carttype == 1) /* ROM */
+                return 0;
+            break;
     }
-    return 0;
+    udata.u_error = ENODEV;
+    return -1;
 }
index 629628a..30c26df 100644 (file)
@@ -6,12 +6,22 @@ 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);
 
-int hd_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
-int hd_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
-int hd_open(uint8_t minor, uint16_t flag);
+int rom_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int rom_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int rom_open(uint8_t minor, uint16_t flag);
 
 /* asm code */
-void hd_xferin(void);
-void hd_xferout(void);
+void rom_sidecar_read(void);
+void rom_cartridge_read(void);
+
+/* In common */
+extern uint16_t romd_size;
+extern uint16_t romd_addr;
+extern uint16_t romd_off;
+extern uint8_t romd_mode;
+
+/* Set up by boot code */
+extern uint8_t sidecar;
+extern uint8_t carttype;
 
 #endif /* __DEVRD_DOT_H__ */
index 87a2f8b..fbd7369 100644 (file)
@@ -14,8 +14,8 @@ struct devsw dev_tab[] =  /* The device driver switch table */
 // -----------------------------------------------------------------
   /* 0: /dev/fd                Floppy disc block devices  */
   {  fd_open,     no_close,    fd_read,   fd_write,   no_ioctl },
-  /* 1: /dev/hd                Hard disc block devices (absent) */
-  {  hd_open,     no_close,    hd_read,   hd_write,   no_ioctl },
+  /* 1: /dev/hd                Hard disc (we use for ROMs) */
+  {  rom_open,    no_close,    rom_read,   rom_write,   no_ioctl },
   /* 2: /dev/tty       TTY devices */
   {  tty_open,     tty_close,   tty_read,  tty_write,  tty_ioctl },
   /* 3: /dev/lpr       Printer devices */
index 2dbacb5..3083b6b 100644 (file)
@@ -1,6 +1,6 @@
 -mwxuy
 -i fuzix.ihx
--b _COMMONMEM=0x0100
+-b _COMMONMEM=0x0200
 -b _UDATA=0x5D00
 -b _DISCARD=0x4000
 -b _CODE=0x6000
@@ -14,11 +14,15 @@ platform-px4plus/main.rel
 start.rel
 version.rel
 lowlevel-z80-banked.rel
+usermem_std-z80-banked.rel
 platform-px4plus/tricks.rel
+platform-px4plus/swapdev.rel
 timer.rel
 kdata.rel
 usermem.rel
 platform-px4plus/devfd.rel
+platform-px4plus/romdisc.rel
+platform-px4plus/sio.rel
 platform-px4plus/devices.rel
 devio.rel
 filesys.rel
@@ -31,7 +35,7 @@ syscall_proc.rel
 syscall_other.rel
 tty.rel
 mm.rel
-simple.rel
+bankfixed.rel
 swap.rel
 devsys.rel
 platform-px4plus/devlpr.rel
index f363279..87ed387 100644 (file)
@@ -3,6 +3,7 @@
 #include <kdata.h>
 #include <printf.h>
 #include <devtty.h>
+#include <devfd.h>
 
 uint16_t ramtop = PROGTOP;
 
@@ -26,8 +27,39 @@ void platform_interrupt(void)
   timer_interrupt();
 }
 
-/* Nothing to do for the map of init */
-void map_init(void)
+extern uint8_t map_translate[MAX_MAPS];
+
+/* Add map numbers. These are logical mappings one of which is the current
+   memory image and the others indexes into the sidecar or cartridge memory.
+
+   Put map #1 last as it means "in memory" and we want it for init */
+
+void pagemap_init(void)
 {
+       uint8_t n = procmem / 32;
+       uint8_t *p = map_translate;
+       uint8_t nv = 0xFF;
+       uint8_t ct;
+       uint8_t i;
+
+       if (!sidecar && carttype != 2)
+        panic("No suitable memory extension");
+       n /= 32;
+       /* Handle sidecar memory */
+       if (sidecar) {
+               nv = n - 4;     /* Number of non sidecar blocks (including in RAM) */
+               ct = 0x83;      /* 0x80-0x83 are sidecar maps */
+       } else
+               ct = n;         /* 1..n are cartridge (1 = in memory) */
+
+       for (i = n; i > 0; i--) {
+               if (i == nv)
+                       ct = nv;
+               *p++ = ct--;
+               pagemap_add(i);
+       }
 }
 
+void map_init(void)
+{
+}
index b9bcddf..a73e7cb 100644 (file)
@@ -1,15 +1,7 @@
 ;
-;      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
+;      PX4 Plus hardware support
 ;
 
-
             .module px4plus
 
             ; exported symbols
            .globl map_process_always
            .globl map_save
            .globl map_restore
+           .globl map_process_save
+           .globl map_kernel_restore
            .globl _kernel_flag
+           .globl _sidecar
+           .globl _carttype
 
            .globl platform_interrupt_all
 
             .globl _ramsize
             .globl _procmem
            .globl _vtinit
+           .globl _cartridge_size
 
            .globl unix_syscall_entry
             .globl null_handler
            .globl nmi_handler
             .globl interrupt_handler
 
-           ; RAM drive
-           .globl _hd_xferin
-           .globl _hd_xferout
-           .globl _ramd_off
-           .globl _ramd_size
-           .globl _ramd_uaddr
+           ; ROM interfaces
+           .globl _rom_sidecar_read
+           .globl _rom_cartridge_read
+           .globl _romd_off
+           .globl _romd_size
+           .globl _romd_addr
+           .globl _romd_mode
 
 
            .globl __bank_0_1
-           .globl __bank_0_2
            .globl __bank_0_3
-           .globl __bank_1_2
            .globl __bank_1_3
-           .globl __bank_2_1
-           .globl __bank_2_3
            .globl __bank_3_1
-           .globl __bank_3_2
 
            .globl __stub_0_1
-           .globl __stub_0_2
            .globl __stub_0_3
-           .globl __stub_1_2
            .globl __stub_1_3
-           .globl __stub_2_1
-           .globl __stub_2_3
            .globl __stub_3_1
-           .globl __stub_3_2
 
 
             .include "kernel.def"
@@ -86,10 +74,26 @@ platform_interrupt_all:
            ret
 
 ;
-;      FIXME: this probably needs to be a new "commondata" area
+;      FIXME: this probably needs to be a new "commondata" area so we can
 ;
 _kernel_flag:
            .db 1
+kernel_map:                    ; Last kernel map we were using
+           .db 0xA2
+saved_map:                     ; Saved mapping for IRQ entry/exit
+           .db 0
+_sidecar:
+           .db 0
+_carttype:
+           .db 0
+_romd_off:
+           .dw 0
+_romd_size:
+           .dw 0
+_romd_addr:
+           .dw 0
+_romd_mode:
+           .db 0
 
 ; -----------------------------------------------------------------------------
 ; KERNEL MEMORY BANK (only accessible when the kernel is mapped)
@@ -97,14 +101,40 @@ _kernel_flag:
             .area _CODE
 
 init_early:
+           ld a, (0xF53F)              ; BIOS cartridge type
+           ld (_carttype), a
             ret
 
 init_hardware:
             ; set system RAM size
-           ; Not strictly correct FIXME: set right when ROM the image
+           ; We have 64K RAM + 64K ROM to immediate hand, but we should
+           ; try and include the "swap" like RAM here to give a sensible
+           ; number, as we won't treat it as disk
             ld hl, #64
+           in a, (0x94)
+           add a
+           jr nc, notplus
+           ld hl, #192                 ; Sidecar always has 128K on the PX4
+                                       ; PX8 version is 120K if we ever do
+                                       ; PX8
+           ld a, #1
+           ld (_sidecar), a            ; Sidecar present
+notplus:    ; Not a PX4plus or PX4 with sidecar
+           ; See if we have a RAM cartridge fitted
+           ld a, (_carttype)
+           cp #2
+           jr nz, noramcart
+           push hl
+           push af
+           call _cartridge_size
+           pop af
+           pop de
+           add hl, de
+noramcart:
             ld (_ramsize), hl
-            ld hl, #32                 ; 32K for kernel
+           or a
+            ld de, #32                 ; 32K for kernel
+           sbc hl, de
             ld (_procmem), hl
 
             ; set up interrupt vectors for the kernel
@@ -169,14 +199,40 @@ _program_vectors:
 
            ; falls through
 
-           ; Map functions are trivial for now
-           ; FIXME: will need to play with BANKR once we ROM the image
 map_kernel: 
+map_kernel_restore:
+           push af
+           ld a, (kernel_map)
+           out (0x05), a
+           pop af
+           ret
 map_process:
+           ld a, h
+           or l
+           jr z, map_kernel
 map_process_always:
+map_process_save:
+           push af
+           in a,(0x05)
+           cp #0x42                    ; Already in user map
+           jr z, reto
+           ld (kernel_map), a
+            ld a, #0x42                        ; user map (ROMs out)
+           out (0x05), a
+reto:
+           pop af
+           ret
+
 map_save:
+           in a, (0x05)
+           ld (saved_map), a
+           ret
 map_restore:
-           ret     
+           ld a, (saved_map)
+           and #0xF0
+           or #0x02
+           out (0x05), a
+           ret
 
 ; outchar: Wait for UART TX idle, then print the char in A
 outchar:
@@ -189,101 +245,20 @@ outcharw:
            out (0x14), a        
             ret
 
-;
-;      RAM disc
-;
-_hd_xferin:
-;
-;      Load the full 24 bit address to start
-;
-       xor a           ;        always aligned
-       out (0x90), a
-       ld hl, #_ramd_off + 1
-       ld de, (_ramd_size)
-hd_xiloop:
-       ld a, (hl)
-       out (0x91), a
-       inc hl
-       ld a, (hl)
-       out (0x92), a
-       ld bc, #0x93
-;
-;      With a 256 byte block it autoincrements
-;
-       ld hl, (_ramd_uaddr)
-       inir
-       dec d
-       ret z
-;
-;      Move on a block
-;
-       ld (_ramd_uaddr), hl
-       ld hl, #_ramd_off + 1
-       inc (hl)
-       jr nz, hd_xiloop
-       inc hl
-       inc (hl)
-       dec hl
-       jr hd_xiloop
-
-_hd_xferout:
-;
-;      Load the full 24 bit address to start
-;
-       xor a           ;        always aligned
-       out (0x90), a
-       ld hl, #_ramd_off + 1
-       ld de, (_ramd_size)
-hd_xoloop:
-       ld a, (hl)
-       out (0x91), a
-       inc hl
-       ld a, (hl)
-       out (0x92), a
-       ld bc, #0x93
-;
-;      With a 256 byte block it autoincrements
-;
-       ld hl, (_ramd_uaddr)
-       otir
-       dec d
-       ret z
-;
-;      Move on a block
-;
-       ld (_ramd_uaddr), hl
-       ld hl, #_ramd_off + 1
-       inc (hl)
-       jr nz, hd_xoloop
-       inc hl
-       inc (hl)
-       dec hl
-       jr hd_xiloop
-
 
-;
-;      FIXME
-current_map:
-       .byte 0
-switch_bank:
-       ret
 ;
 ;
 ;      Banking helpers
 ;
-;      FIXME: these are from zx128 - not yet converted to px4plus. We
-; should also be able to dump all to/from bank2 versions
-;
-;
 ;      Logical         Physical
-;      0               COMMON (0x4000)
-;      1               0
-;      2               1
-;      3               7
+;      0               COMMON
+;      1               ROM1
+;      2               *unused*
+;      3               ROM2
 ;
 ;
 __bank_0_1:
-       xor a              ; switch to physical bank 0 (logical 1)
+       ld a, #0xA2        ; switch to 32K ROM 1
 bankina0:
        ;
        ;       Get the target address first, otherwise we will change
@@ -295,158 +270,98 @@ bankina0:
        ld d, (hl)
        inc hl
        push hl            ; Restore corrected return pointer
-       ld bc, (current_map)    ; get current bank into B
-       call switch_bank   ; Move to new bank
+       ld c, #0x05
+       in b, (c)
+       out (c), a
        ; figure out which bank to map on the return path
-       ld a, c
-       or a
+       ld a, #0xA2
+       cp b
        jr z, __retmap1
-       dec a
-       jr z, __retmap2
        jr __retmap3
 
 callhl:        jp (hl)
-__bank_0_2:
-       ld a, #1           ; logical 2 -> physical 1
-       jr bankina0
+
 __bank_0_3:
-       ld a, #7           ; logical 3 -> physical 7
+       ld a, #0xE2        ; 32K ROM 2
        jr bankina0
 
-__bank_1_2:
-       ld a, #1
-bankina1:
+__bank_1_3:
+       ld a, #0xE2        ; 32K ROM 2
        pop hl             ; Return address (points to true function address)
        ld e, (hl)         ; DE = function to call
        inc hl
        ld d, (hl)
        inc hl
        push hl            ; Restore corrected return pointer
-       call switch_bank   ; Move to new bank
+       out (0x05), a
 __retmap1:
        ex de, hl
        call callhl        ; call the function
-       xor a              ; return to bank 1 (physical 0)
-       jp switch_bank
+       ld a,#0xA2         ; return to ROM1
+       out (0x05), a
+       ret
 
-__bank_1_3:
-       ld a, #7
-       jr bankina1
-__bank_2_1:
-       xor a
-bankina2:
-       pop hl             ; Return address (points to true function address)
-       ld e, (hl)         ; DE = function to call
-       inc hl
-       ld d, (hl)
-       inc hl
-       push hl            ; Restore corrected return pointer
-       call switch_bank   ; Move to new bank
-__retmap2:
-       ex de, hl
-       call callhl        ; call the function
-       ld a, #1           ; return to bank 2
-       jp switch_bank
-__bank_2_3:
-       ld a, #7
-       jr bankina2
 __bank_3_1:
-       xor a
-bankina3:
+       ld a,#0xA2         ; 32K ROM 1
        pop hl             ; Return address (points to true function address)
        ld e, (hl)         ; DE = function to call
        inc hl
        ld d, (hl)
        inc hl
        push hl            ; Restore corrected return pointer
-       call switch_bank   ; Move to new bank
+       out (0x05), a
 __retmap3:
        ex de, hl
        call callhl        ; call the function
-       ld a, #7           ; return to bank 0
-       jp switch_bank
-
-__bank_3_2:
-       ld a, #1
-       jr bankina3
+       ld a, #0xE2        ; return to ROM 2
+       out (0x05), a
+       ret
 
 ;
 ;      Stubs need some stack munging and use DE
 ;
-
 __stub_0_1:
-       xor a
+       ld a, #0xA2
 __stub_0_a:
        pop hl          ; the return
        ex (sp), hl     ; write it over the discard
-       ld bc, (current_map)
-       call switch_bank
-       ld a, c
-       or a
+       ld c, #0x05
+       in b, (c)
+       out (c), a
+       ld a, #0xA2
+       cp b
        jr z, __stub_1_ret
-       dec a
-       jr z, __stub_2_ret
        jr __stub_3_ret
-__stub_0_2:
-       ld a, #1
-       jr __stub_0_a
 __stub_0_3:
-       ld a, #7
+       ld a, #0xE2
        jr __stub_0_a
 
-__stub_1_2:
-       ld a, #1
-__stub_1_a:
+__stub_1_3:
+       ld a, #0xE2
        pop hl          ; the return
        ex (sp), hl     ; write it over the discad
-       call switch_bank
+       out (0x05), a
 __stub_1_ret:
        ex de, hl
        call callhl
-       xor a
-       call switch_bank
-       pop de
-       push de         ; dummy the caller will discard
-       push de
-       ret
-__stub_1_3:
-       ld a, #7
-       jr __stub_1_a
-
-__stub_2_1:
-       xor a
-__stub_2_a:
-       pop hl          ; the return
-       ex (sp), hl     ; write it over the discad
-       call switch_bank
-__stub_2_ret:
-       ex de, hl       ; DE is our target
-       call callhl
-       ld a,#1
-       call switch_bank
+       ld a, #0xA2
+       out (0x05), a
        pop de
        push de         ; dummy the caller will discard
        push de
        ret
-__stub_2_3:
-       ld a, #7
-       jr __stub_2_a
 
 __stub_3_1:
-       xor a
-__stub_3_a:
+       ld a, #0xA2
        pop hl          ; the return
        ex (sp), hl     ; write it over the discad
-       call switch_bank
+       out (0x05), a
 __stub_3_ret:
        ex de, hl
        call callhl
-       ld a,#7
-       call switch_bank
+       ld a,#0xE2
+       out (0x05), a
        pop de
        push de         ; dummy the caller will discard
        push de
        ret
-__stub_3_2:
-       ld a, #1
-       jr __stub_3_a
diff --git a/Kernel/platform-px4plus/romdisc.s b/Kernel/platform-px4plus/romdisc.s
new file mode 100644 (file)
index 0000000..9d718d0
--- /dev/null
@@ -0,0 +1,79 @@
+;
+;      ROM drive interfaces
+;
+       .globl _rom_sidecar_read
+       .globl _rom_cartridge_read
+
+       .globl _romd_mode
+       .globl _romd_addr
+       .globl _romd_size
+       .globl _romd_off
+
+       .globl map_process_save
+       .globl map_kernel_restore
+
+       .area _COMMONMEM
+
+_rom_sidecar_read:
+       ld a, (_romd_mode)
+       or a
+       push af
+       call nz, map_process_save
+       xor a
+       out (0x90), a           ; low byte is always zero
+       ld hl, #_romd_off
+       ld de, (_romd_size)     ; Always multiple of 512 - don't need low FIXME
+rom_sc_loop:
+       ld a, (hl)
+       out (0x91), a           ; mid byte
+       inc hl
+       ld a, (hl)
+       out (0x92), a           ; top
+       ld bc, #0x93            ; port 93, 256 repeats
+       ld hl, (_romd_addr)
+       inir                    ; copy 256
+       dec d
+       jr z, rom_sc_done
+       ld (_romd_addr), hl     ; save pointer
+       ld hl, #_romd_off
+       inc (hl)                ; next page
+       jr rom_sc_loop
+rom_sc_done:
+       pop af
+       ret z
+       jp map_kernel_restore
+
+
+_rom_cartridge_read:
+       ld a, (_romd_mode)
+       or a
+rom_cr1:
+       push af
+       call nz, map_process_save
+       xor a
+       out (0x10), a           ; low byte is always zero
+       ld hl, #_romd_off
+       ld de, (_romd_size)     ; Always multiple of 512 - don't need low FIXME
+rom_ca_loop:
+       ld a, (hl)
+       out (0x11), a           ; mid byte
+       ld bc, #0x10            ; port 10, 256 repeats
+       ld hl, (_romd_addr)
+rom_ca_cp:
+       out (c), b              ; set low byte
+       in a, (0x12)            ; fetch from ROM
+       ld (hl), a              ; save
+       inc hl
+       inc b
+       jr nz, rom_ca_cp        ; For the 256 byte block
+       dec d
+       jr z, rom_ca_done
+       ld (_romd_addr), hl     ; save pointer
+       ld hl, #_romd_off
+       inc (hl)                ; next page
+       jr rom_ca_loop
+rom_ca_done:
+       pop af
+       ret z
+       jp map_kernel_restore
+
diff --git a/Kernel/platform-px4plus/sio.c b/Kernel/platform-px4plus/sio.c
new file mode 100644 (file)
index 0000000..53e44a1
--- /dev/null
@@ -0,0 +1,43 @@
+#include <kernel.h>
+#include <sio.h>
+
+__sfr __at 0x00 baudrate;
+__sfr __at 0x15 artmr;
+
+/* Select SIO */
+int select_sio(void)
+{
+  /* FIXME: save old modem bits, baud etc. We can't do this via hw
+     so probably need some kind of tty callbacks here */
+  baudrate = 0xB0;     /* 38400 */
+  artmr = 0x04;                /* 8N1 */
+  /* FIXME: disable ART IRQ */
+  return 0;
+}
+
+void deselect_sio(int old)
+{
+  /* FIXME */
+  used(old);
+}
+
+__sfr __at 0x14 artwr;
+__sfr __at 0x15 artsr;
+
+void sio_write(uint8_t *buf, int len)
+{
+  while(len--) {
+    while(!(artsr & 1));
+    artwr = *buf++;
+  }
+}
+
+int sio_read(uint8_t *buf, int len)
+{
+  /* FIXME: timeouts etc */
+  while(len--) {
+    while(!(artsr & 2))
+      *buf++ = artwr;
+  }
+  return 0;
+}
diff --git a/Kernel/platform-px4plus/sio.h b/Kernel/platform-px4plus/sio.h
new file mode 100644 (file)
index 0000000..260f3b3
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef _DEV_SIO_H
+#define _DEV_SIO_H
+
+extern int select_sio(void);
+extern void deselect_sio(int old);
+
+extern void sio_write(uint8_t *buf, int len);
+extern int sio_read(uint8_t *buf, int len);
+
+/* These don't truely belong here but it will do for now */
+extern void read_from_bank(uint16_t bank, uint16_t dptr, uint8_t *buf, uint16_t len);
+
+#endif
\ No newline at end of file
diff --git a/Kernel/platform-px4plus/swapdev.s b/Kernel/platform-px4plus/swapdev.s
new file mode 100644 (file)
index 0000000..de6397e
--- /dev/null
@@ -0,0 +1,214 @@
+;
+;      Support code for swap device activity
+;
+
+               .globl _cartridge_copy
+               .globl _cartridge_size
+               .globl _sidecar_copy
+
+               .globl _make_mapped
+
+               .globl _map_translate
+               .globl _map_live
+
+
+               .area _COMMONMEM
+
+;
+;      A holds the bank to use (1 = RAM 2/3 for cartridge 128+ sidecar
+;
+_cartridge_copy:
+               push bc
+               push de
+               push hl
+               ld de, #0x80    ; d is top half of I/O offset, e is the 
+                               ; block counter
+               cp #2
+               jr z, lowcopy
+               ld d, #0x80
+lowcopy:
+               ld hl, #0x5D00
+cart_copy:
+               ld a, d
+               out (0x11), a   ; high byte
+               ld bc, #0x10    ; port 10, 256 repeats
+cart_copy256:
+               out (c), b      ; set low byte to access
+               ld a, (hl)
+               out (0x12), a   ; write to cartridge
+               inc hl
+               inc b
+               jr nz, cart_copy256
+               inc d           ; move on a page
+               dec e
+               jr nz, cart_copy
+               pop hl
+               pop de
+               pop bc
+               ret
+
+;
+;      Exchange the process in bank a with the process in RAM
+;
+_cartridge_exchange:
+               push bc
+               push de
+               push hl
+               ld de, #0x80    ; d is top half of I/O offset, e is the 
+                               ; block counter
+               cp #2
+               jr z, lowx
+               ld d, #0x80
+lowx:
+               ld hl, #0x5D00
+cart_x:
+               ld a, d
+               out (0x11), a   ; high byte
+               ld bc, #0x10    ; port 10, 256 repeats
+cart_x256:
+               out (c), b      ; set low byte to access
+               in a, (0x12)    ; existing byte
+               push af
+               ld a, (hl)
+               out (0x12), a   ; write to cartridge
+               pop af
+               ld (hl), a      ; write to RAM
+               inc hl
+               inc b
+               jr nz, cart_x256
+               inc d           ; move on a page
+               dec e
+               jr nz, cart_x
+               pop hl
+               pop de
+               pop bc
+               ret
+
+
+               .area _CODE
+
+_cartridge_size:
+               ld c, #0xA512
+               xor a
+               out (0x11), a   ; low byte 0
+               ld a, #0x40
+               out (0x10), a   ; address 0x4000 selected
+               out (c), b
+               in a, (0x12)
+               cp b
+               jr nz, size16
+               ld a, #0x80
+               out (0x10), a
+               out (c), b
+               in a, (0x12)
+               cp b
+               jr nz, size32
+               ld hl, #64
+               ret
+size16:
+               ld hl, #16
+               ret
+size32:
+               ld hl, #32
+               ret
+
+               .area _COMMONMEM
+
+_sidecar_copy:
+               push bc
+               push de
+               push hl
+               and #0x7F       ; strip the magic bit for the bank code
+               ld e, #0
+               rra
+               rl e
+               ld d, #0x80
+               out (0x92), a   ; pick the right 64K bank
+               ld hl, #0x5D00  ; memory area to process
+               xor a
+               out (0x90), a   ; align the low byte on the page boundary
+sidecar_cnext:
+               ld a, e
+               out (0x91), a   ; mid part of the address
+               ld bc, #0x94    ; 256 bytes into 0x94
+               otir            ; also adjusts HL for us
+               inc e           ; next page
+               dec d           ; count of pages to do
+               jr nz, sidecar_cnext
+               pop hl
+               pop de
+               pop bc
+               ret
+
+_sidecar_exchange:
+               push bc
+               push de
+               push hl
+               and #0x7F       ; strip the magic bit for the bank code
+               ld e, #0
+               rra
+               rl e
+               ld d, #0x80
+               out (0x92), a   ; pick the right 64K bank
+               ld hl, #0x5D00  ; memory area to process
+sidecar_xnext:
+               ld a, e
+               out (0x91), a   ; mid part of the address
+               ld bc, #0x90    ; 256 bytes into 0x94
+;
+;      FIXME: this loop wants optimising properly
+;
+sidecar_xnl:
+               out (c), b      ; set low byte
+               in a, (0x12)
+               out (c), b      ; it auto-increments so put it back
+               push af
+               ld a, (hl)
+               out (0x12), a
+               pop af
+               ld (hl), a
+               inc hl
+               inc b
+               jr nz, sidecar_xnl
+               inc e           ; next page
+               dec d           ; count of pages to do
+               jr nz, sidecar_xnext
+               pop hl
+               pop de
+               pop bc
+               ret
+
+;
+;      Make the requested process the current one in memory. We use this
+;      on task switching but also on the floppy I/O when swapping in or
+;      out. Preserves DE.
+;
+_make_mapped:
+               ld c, a
+               ld b, #0
+               ld hl, #_map_translate
+               add hl, bc
+               ld a, (hl)              ; Are we in RAM ?
+               cp #1
+               ret z
+               ;
+               ;       We need to do an exchange
+               ;
+               push de
+               ld de, (_map_live)      ; current RAM owner
+               ld (de), a              ; current owner gets our page
+               ld (hl), #1             ; we get its page
+
+               bit 7, a
+               jr z, in_sidecar
+               ;
+               ;       We are in the cartridge
+               ;       Swap ourselves with whoever is current RAM task
+               ;
+               call _cartridge_exchange
+               jr in_memory2
+in_sidecar:
+               call _sidecar_exchange
+in_memory2:
+               pop de                  ; recover task pointer
+               ret
index 00a546e..d6f1a56 100644 (file)
        .globl _swapper
        .globl _swapout
 
+       .globl _map_translate
+       .globl _map_live
+       .globl _sidecar_copy
+       .globl _cartridge_copy
+       .globl _make_mapped
+
         ; imported debug symbols
         .globl outstring, outde, outhl, outbc, outnewline, outchar, outcharhex
 
@@ -89,25 +95,24 @@ _switchin:
        add hl, de      ; process ptr
        pop de
 
-        ld a, (hl)
+       ;
+       ;       Always use the swapstack, otherwise when we call map_kernel
+       ;       having copied the udata stash back to udata we will crap
+       ;       somewhere up the stackframe and it's then down to luck
+       ;       if those bytes are discarded or not.
+       ;
+       ;       Yes - this was a bitch to debug, please don't break it !
+       ;
+       ld sp, #_swapstack
 
+        ld a, (hl)
        or a
        jr nz, not_swapped
 
        ;
-       ;       We are still on the departing processes stack, which is
-       ;       fine for now.
+       ;       Let the swapper run
        ;
-       ld sp, #_swapstack
        push hl
-       ; We will always swap out the current process
-       ld hl, (U_DATA__U_PTAB)
-       push hl
-       push af
-       call _swapout
-       pop af
-       pop hl
-       pop hl
        push de
        push af
        call _swapper
@@ -116,8 +121,17 @@ _switchin:
        pop hl
        ld a, (hl)
 
-not_swapped:        
+not_swapped:
+       ;
+       ;       On the PX4 this is only half the game. The process we want
+       ;       is probably stuffed into the sidecar or cartridge
+       ;
+       ;       Make bank A mapped bank. Preserves DE, trashes AF,BC,HL
+       ;
+       call _make_mapped
+       ;
         ; 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
@@ -201,15 +215,26 @@ _dofork:
         ; now we're in a safe state for _switchin to return in the parent
        ; process.
 
-       ld hl, (U_DATA__U_PTAB)
-       push hl
+        ; now the copy operation is complete we can get rid of the stuff
+        ; _switchin will be expecting from our copy of the stack.
+        ; --------- 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
-       call _swapout
+       ld a, c
+       call outcharhex
        pop af
-       pop hl
+       ld a, (U_DATA__U_PAGE)
+
+       call bankfork                   ;       do the bank to bank copy
+
+       ; Fix up stack
 
-        ; 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
@@ -231,6 +256,43 @@ _dofork:
        ; to be the live uarea. The parent is frozen in time and space as
        ; if it had done a switchout().
         ret
+
+;
+;      A is the parent C is the child bank. Both of these are of course
+;      logical banks. The logical bank of A right now is 1 (in memory),
+;      but this will all change
+;
+;      We do a copy to the I/O mapped sidecar or cartridge rather than the
+;      usual LDIR. We also update our logical mapping table as we
+;      effectively swapped ram between parent and child.
+;
+bankfork:
+       push af
+       ld b, #0
+       ld hl, #_map_translate
+       add hl, bc
+       push hl
+       ld a, (hl)
+       bit 7, a
+       jr nz, copy_to_sidecar
+       ;
+       ; Forking to cartridge
+       ;
+       call _cartridge_copy
+       jr bankcopy_done
+copy_to_sidecar:
+       call _sidecar_copy
+bankcopy_done:
+       pop hl          ; child translation entry
+       ld a, (hl)      ; entry that was allocated
+       ld (hl), #1     ; child is now main memory
+       ld de, (_map_live)      ; parent entry
+       ld (de), a              ; parent now gets "new" entry as child has
+                               ; the RAM
+       ld (_map_live), hl      ; live task map
+       ld b, #0
+       pop af
+       ret
 ;
 ;      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