68hc11test: initial incomplete compile testing for HC11
authorAlan Cox <alan@linux.intel.com>
Mon, 20 Jul 2015 21:46:17 +0000 (22:46 +0100)
committerAlan Cox <alan@linux.intel.com>
Mon, 20 Jul 2015 21:46:17 +0000 (22:46 +0100)
17 files changed:
Kernel/platform-68hc11test/68hc11.h [new file with mode: 0644]
Kernel/platform-68hc11test/Makefile [new file with mode: 0644]
Kernel/platform-68hc11test/README [new file with mode: 0644]
Kernel/platform-68hc11test/commonmem.s [new file with mode: 0644]
Kernel/platform-68hc11test/config.h [new file with mode: 0644]
Kernel/platform-68hc11test/crt0.s [new file with mode: 0644]
Kernel/platform-68hc11test/devices.c [new file with mode: 0644]
Kernel/platform-68hc11test/devrd.c [new file with mode: 0644]
Kernel/platform-68hc11test/devrd.h [new file with mode: 0644]
Kernel/platform-68hc11test/devtty.c [new file with mode: 0644]
Kernel/platform-68hc11test/devtty.h [new file with mode: 0644]
Kernel/platform-68hc11test/kernel.def [new file with mode: 0644]
Kernel/platform-68hc11test/libc.c [new file with mode: 0644]
Kernel/platform-68hc11test/main.c [new file with mode: 0644]
Kernel/platform-68hc11test/p68hc11.s [new file with mode: 0644]
Kernel/platform-68hc11test/target.mk [new file with mode: 0644]
Kernel/platform-68hc11test/tricks.s [new file with mode: 0644]

diff --git a/Kernel/platform-68hc11test/68hc11.h b/Kernel/platform-68hc11test/68hc11.h
new file mode 100644 (file)
index 0000000..697ea0e
--- /dev/null
@@ -0,0 +1,5 @@
+extern volatile uint8_t *baud;
+extern volatile uint8_t *sccr1;
+extern volatile uint8_t *sccr2;
+extern volatile uint8_t *scdr;
+extern volatile uint8_t *scsr;
diff --git a/Kernel/platform-68hc11test/Makefile b/Kernel/platform-68hc11test/Makefile
new file mode 100644 (file)
index 0000000..dc3f59c
--- /dev/null
@@ -0,0 +1,33 @@
+
+CSRCS = devtty.c devrd.c
+CSRCS += devices.c main.c libc.c
+
+ASRCS = crt0.s p68hc11.s
+ASRCS += tricks.s commonmem.s
+
+COBJS = $(CSRCS:.c=$(BINEXT))
+AOBJS = $(ASRCS:.s=$(BINEXT))
+OBJS  = $(COBJS) $(AOBJS)
+
+JUNK = $(CSRCS:.c=.o) $(ASRCS:.s=.o)
+
+all:   $(OBJS)
+
+$(COBJS): %$(BINEXT): %.c
+       $(CROSS_CC) $(CROSS_CCOPTS) -c $<
+
+$(AOBJS): %$(BINEXT): %.s
+       $(CROSS_AS) $(ASOPTS) $< -o $*.o
+
+clean:
+       rm -f $(OBJS) $(JUNK)  core *~ 
+
+image:
+       $(CROSS_LD) -o ../fuzix.bin -M >../fuzix.map \
+       crt0.o commonmem.o \
+       p68hc11.o ../start.o ../version.o ../lowlevel-68hc11.o \
+       tricks.o main.o ../timer.o ../kdata.o devrd.o devices.o \
+       ../devio.o ../filesys.o ../process.o ../inode.o ../syscall_fs.o \
+       ../syscall_proc.o ../syscall_other.o ../mm.o ../swap.o ../bankfixed.o \
+       ../tty.o ../devsys.o ../usermem.o ../syscall_fs2.o ../syscall_exec16.o \
+       ../usermem_std-68hc11.o devtty.o libc.o
diff --git a/Kernel/platform-68hc11test/README b/Kernel/platform-68hc11test/README
new file mode 100644 (file)
index 0000000..439a84b
--- /dev/null
@@ -0,0 +1,17 @@
+
+68HC811E Development board
+
+Memory map:
+0000-00FF:             internal RAM (unbanked)
+0100-F7FF:             externam RAM (banked)
+       but with hole
+F000-F03F:             I/O devices (unbanked)
+F800-FFFF:             2K EEPROM (unbanked)
+
+
+8 banks of 64K (minus 2.5K or so per bank unusable)
+
+Kernel in bank 0, user space in 1-7
+
+Serial is the onchip port
+SPI drives the SD card
diff --git a/Kernel/platform-68hc11test/commonmem.s b/Kernel/platform-68hc11test/commonmem.s
new file mode 100644 (file)
index 0000000..3196223
--- /dev/null
@@ -0,0 +1,21 @@
+;
+;      udata is a bit special we have to copy it on a task switch as we've
+;      got almost no common memory space on the simple board design
+;
+        .file "commonmem"
+       .mode mshort
+
+        ; exported symbols
+        .globl _ub
+        .globl udata
+        .globl kstack_top
+        .globl istack_top
+        .globl istack_switched_sp
+
+        .sect .udata
+
+       .comm udata,512,1
+       .comm kstack_top,0,1
+       .comm istack_base,254,1
+       .comm istack_top,2,1
+       .comm istack_switched_sp,2,1
diff --git a/Kernel/platform-68hc11test/config.h b/Kernel/platform-68hc11test/config.h
new file mode 100644 (file)
index 0000000..e31e215
--- /dev/null
@@ -0,0 +1,47 @@
+/* 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 - for now while we get it booting */
+#undef CONFIG_SINGLETASK
+#undef CONFIG_USERMEM_C
+/* We use big banks so use the helper */
+#define CONFIG_BANK_FIXED
+#define CONFIG_BANKS   7       /* and one for the kernel */
+#define MAX_MAPS 7
+#define MAPBASE            0x200
+#define MAP_SIZE    0xEE00
+/* And swapping */
+#define SWAPDEV 6      /* FIXME */
+#define SWAP_SIZE   0x78       /* Almost a full 64K */
+/* FIXME: udata swap separately */
+#define SWAPBASE    0x0200     /* We swap the lot in one */
+#define SWAPTOP            0xF000
+#define MAX_SWAPS      32
+
+/* Serial tty */
+#undef CONFIG_VT
+
+#define TICKSPERSEC 100   /* Ticks per second */
+#define PROGBASE    0x0200  /* also data base */
+#define PROGLOAD    0x0200  /* also data base */
+#define PROGTOP     0xF000  /* Top of program, base of I/O */
+
+#define BOOT_TTY (512 + 1)   /* Set this to default device for stdio, stderr */
+                          /* In this case, the default is the first TTY device */
+                            /* Temp FIXME set to serial port for debug ease */
+
+/* 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 1
+#define TTYDEV   BOOT_TTY /* Device used by kernel for messages, panics */
+#define NBUFS    7        /* Number of block buffers */
+#define NMOUNTS         2        /* Number of mounts at a time */
+
+#define swap_map(x)    ((uint8_t *)(x))
diff --git a/Kernel/platform-68hc11test/crt0.s b/Kernel/platform-68hc11test/crt0.s
new file mode 100644 (file)
index 0000000..58fa149
--- /dev/null
@@ -0,0 +1,53 @@
+               ; imported symbols
+
+               .file "crt0.s"
+               .mode mshort
+
+               .globl fuzix_main
+               .globl init_early
+               .globl init_hardware
+               .globl kstack_top
+
+               ; startup code @0
+               .sect .start
+               jmp start
+
+               .sect .text
+start:         
+               sei
+               lds #kstack_top
+;
+;      FIXME: any set up needed ?
+;
+
+               jsr init_early
+               jsr init_hardware
+               jsr fuzix_main
+               sei
+stop:          bra stop
+
+;
+;      Zeropage compiler goo
+;
+
+               .globl _.frame
+               .globl _.tmp
+               .globl _.d0
+               .globl _.d1
+               .globl _.d2
+               .globl _.d3
+               .globl _.d4
+               .globl _.d5
+               .globl _.xy
+               .globl _.z
+
+.equ _.frame,0x40
+.equ _.tmp,0x42
+.equ _.d0,0x44
+.equ _.d1,0x46
+.equ _.d2,0x48
+.equ _.d3,0x4A
+.equ _.d4,0x4C
+.equ _.d5,0x4E
+.equ _.xy,0x50
+.equ _.z,0x52
\ No newline at end of file
diff --git a/Kernel/platform-68hc11test/devices.c b/Kernel/platform-68hc11test/devices.c
new file mode 100644 (file)
index 0000000..df1dcdd
--- /dev/null
@@ -0,0 +1,38 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <devrd.h>
+#include <devsys.h>
+#include <tty.h>
+#include <devtty.h>
+
+struct devsw dev_tab[] =  /* The device driver switch table */
+{
+// minor    open         close        read      write       ioctl
+// -----------------------------------------------------------------
+  /* 0: /dev/hd                Hard disc block devices (SD card)  */
+  {  rd_open,     no_close,    rd_read,   rd_write,   no_ioctl },
+  /* 1: /dev/fd                Floppy devices (absent) */
+  {  nxio_open,     no_close,    no_rdwr,   no_rdwr,   no_ioctl },
+  /* 2: /dev/tty       TTY devices */
+  {  tty_open,     tty_close,   tty_read,  tty_write,  tty_ioctl },
+  /* 3: /dev/lpr       Printer devices (none) */
+  {  nxio_open,     no_close,   no_rdwr,   no_rdwr,  no_ioctl  },
+  /* 4: /dev/mem etc   System devices (one offs) */
+  {  no_open,      no_close,    sys_read, sys_write, sys_ioctl  },
+  /* Pack to 7 with nxio if adding private devices and start at 8 */
+};
+
+bool validdev(uint16_t dev)
+{
+    /* This is a bit uglier than needed but the right hand side is
+       a constant this way */
+    if(dev > ((sizeof(dev_tab)/sizeof(struct devsw)) << 8) + 255)
+       return false;
+    else
+        return true;
+}
+void device_init(void)
+{
+}
+
diff --git a/Kernel/platform-68hc11test/devrd.c b/Kernel/platform-68hc11test/devrd.c
new file mode 100644 (file)
index 0000000..70f4fc3
--- /dev/null
@@ -0,0 +1,69 @@
+/* 
+ * NC100 RD PCMCIA driver
+ *
+ */
+
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devrd.h>
+
+static int rd_transfer(bool is_read, uint8_t rawflag)
+{
+    blkno_t block;
+    int block_xfer;
+    uint16_t dptr;
+    int dlen;
+    int ct = 0;
+    int map;
+
+    /* FIXME: raw is broken unless nicely aligned */
+    if(rawflag) {
+        dlen = udata.u_count;
+        dptr = (uint16_t)udata.u_base;
+        if (((uint16_t)dptr | dlen) & BLKMASK) {
+            udata.u_error = EIO;
+            return -1;
+        }
+        block = udata.u_offset >> 9;
+        block_xfer = dlen >> 9;
+        map = 1;
+    } else { /* rawflag == 0 */
+        dlen = 512;
+        dptr = (uint16_t)udata.u_buf->bf_data;
+        block = udata.u_buf->bf_blk;
+        block_xfer = 1;
+        map = 0;
+    }
+    block += 2*320;    /* ramdisc starts at 320K in */
+        
+    while (ct < block_xfer) {
+/*        rd_memcpy(is_read, map, dptr, block); */
+        block++;
+        ct++;
+    }
+    return ct;
+}
+
+int rd_open(uint8_t minor, uint16_t flag)
+{
+    flag;
+    if(minor != 0) {
+        udata.u_error = ENODEV;
+        return -1;
+    }
+    return 0;
+}
+
+int rd_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;minor;
+    return rd_transfer(true, rawflag);
+}
+
+int rd_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;minor;
+    return rd_transfer(false, rawflag);
+}
+
diff --git a/Kernel/platform-68hc11test/devrd.h b/Kernel/platform-68hc11test/devrd.h
new file mode 100644 (file)
index 0000000..6320b26
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __DEVRD_DOT_H__
+#define __DEVRD_DOT_H__
+
+/* public interface */
+int rd_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int rd_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int rd_open(uint8_t minor, uint16_t flag);
+
+/* asm banking helper */
+void rd_memcpy(uint8_t isread, uint8_t map, uint16_t dptr, uint16_t block);
+
+#endif /* __DEVRD_DOT_H__ */
+
diff --git a/Kernel/platform-68hc11test/devtty.c b/Kernel/platform-68hc11test/devtty.c
new file mode 100644 (file)
index 0000000..eb54dc2
--- /dev/null
@@ -0,0 +1,81 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <devtty.h>
+#include <vt.h>
+#include <tty.h>
+#include <68hc11.h>
+
+static char tbuf1[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},
+};
+
+/* tty1 is the HC11 port B serial */
+
+/* Output for the system console (kprintf etc) */
+void kputchar(char c)
+{
+       if (c == '\n')
+               tty_putc(1, '\r');
+       tty_putc(1, c);
+}
+
+ttyready_t tty_writeready(uint8_t minor)
+{
+       uint8_t c = *scsr;
+       return (c & 0x80) ? TTY_READY_NOW : TTY_READY_SOON;
+}
+
+void tty_putc(uint8_t minor, unsigned char c)
+{
+       *scdr = c;
+}
+
+void tty_sleeping(uint8_t minor)
+{
+       used(minor);
+}
+
+/* Assumes 8MHz crystal and SCPR set to 011 */
+void tty_setup(uint8_t minor)
+{
+       uint8_t b = ttydata[1].termios.c_cflag & CBAUD;
+       *sccr1 = 0;
+       *sccr2 = 0x2C;  /* rx interrupt, rx/tx enabled */
+       if (b < B75)
+               b = B75;        /* Lowest with fixed divider.. we can do 50
+                                  but its much mucking about */
+       if (b > B9600)
+               b = B9600;
+       /* Only 8N1 */
+       ttydata[1].termios.c_cflag &= ~(CBAUD|PARENB);
+       ttydata[1].termios.c_cflag |= b | CS8;
+       
+       b = B9600 - b;
+       
+       *baud = b | 0x3;
+       minor;
+}
+
+/* Carrier etc are done via extra control lines. We don't have any spare! */
+int tty_carrier(uint8_t minor)
+{
+       minor;
+       return 1;
+}
+
+void platform_interrupt(void)
+{
+       uint8_t c = *scsr;
+       if (c & 0x20) {
+               /* Character arrived */
+               c = *scdr;      /* This clears the irq as well */
+               tty_inproc(1, c);
+       }
+       timer_interrupt();
+}
+
diff --git a/Kernel/platform-68hc11test/devtty.h b/Kernel/platform-68hc11test/devtty.h
new file mode 100644 (file)
index 0000000..c387e90
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef __DEVTTY_DOT_H__
+#define __DEVTTY_DOT_H__
+
+#endif
diff --git a/Kernel/platform-68hc11test/kernel.def b/Kernel/platform-68hc11test/kernel.def
new file mode 100644 (file)
index 0000000..5286775
--- /dev/null
@@ -0,0 +1,51 @@
+;
+;      Hide the udata above the I/O in the gap before the EEPROM
+;
+.equ U_DATA                      , 0xF200       ; (this is struct u_data from kernel.h)
+.equ U_DATA__TOTALSIZE           , 0x200        ;
+.equ IRQ_STACK             , 0xF400
+.equ EESTACK                       , 0xF600         ; used for eeprom stuff
+
+;
+;      EEPROM entry points
+;
+;      A = srcbank, B = dstbank
+;      IX = src, returns value in D
+.equ fargetb                   , 0xF840
+.equ fargetw                   , 0xF842
+;
+;      A = srcbank, B = dstbank
+;      IX = dst, IY = dstval
+;
+.equ farputb                   , 0xF844
+.equ farputw                   , 0xF846
+;
+;      A = srcbank, B = dstbank
+;      IX = dst, IY = src
+;      kernel:_tmp1 = length (in kernel bank)
+;
+.equ farcopy                   , 0xF848
+;
+;      A = bank, IX = function, IY = far stack
+;
+.equ farcall                   , 0xF84A
+;
+;      A = bank, IX = function, IY = far stack
+;
+.equ farjump                   , 0xF84C
+;
+;      A = bank
+;
+.equ setbank                   , 0xF84E
+;
+;      D = 0
+;
+.equ reboot                    , 0xF850
+;
+;
+;      Low memory usage (not banked)
+;
+.equ tmp1                      , 0xFE          ; 16bits
+.equ curbank                   , 0xFD
+.equ usrbank                   , 0xFC          ; we track this to emulate
+                                               ; usermode copy stuff
\ No newline at end of file
diff --git a/Kernel/platform-68hc11test/libc.c b/Kernel/platform-68hc11test/libc.c
new file mode 100644 (file)
index 0000000..311e411
--- /dev/null
@@ -0,0 +1,25 @@
+#include "cpu.h"
+
+void *memcpy(void *d, const void *s, size_t sz)
+{
+  unsigned char *dp, *sp;
+  while(sz--)
+    *dp++=*sp++;
+  return d;
+}
+
+void *memset(void *d, int c, size_t sz)
+{
+  unsigned char *p = d;
+  while(sz--)
+    *p++ = c;
+  return d;
+}
+
+size_t strlen(const char *p)
+{
+  const char *e = p;
+  while(*e++);
+  return e-p-1;
+}
+
diff --git a/Kernel/platform-68hc11test/main.c b/Kernel/platform-68hc11test/main.c
new file mode 100644 (file)
index 0000000..2baa0c1
--- /dev/null
@@ -0,0 +1,32 @@
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+
+void platform_idle(void)
+{
+}
+
+void do_beep(void)
+{
+}
+
+/*
+ * Map handling: We have flexible paging. Each map table consists of a set of pages
+ * with the last page repeated to fill any holes.
+ */
+
+void pagemap_init(void)
+{
+    int i;
+    for (i = 0x01; i < 0x08; i++)
+        pagemap_add(i);
+}
+
+void map_init(void)
+{
+}
+
+
+uint8_t need_resched;
diff --git a/Kernel/platform-68hc11test/p68hc11.s b/Kernel/platform-68hc11test/p68hc11.s
new file mode 100644 (file)
index 0000000..e01800a
--- /dev/null
@@ -0,0 +1,149 @@
+;
+;          68HC11 Simulation Platform 
+;
+
+        .file "p68hc11"
+       .mode mshort
+
+        ; exported symbols
+        .globl init_early
+        .globl init_hardware
+        .globl interrupt_handler
+        .globl program_vectors
+       .globl map_kernel
+       .globl map_process
+       .globl map_process_always
+       .globl map_save
+       .globl map_restore
+
+        ; exported debugging tools
+        .globl trap_monitor
+        .globl trap_reboot
+
+        include "kernel.def"
+        include "../kernel-hc11.def"
+
+;
+;      TODO: hardware registers
+;
+
+       .globl baud
+.equ baud,0xf000
+       .globl sccr1
+.equ sccr1,0xf000
+       .globl sccr2
+.equ sccr2,0xf000
+       .globl scdr
+.equ scdr,0xf000
+       .globl scsr
+.equ scsr,0xf000
+
+        .sect .data
+
+trapmsg:
+       .ascii "Trapdoor: SP="
+       .byte 0
+trapmsg2:
+       .ascii ", PC="
+        .byte 0
+tm_user_sp:
+       .word 0
+
+savedbank:
+       .word 0
+
+       .sect .text
+trap_monitor:
+       sei
+       bra trap_monitor
+
+trap_reboot:
+       jmp reboot
+
+init_early:
+       rts
+
+init_hardware:
+       ; set system RAM size
+       ldd #512
+       std ramsize
+       ldd #512-64
+       std procmem
+
+       ; Our vectors are in high memory unlike Z80 but we still
+       ; need vectors
+       clra
+       clrb            ; pass NULL
+       jsr program_vectors
+       rts
+
+
+program_vectors:
+;
+;      FIXME: figure out how this will interact with eeprom (eeprom should
+;      bank switch then call into some secondary vector)
+;
+       rts     ; rti will be in eeprom
+
+;
+;      Memory is fully banked, with no real common. We simply track the
+;      "correct" user bank for use by the copiers.
+;
+map_process_always:
+       psha
+       ldaa U_DATA__U_PAGE
+       staa usrbank
+       pula
+       rts
+
+map_kernel:
+       clr usrbank
+       rts
+
+map_restore:
+       psha
+       ldaa savedbank
+       pula
+       rts
+map_save:
+       psha
+       ldaa curbank
+       staa savedbank
+       pula
+       rts
+
+map_process:
+       xgdx
+       ldaa P_TAB__P_PAGE_OFFSET,x
+       staa usrbank
+       xgdx
+       rts
+
+;
+;      Bank handling
+;
+       .globl doexec
+       .globl sigdispatch
+       .globl _ugetc
+       .globl _ugetw
+       .globl _ugets
+       .globl _uget
+       .globl _uputc
+       .globl _uputw
+       .globl _uputs
+       .globl _uput
+       .globl _uzero
+
+
+doexec:
+sigdispatch:
+_ugetc:
+_ugetw:
+_ugets:
+_uget:
+_uputc:
+_uputw:
+_uput:
+_uzero:
+       /* FIXME */
+       rts
diff --git a/Kernel/platform-68hc11test/target.mk b/Kernel/platform-68hc11test/target.mk
new file mode 100644 (file)
index 0000000..5858abd
--- /dev/null
@@ -0,0 +1 @@
+export CPU = 68hc11
diff --git a/Kernel/platform-68hc11test/tricks.s b/Kernel/platform-68hc11test/tricks.s
new file mode 100644 (file)
index 0000000..122705f
--- /dev/null
@@ -0,0 +1,166 @@
+;
+;      68HC11 fully banked (so no real 'common')
+;
+        .file "tricks"
+       .mode mshort
+
+        .globl newproc
+        .globl chksigs
+        .globl getproc
+        .globl trap_monitor
+        .globl inint
+        .globl switchout
+        .globl switchin
+        .globl dofork
+       .globl ramtop
+
+        include "kernel.def"
+        include "../kernel-hc11.def"
+
+        .sect .data
+
+; ramtop must be in common for single process swapping cases
+; and its a constant for the others from before init forks so it'll be fine
+; here
+
+ramtop:
+       .word 0
+
+       .sect .code
+
+; 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().
+;
+; FIXME: make sure we optimise the switch to self case higher up the stack!
+; 
+; This function can have no arguments or auto variables.
+switchout:
+       sei
+        jsr chksigs
+
+        ; save machine state
+        ldx #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:
+       pshx
+       sts U_DATA__U_SP
+
+        ; set inint to false
+       clr inint
+
+        ; find another process to run (may select this one again) returns it
+        ; in X
+        jsr getproc
+        jsr switchin
+        ; we should never get here
+        jsr trap_monitor
+
+badswitchmsg: .ascii "switchin: FAIL"
+            .byte 13
+           .byte 10
+           .byte 0
+
+; new process pointer is in D
+switchin:
+       sei
+       
+       xgdx
+
+       ;
+       ; FIXME: implement dragon-nx uarea copy logic for HC11 via
+       ; eeprom copy helpers
+       ;
+
+       ; ------- No stack -------
+        ; check u_data->u_ptab matches what we wanted
+       cmpx U_DATA__U_PTAB
+        bne switchinfail
+
+       ; wants optimising up a bit
+       ldaa #P_RUNNING
+       staa P_TAB__P_STATUS_OFFSET,x
+
+       clr runticks
+
+        ; restore machine state -- note we may be returning from either
+        ; _switchout or _dofork
+        lds U_DATA__U_SP
+
+
+        ; enable interrupts, if the ISR isn't already running
+       ldaa inint
+        beq swtchdone ; in ISR, leave interrupts off
+       cli
+swtchdone:
+        pulx ; return code
+       xgdx
+        rts
+
+switchinfail:
+       jsr outx
+        ldx #badswitchmsg
+        jsr outstring
+       ; something went wrong and we didn't switch in what we asked for
+        jmp trap_monitor
+
+fork_proc_ptr: .word 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:
+       sei
+       ; new process is in D, get parent pid into d and process into x
+
+       xgdx
+
+       stx fork_proc_ptr
+       ldd P_TAB__P_PID_OFFSET,x
+
+        ; 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.
+       xgdx
+        pshx    ; x has p->p_pid from above, the return value in the parent
+
+        ; 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.
+        sts U_DATA__U_SP
+
+        ; now we're in a safe state for _switchin to return in the parent
+       ; process.
+
+       ; --------- we switch stack copies in this call -----------
+       ; d is the process pointer
+       jsr fork_copy
+
+       ; We are now in the kernel child context
+
+        ; now the copy operation is complete we can get rid of the stuff
+        ; _switchin will be expecting from our copy of the stack.
+       pulx
+
+        ldd fork_proc_ptr
+        jsr newproc
+
+       ; any calls to map process will now map the childs memory
+
+        ; runticks = 0;
+        clr runticks
+        ; 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().
+        rts
+
+fork_copy:
+       ; FIXME
+       rts                     ; this stack is copied so safe to return on
+
+