changeset 3170:18306d646f71

mc09: First release of working L2 port to MC09 platform Kernel has conditional code so should build for all targets, but it's been split out into a separate file to avoid polluting the main code. The included system call source code only has minor conditional additions so it is shared.
author Neal Crook <foofoobedoo@gmail.com>
date Thu, 20 Apr 2017 20:15:19 +0100
parents 1ff3d7673e36
children 0116eacf444a
files level1/modules/rel.asm level2/mc09l2/bootfiles/makefile level2/mc09l2/modules/makefile level2/modules/kernel/falltsk.asm level2/modules/kernel/fld.asm level2/modules/kernel/fldabx.asm level2/modules/kernel/fmove.asm level2/modules/kernel/fsrqmem.asm level2/modules/kernel/mc09krn.asm
diffstat 9 files changed, 1732 insertions(+), 93 deletions(-) [+]
line wrap: on
line diff
--- a/level1/modules/rel.asm	Mon Apr 17 22:59:28 2017 +0100
+++ b/level1/modules/rel.asm	Thu Apr 20 20:15:19 2017 +0100
@@ -1,4 +1,4 @@
-********************************************************************
+*******************************************************************
 * REL - Relocation routine
 *
 * $Id$
@@ -11,24 +11,24 @@
 *
 *          2004/11/09  P.Harvey-Smith
 * Added code to flip Dragon Alpha into text mode on boot.
-* 
+*
 
          nam   REL
          ttl   Relocation routine
 
-         IFP1
+       IFP1
          use   defsfile
-         ENDC
+       ENDC
 
 XX.Size  equ   6          number of bytes before REL actually starts
 Offset   equ   Bt.Start+XX.Size
-         IFEQ  Level-1
+       IFEQ  Level-1
 ScStart  equ   $8000      screen start in memory
-         ELSE
+       ELSE
 ScStart  equ   $8008      screen start in memory
-         ENDC
+       ENDC
 
-tylg     set   Systm+Objct   
+tylg     set   Systm+Objct
 atrv     set   ReEnt+rev
 rev      set   $05
 edition  set   5
@@ -50,45 +50,283 @@
          IFGT  Level-1
 
 *************************************************************************
-* Level2/level3
+** Start of Level2/Level3 code
+**
+** The boot-loader loads the "kernelfile" from track34 of the disk into
+** memory at $26xx and then jumps into it at address $2602. The
+** kernelfile is formed by concatenating the modules REL, BOOT, KRN.
+** The entry point jumps via the REL module header to label "start".
+**
+** One function of REL is to copy the kernelfile from $26xx to high
+** memory (specifically, to Bt.Start). $1200 bytes are copied.
+**
+** The size of each of these modules is controlled with filler bytes (eg,
+** see label "Filler" below) so that (after relocation):
+** REL  starts at $ED00 and is $130 bytes in size
+** BOOT starts at $EE30 and is $1D0 bytes in size
+** KRN  starts at $F000 and ends at $FEFF (but the 'emod' comes before
+**      the end of krn -- refer to the source file for details)
+**
+** When REL starts, it has NO STACK
+*************************************************************************
+
+       IFNE  mc09
+
+*************************************************************************
+** Start of Level2 code for mc09 ****************************************
 *************************************************************************
 
-L001F    fcb   $6C      MMU, IRQ, Vector page, SCS
-         fcb   $00      map type 0
-         fcb   $00      no FIRQ
-         fcb   $00      no IRQ
-         fdb   $0900    timer
-         fcb   $00      unused
-         fcb   $00      unused
-         IFEQ  TkPerSec-50
-         fcb   $0B	50Hz refresh, alphanumeric display, 8 lines/char row
-         ELSE
-         fcb   $03	60Hz refresh, alphanumeric display, 8 lines/char row
-         ENDC
+crash    lda   #'*        signal a crash error
+         jsr   <D.BtBug
+         tfr   b,a        save error code
+         jsr   <D.BtBug   and dump this out, too
+badbad   bra   badbad
+
+
+* Entry point for REL. Code is currently running at $26xx. Arrive with
+* MMU enabled (with 1-1 mapping), ROM disabled, TR=0, FRT=0.
+*
+* The MMU (which Coco calls Dynamic Address Translator, DAT) maps
+* 8Kbyte blocks of physical memory into 8Kbyte regions of the CPU
+* address space.
+*
+* There don't seem to be consistent names for stuff but I try to use:
+* Page             - a 256Byte region of memory
+* Block            - an 8Kbyte hunk of physical memory
+* Map              - an 8Kbyte region of CPU address space. Map 0-7
+*                    are addressed when TR=0, Map 8-15 are in use
+*                    when TR=1.
+* Mapping register - one of 16 registers (8 for TR=0, 8 for TR=1)
+*                    that control which block appears in which map.
+*
+* There are 64 blocks ($00-$3F) on 512K system, 128 blocks ($00-7F)
+* on 1MByte system. At the moment we assume 512K.
+*
+* In order to start krn, need to:
+* - put block   0 in map 0 ($0000 in CPU address space)
+* - put block   7 in map 7 ($E000 in CPU address space)
+* - enable FRT (makes top 512 locations of block 7 permanently
+*   mapped at CPU address $FE00 - $FFFF).
+*
+* Need to use block 7 for the top of memory because that is where
+* the mc09 MMU hardware implements the special fixed-RAM-top (FRT)
+* functionality that keeps a tiny piece of the NitrOS9 kernel
+* permanently mapped into memory.
+*
+* This is different from the COCO, which uses block $3f. $3f also
+* holds the I/O space on COCO whereas for mc09, the I/O space overlays
+* and is not affected by the MMU at all.
+
+start    ldx   #MMUADR
+         lda   #(MMU_TR0|0)     Select mapping reg 0, with TR=0
+         ldb   #$0              Select bottom block of physical memory
+         std   ,x               Write A to MMUADR to set MAPSEL=0, then write B to MMUDAT
+
+         lda   #(MMU_TR0|7)     Select mapping reg 7, with TR=0
+         ldb   #$7              Select block 7 of physical memory (512Kbyte system)
+         std   ,x               Write A to MMUADR to set MAPSEL=7, then write B to MMUDAT
+
+         lda   #MMU_TR0FRT
+         sta    ,x              Enable FixedRamTop
+
+* The setup below has been reordered compared with the Coco code. This code does
+* the copy/branch high before any of the page0 setup, reflecting an earlier code
+* version where MMU setup was deferred (and so page0 was not yet mapped). Could restore
+* the Coco ordering, if that allows more common code, or just leave it as-is.
+
+* Copy kernelfile image from $26xx to Bt.Start ($ED00)
+L00E2    tfr   pc,d       get the address at which we're executing
+         cmpa  #$26       the bootfile starts out at $2600
+         bne   L0101      if not at $26xx, already copied: continue with booting
+         ldu   #$2600     else move rel, Boot, krn over
+         ldx   #$1200     number of bytes to copy
+         ldy   #Bt.Start  where to put it
+
+cpkrn    ldd   ,u++       from
+         std   ,y++       to
+         leax  -2,x       update count
+         bne   cpkrn
+* Go to copy in high memory
+         jmp   >Offset+L0101
+
+* Now executing at $EDxx
+L0101    ldb   #$FF       negative - do complete boot
+
+start1   orcc  #IntMasks  turn off IRQ's
+
+* [NAC HACK 2016Dec05] todo: turn off timer interrupt in case this is a reboot
+
+         clra             make A=0 for later
+         tfr   a,dp
+         clr   <D.CBStrt  cold boot start: don't re-boot on reset
+
+         lds   #$1FFF     set stack to the end of block 0
+         stb   ,-s        save status of start, $00=cold, $01=warm [NAC HACK 2016Dec06] $FF = startup: do complete boot (above)
+* This is done so I can tell what went on in the direct page if there's
+* a crash. 0(crash) 1(reset) -1(startup)
+*         beq   Cont       --don't clear out direct page if it's a crash
+
+         clrb             clear out ALL of direct page
+         tfr   d,x        here, too
+L0072    sta   ,x+        clear out the direct page
+         incb             Boot won't be using any of it!
+         bne   L0072      BUT RAMMER/MD DOES!!!
+
+* Use D.TINIT as a shadow of the MMU address register, so that we can
+* do read/mod/write of TR bit later on
+         lda   #MMU_TR0
+         sta   <D.TINIT
+
+
+**         tst   ,s         check status : 0(crash) 1(reset) -1(startup)
+**         bmi   StoreQ     if NOT a crash or reset, start at the start...
+**         bne   ClrLoop
+
+MoveTxt  leau  <BootMsg,pcr point to OS-9 Welcome Message
+         bsr   OutMsg
+* 0  = crash
+* 1  = reset
+* -1 = startup
+         ldb   ,s+        check state of boot
+         bne   L0101a     if OK, continue
+* X pointing to FailMsg
+         bsr   OutMsg
+L00E0    bra   L00E0      loop forever
+
 
-         IFEQ  Width-80
-         fcb   $34 200 lines, 80 column mode, no attribute byte (monochrome)
-         fcb   $3F        white border
-BOOTLINE set   11	80-col start line for BOOT/FAIL messages
-         ENDC
+* display null-terminated message at U to UART. U, A, CC updated.
+OutMsg   lda   VDUSTA
+         bita  #2
+         beq   OutMsg
+         lda   ,u+
+         beq   MsgDone
+         sta   VDUDAT
+         bra   OutMsg
+MsgDone  rts
+
+
+BootMsg
+         fcc   /NITROS9 BOOT/
+         fcb   0
+FailMsg
+         fcc   / FAILED/
+         fcb   0
+
+
+* Copy X bytes from U to Y
+L00FD    lda   ,u+
+         sta   ,y+
+         leax  -1,x
+         bne   L00FD
+         rts
+
 
-         IFEQ  Width-40
-         fcb   $24 200 lines, 40-col, no attribute byte
-         fcb   $3F        white border
-BOOTLINE set   13	40-col start line for BOOT/FAIL messages
-         ENDC
+* Debug routine. Not executed here, but copied to D.Crash
+* [NAC HACK 2017Jan21] the copy/space assigned is 16 bytes
+* [NAC HACK 2017Jan21] so make sure it fits!! Ought to be a check..
+* Come here with ASCII code in A. Clear bit 7 then
+* display code on the VDU at the current cursor position.
+* All registers except A are preserved. Vital to preserve CC
+* because the caller needs it to detect that bit 7 was set -
+* indicating the end of the string for some callers.
+BtDebug  pshs  cc,d,x     save the registers
+DebBsy   ldb   VDUSTA
+         bitb  #2
+         beq   DebBsy     wait until UART non-full
+         anda  #$7f       make valid ASCII
+         sta   VDUDAT     send character
+         puls  cc,d,x,pc  restore regs and exit
+
+
+
+* [NAC HACK 2016Dec06] not sure there's any logic to what's done
+* while we're at $2600 and what's done now we're at $EExx
+* ..I think the distinction is what's done on a reboot-without-reload. Check.
+* [NAC HACK 2016Dec06] At D.BtBug there are 3 bytes which
+* default to RTS <16-bit address of debug routine>
+* for debug, change the RTS ($39) to JMP ($7E)
+* Come here in high memory: $EExx
+L0101a
+*         lda   #$39       RTS
+         lda   #$7E       JMP
+         sta   <D.BtBug
+         leax  <BtDebug,pc point to debug routine
+         stx   <D.BtBug+1
+
+         leau  <R.Crash,pcr point to D.Crash, D.CBStart
+         ldy   #D.Crash   move it over
+         ldx   #$10
+         bsr   L00FD
+
 
-         IFEQ  Width-32
-         fcb   $20 200 lines, 32-col, no attribute byte
-         fcb   $00        black border
-BOOTLINE set   13	32-col start line for BOOT/FAIL messages
-         ENDC
+         ldx   #$F000     we KNOW where krn module starts in memory
+         ldd   M$Exec,x   get execution start address of module
+         jmp   d,x        jump to it
+
+* D.Crash
+R.Crash
+*[NAC HACK 2017Jan21] since we're not planning to crash it's OK to comment this out, for now,
+*[NAC HACK 2017Jan21] but I'm puzzled about why we'd set TR=0 (user mode??) on a crash
+*[NAC HACK 2016Dec08] L003F    clr   >$FF91     go to map type 0 - called by CC3Go from map 1
+         jmp   >Offset+crash
+
+         fcb   $00        warm start flag
+         fdb   $0074      go to $0074, next routine
+
+* reset vector: map ROMs out and go to REL in the default DECB block map,
+* which is still block $3F at the top of memory
+         nop              required for the ROMs to believe it's a reset vector
+         clr   >$FFDF     go to all RAM mode
+**[NAC HACK 2016Dec05]          jmp   >Offset+reset and re-start the boot
+
+* Filler to get to a total size of $130. XX.Size is bytes at the start of
+* this file - before the module header. 3 is bytes after this filler - the
+* end boilerplate for the module.
+Filler   fill  $39,$130-XX.Size-3-*
+
+       ELSE                          match IFNE mc09
+
+**************************************************************************
+** Start of Level2/Level3 code for coco3 *********************************
+**************************************************************************
 
-         fcb   $00 display in lower 512k bank
-         fcb   $00 vertical fine scroll set to 0
-         fcb   Bt.Block*4  display block where-ever
-         fcb   $01 offset 8 bytes
-         fcb   $00 no horizontal scroll
+* GIME setup data stored at $FF90-$FF9F and in direct page
+L001F    fcb   $6C      D.HINIT  MMU, IRQ, Vector page, SCS
+         fcb   $00      D.TINIT  set MMU map type 0
+         fcb   $00      D.IRQER  no FIRQ
+         fcb   $00      D.FRQER  no IRQ
+         fdb   $0900    D.TIMxx  timer
+         fcb   $00      D.RESV1  unused
+         fcb   $00      D.RESV2  unused
+       IFEQ  TkPerSec-50
+         fcb   $0B      D.VIDMD  50Hz refresh, alphanumeric display, 8 lines/char row
+       ELSE
+         fcb   $03      D.VIDMD  60Hz refresh, alphanumeric display, 8 lines/char row
+       ENDC
+
+       IFEQ  Width-80
+         fcb   $34      D.VIDRS  200 lines, 80 column mode, no attribute byte (monochrome)
+         fcb   $3F      D.BORDR  white border
+BOOTLINE set   11       80-col start line for BOOT/FAIL messages
+       ENDC
+
+       IFEQ  Width-40
+         fcb   $24      D.VIDRS  200 lines, 40-col, no attribute byte
+         fcb   $3F      D.BORDR  white border
+BOOTLINE set   13       40-col start line for BOOT/FAIL messages
+       ENDC
+
+       IFEQ  Width-32
+         fcb   $20      D.VIDRS  200 lines, 32-col, no attribute byte
+         fcb   $00      D.BORDR  black border
+BOOTLINE set   13       32-col start line for BOOT/FAIL messages
+       ENDC
+
+         fcb   $00      D.RESV3  (Distro 2Byte updates) display in lower 512k bank
+         fcb   $00      D.VOFF2  vertical fine scroll set to 0
+         fcb   Bt.Block*4  D.VOFF1 display block where-ever
+         fcb   $01      D.VOFF0  offset 8 bytes
+         fcb   $00      D.HOFF0  no horizontal scroll
 
 crash    lda   #'*        signal a crash error
          jsr   <D.BtBug
@@ -115,7 +353,18 @@
          tfr   a,dp
          ENDC
          clr   <D.CBStrt  cold boot start: don't re-boot on reset
-         clr   >$FFA0     map in block 0
+
+* Coco3 enters this code with TR=1 and the MMU mappings set thus:
+* TR=0: map 0-7: $??,$39,$3A,$3B,$3C,$3D,$3E,$3F
+* TR-1: map 0-7: $38,$30,$31,$32,$33,$3D,$35,$3F
+*
+* Enter krn with TR=0. Only 2 (TR=0) mappings need to be set up:
+* Physical RAM block $3F mapped to the top of memory (already by default)
+* Physical RAM block $0  mapped to the bottom of memory.
+*
+* RAM block 0 about to get mapped. TR set to 0 by the GIME setup below.
+
+         clr   >DAT.Regs+0 map RAM block 0 to block 0 in DAT
          lds   #$1FFF     set stack to the end of the block
          stb   ,-s        save status of start, $00=cold, $01=warm
 * This is done so I can tell what went on in the direct page if there's
@@ -134,6 +383,9 @@
          leay  <L001F,pcr point to the video setup data
          ldx   #$0090     set video mapping
          deca             now D=$FF00, versus STU >-$0100,x (saves 1 byte)
+
+* Copy setup data to (1) the GIME at $FF90-$FFA0 and (2) shadow copy
+* in the direct page at $0090 (D.HINIT etc).
 L0084    ldu   ,y++       get the bytes
          stu   d,x        save in the hardware
          stu   ,x++       and in the direct page
@@ -159,7 +411,7 @@
          bmi   StoreQ     if NOT a crash or reset, start at the start...
          cmpd  ,x         are they the same?
          beq   MoveTxt    don't bother clearing the screen if it's there
-StoreQ   
+StoreQ
          IFNE  H6309
          stq   ,x         otherwise save the bytes on-screen
          ELSE
@@ -211,7 +463,7 @@
          leax  -1,x
          bne   L00FD
          ENDC
-         rts   
+         rts
 
 L0011    fdb   ScStart+(BOOTLINE*Width)+((Width-L1)/2)
          fcb   L1         length of the text below
@@ -248,7 +500,7 @@
          clr   >$FFA0     map block 0 in again
          puls  cc,d,x,pc  restore X and exit
 
-L0101    
+L0101
          lda   #$7E       RTS
          sta   <D.BtBug
          leax  <BtDebug,pc point to debug routine
@@ -270,7 +522,7 @@
          jmp   d,x        jump to it
 
 * D.Crash
-R.Crash  fcb   $10        size of the data to move over
+R.Crash  fcb   $10        size of the data to move over - 6 for D.Crash, $B for D.CBStrt
 L003F    clr   >$FF91     go to map type 0 - called by CC3Go from map 1
          jmp   >Offset+crash
 
@@ -283,28 +535,40 @@
          clr   >$FFDF     go to all RAM mode
          jmp   >Offset+reset and re-start the boot
 
-* L2 kernel file is composed of rel, boot, krn. The size of each of these
-* is controlled with filler, so that (after relocation):
-* rel  starts at $ED00 and is $130 bytes in size
-* boot starts at $EE30 and is $1D0 bytes in size
-* krn  starts at $F000 and ends at $FEFF (there is no 'emod' at the end
-*      of krn and so there are no module-end boilerplate bytes)
-*
 * Filler to get to a total size of $130. XX.Size is bytes at the start of
 * this file - before the module header. 3 is bytes after this filler - the
 * end boilerplate for the module.
 Filler   fill  $39,$130-XX.Size-3-*
 
+         ENDC                          match IFNE mc09
          ELSE                          match IFGT Level-1
 
 *************************************************************************
-* Entry point for level1
+** Start of Level1 code
+**
+** The boot-loader loads the "kernelfile" from track34 of the disk into
+** memory at $26xx and then jumps into it at address $2602. The
+** kernelfile is formed by concatenating modules REL, BOOT, KRN,
+** KRNP2, INIT -- and maybe others, depending upon the hardware
+** configuration.
+** The entry point jumps via the REL module header to label "start".
+**
+** One function of REL is to copy the kernelfile from $26xx to high
+** memory (specifically, to Bt.Start). Bt.Size ($1000-$1080) bytes are
+** copied.
+**
+** Unlike the Level2/Level3 case, the size of each of the modules in the
+** kernelfile is not padded.
+**
+** When REL starts, it has NO STACK
+*************************************************************************
+
+*************************************************************************
+* Entry point for Level1 (all platforms) ********************************
 *************************************************************************
 
 Start
-         IFNE  mc09
-* currently we have NO STACK
-
+       IFNE  mc09
          leax  <BootMsg,pcr
 outbsy   lda   VDUSTA
          bita  #2
@@ -315,16 +579,16 @@
          bra   outbsy
 
 done
-         ELSE                          match IFNE mc09
+       ELSE                          match IFNE mc09
 
          clr   PIA0Base+3
 
-         IFNE  (tano+d64+dalpha)
+       IFNE  (tano+d64+dalpha)
          clr   PIA0Base+1              added for Dragon, works on CoCo
-         ENDC
-         IFNE  H6309
+       ENDC
+       IFNE  H6309
          ldmd  #3                      native mode
-         ENDC
+       ENDC
 
          sta   $FFDF                   turn off ROM
 * locate Boot Text Screen at $8000
@@ -335,15 +599,15 @@
          bne   L262B
          sta   1,x
 
-	 IFNE	dalpha
-	 clr	$ffc0		* Reset to text mode if Dragon Alpha
-	 clr	$ffc2
-	 clr	$ffc4
-	
-	 lda	$ff22
-	 anda	#$07
-	 sta	$ff22
-	 ENDC
+       IFNE   dalpha
+         clr    $ffc0                Reset to text mode if Dragon Alpha
+         clr    $ffc2
+         clr    $ffc4
+
+         lda    $ff22
+         anda   #$07
+         sta    $ff22
+       ENDC
 
 * Clear VDG screen
          ldx   #ScStart
@@ -362,16 +626,16 @@
          decb
          bne   L2649
 
-         IFNE  (tano+d64+dalpha)
+       IFNE  (tano+d64+dalpha)
          tst   <$72
-         ELSE
+       ELSE
          ldd   #$1212
          cmpd  <$0078
-         ENDC
+       ENDC
 
          beq   L266E
 
-         ENDC              match IFNE mc09
+       ENDC              match IFNE mc09
 
 * Copy boot track from $2600 to $EE00 - not quite all of it though. The whole boot
 * track is $1200 bytes and would take us right up to $FFFF. We actually copy up to
@@ -394,18 +658,18 @@
          jmp   d,x
 
 BootMsg
-         IFNE  mc09
+       IFNE  mc09
          fcn   / Boot /
-         ELSE
-         IFNDEF dalpha		save some bytes on Dragon Alpha
+       ELSE
+       IFNDEF dalpha          save some bytes on Dragon Alpha
          fcc   /NITROSy/
          fcb   $60
-         ENDC
+       ENDC
          fcc   /BOOT/
 BootMLen equ   *-BootMsg
-         ENDC                   match IFNE mc09
+       ENDC                   match IFNE mc09
 
-         ENDC                   match IFGT Level-1
+       ENDC                   match IFGT Level-1
 
          emod
 eom      equ   *
--- a/level2/mc09l2/bootfiles/makefile	Mon Apr 17 22:59:28 2017 +0100
+++ b/level2/mc09l2/bootfiles/makefile	Thu Apr 20 20:15:19 2017 +0100
@@ -7,7 +7,7 @@
 DEPENDS		= ./makefile
 
 # The _80 in rel_80 refers to 80-column screen
-KERNEL_MC09SD	= $(MD)/rel_80 $(MD)/boot_sdc $(MD)/krn
+KERNEL_MC09SD	= $(MD)/rel_80 $(MD)/boot_sdc $(MD)/mc09krn
 
 MC09SDC_80D	= $(MD)/mc09sdc.dr $(MD)/dds0_80d.dd $(MD)/s0_80d.dd $(MD)/s1_80d.dd $(MD)/s2_80d.dd $(MD)/s3_80d.dd
 
--- a/level2/mc09l2/modules/makefile	Mon Apr 17 22:59:28 2017 +0100
+++ b/level2/mc09l2/modules/makefile	Thu Apr 20 20:15:19 2017 +0100
@@ -14,7 +14,7 @@
 TPB		= $(3RDPARTY)/booters
 
 BOOTERS		= boot_sdc
-BOOTTRACK	= rel_80 $(BOOTERS) krn
+BOOTTRACK	= rel_80 $(BOOTERS) mc09krn
 
 KERNEL		= krnp2 krnp3_perr krnp4_regdump
 SYSMODS		= ioman init sysgo_dd rominfo vectors
@@ -49,14 +49,14 @@
 # The following macros represent a collection of modules for various
 # kernel tracks and bootfile configurations.
 #
-KERNEL_MC09SD	= rel_80 boot_sdc krn
+KERNEL_MC09SD	= rel_80 boot_sdc mc09krn
 
 ALLOBJS		=  $(BOOTTRACK) $(KERNEL) $(SYSMODS) $(CLOCKS) $(RBF) $(SCF) $(PIPE) $(RFM)
 
 all:	$(ALLOBJS)
 
 # Kernel
-ccbkrn krn krnp2:
+mc09krn krn krnp2:
 	$(CD) kernel; make $@
 	$(OS9COPY) kernel/$@ .
 
--- a/level2/modules/kernel/falltsk.asm	Mon Apr 17 22:59:28 2017 +0100
+++ b/level2/modules/kernel/falltsk.asm	Thu Apr 20 20:15:19 2017 +0100
@@ -82,7 +82,11 @@
          stu   b,x          save DAT image pointer in task table
          cmpb  #2           is it either system or GrfDrv?
          bhi   L0C9F        no, return
+      IFNE  mc09
+         lda   <D.TINIT
+      ELSE
          ldx   #DAT.Regs    update system DAT image
+      ENDC
          lbsr  L0E93        go bash the hardware
 L0C9F    puls  cc,d,x,u,pc
 
--- a/level2/modules/kernel/fld.asm	Mon Apr 17 22:59:28 2017 +0100
+++ b/level2/modules/kernel/fld.asm	Thu Apr 20 20:15:19 2017 +0100
@@ -22,6 +22,14 @@
          clrb                 Clear carry/setup for STB
          pshs  cc             Preserve interrupt status/settings
          orcc  #IntMasks      shut IRQ's off
+       IFNE  mc09
+         ldb   <D.TINIT       Current MMU mask - selects block 0
+         stb   >MMUADR        Select block 0
+         sta   >MMUDAT        Map block into $0000-$1FFF
+         lda   ,x             Get byte
+         clrb
+         stb   >MMUDAT        Map block 0 into $0000-$1FFF
+       ELSE
          sta   >DAT.Regs      Map block into $0000-$1FFF
          IFNE  H6309
          brn    L0AC8         short delay
@@ -31,6 +39,7 @@
          IFNE  H6309
          brn    L0AC8         short delay
          ENDC
+       ENDC
          puls  pc,cc          Get interrupt status/(or turn on) & return
 
 * Get 1st byte of LDDDXY - also used by many other routines
@@ -39,9 +48,18 @@
          pshs  b,cc
          clrb                 Clear carry/setup for STB
          orcc  #IntMasks      Shut off interrupts
+       IFNE  mc09
+         ldb   <D.TINIT       Current MMU mask - selects block 0
+         stb   >MMUADR        Select block 0
+         sta   >MMUDAT        Map in MMU block into slot 0
+         lda   ,x+            Get byte
+         clrb
+         stb   >MMUDAT        Map block 0 back in
+       ELSE
          sta   >DAT.Regs      Map in MMU block into slot 0
          lda   ,x+            Get byte
          stb   >DAT.Regs
+       ENDC
 *         clr   >DAT.Regs     Map in MMU block #0 into slot 0
 *         andcc #^IntMasks
          puls  b,cc
@@ -77,15 +95,19 @@
 
 * Get 2 bytes for LDDDXY (also called by other routines)
 * Should simply map in 2 blocks, and do a LDD (don't have to worry about wrap)
+       IFNE  mc09
+L0B02    pshs  u,y,x,dp       Preserve regs (x, y adjusted by AdjBlk0)
+       ELSE
 L0B02    pshs  u,y,x          Preserve regs (x, y adjusted by AdjBlk0)
-         IFNE  H6309
+       ENDC
+
+       IFNE  H6309
          addr  d,x            Point X to X+D
-         ELSE
+       ELSE
          leax  d,x
-         ENDC
+       ENDC
          bsr   AdjBlk0        Wrap address around for 1 block
          ldu   <D.SysDAT      Get sys DAT Image ptr
-*         lda   1,u            Get MMU block #0
          clra                 system block 0 =0 always
          ldb   3,u            Get MMU block #1
          tfr   d,u            make U=blocks to re-map in once done
@@ -93,7 +115,35 @@
          ldb   3,y            Get MMU block #1
          pshs  cc             Preserve int. status
          orcc  #IntMasks      shut off int.
+       IFNE  mc09
+         lda   <D.TINIT       Current MMU mask - selects block 0
+         inca                 Select block 1
+
+         ldb   1,y            Get MMU block #0
+         tfr   b,dp           Save it for later
+         ldb   3,u            Get restore value for MMU block #1
+         tfr   d,u            Save it for later
+
+         ldb   3,y            Get MMU block #1
+         std   >MMUADR        Set address and block 1
+
+         deca                 Select block 0
+         tfr   dp,b
+         std   >MMUADR        Set address and block 0
+
+         ldy   ,x             Get 2 bytes
+
+         tfr   u,d
+         std   >MMUADR        Restore original MMU block #1
+         deca                 Select block 0
+         clrb                 system block 0 =0 always
+         std   >MMUADR        Restore original MMU block #0
+
+         tfr   y,d            Put the data in the right place
+         puls  pc,u,y,x,dp,cc Restore regs & return
+       ELSE
          std   >DAT.Regs      Map in both blocks
          ldd   ,x             Get 2 bytes
          stu   >DAT.Regs      Map original blocks in
          puls  pc,u,y,x,cc    Restore regs & return
+       ENDC
--- a/level2/modules/kernel/fldabx.asm	Mon Apr 17 22:59:28 2017 +0100
+++ b/level2/modules/kernel/fldabx.asm	Thu Apr 20 20:15:19 2017 +0100
@@ -19,11 +19,20 @@
 * Exit : B=Byte from other task
 L0C40    pshs  cc,a,x,u
          bsr   L0BF5        Calculate offset into DAT image (fmove.asm)
-         ldd   a,u
+         ldd   a,u          [NAC HACK 2017Jan25] why ldd when a is never used??
          orcc  #IntMasks
+      IFNE  mc09
+         lda   <D.TINIT     Current MMU mask - selects block 0
+         sta   >MMUADR      Select block 0
+
+         stb   >MMUDAT      Map selected block into $0000-$1FFF
+         ldb   ,x
+         clr   >MMUDAT      Restore mapping at $0000-$1FFF
+      ELSE
          stb   >DAT.Regs    Map block into $0000-$1FFF
          ldb   ,x
          clr   >DAT.Regs    Restore mapping at $0000-$1FFF
+      ENDIF
          puls  cc,a,x,u
 
          stb   R$A,u        Save into caller's A & return
@@ -63,9 +72,21 @@
          pshs  cc,d,x,u
          bsr   L0BF5        Calculate offset into DAT image (fmove.asm)
          ldd   a,u          Get memory block
+      IFNE  mc09
+         orcc  #IntMasks
+         lda   <D.TINIT     Current MMU mask - selects block 0
+         sta   >MMUADR      Select block 0
+
+         lda   1,s          Haven't lost stack yet so this is safe
+
+         stb   >MMUDAT      Map selected block into $0000-$1FFF
+         sta   ,x
+         clr   >MMUDAT      Restore mapping at $0000-$1FFF
+      ELSE
          lda   1,s
          orcc  #IntMasks
          stb   >DAT.Regs    Map selected block into $0000-$1FFF
          sta   ,x
          clr   >DAT.Regs    Restore mapping at $0000-$1FFF
+      ENDIF
          puls  cc,d,x,u,pc
--- a/level2/modules/kernel/fmove.asm	Mon Apr 17 22:59:28 2017 +0100
+++ b/level2/modules/kernel/fmove.asm	Thu Apr 20 20:15:19 2017 +0100
@@ -19,10 +19,10 @@
 * in the $AXXX range, and as a result, the process stack pointer would get
 * switched out when $FFA5-$FFA6 was written and the stack would disappear.
 *
-         IFEQ  H6309
+       IFEQ  H6309
 L0A01    clrb
          rts
-         ENDC
+       ENDC
 
 FMove    ldd   R$D,u        get source & destination task #'s
 L0B25    ldy   R$Y,u        Get # bytes to move
@@ -146,10 +146,27 @@
 L0B84    std   $0F,s
          puls  y
          orcc  #IntMasks
+       IFNE  mc09
+         lda   <D.TINIT     Current MMU mask - selects block 0
+         ora   #5
+         sta   >MMUADR      Select block 5
+         lda   $0E,s        stack could disappear in the remapping..
+         exg   d,y          swap them; final destination for d
+         sta   >MMUDAT
+***** NO STACK USE BETWEEN HERE.....
+         lda   <D.TINIT     Current MMU mask - selects block 0
+         ora   #6
+         sta   >MMUADR      Select block 6
+         stb   >MMUDAT
+* the coco code did a "tfr d,y". mc09 did a "exg d,y" which
+* left y correct but we also need d=y at the end..
+         tfr   y,d
+       ELSE
          lda   $0E,s  +++
          sty   >DAT.Regs+5
 ***** NO STACK USE BETWEEN HERE.....
          tfr   d,y    +++
+       ENDIF
          andb  #$07
          beq   L0B99
 L0B92    lda   ,x+
@@ -191,9 +208,21 @@
          bne   L0BA4  +++
          exg   x,u
 L0BBC    ldy   <D.SysDAT
+       IFNE  mc09
+         lda   <D.TINIT     Current MMU mask - selects block 0
+         ora   #5
+         sta   >MMUADR      Select block 5
+         ldb   $0B,y
+         stb   >MMUDAT      Restore it
+         inca
+         sta   >MMUADR      Select block 6
+         ldb   $0D,y
+         stb   >MMUDAT      Restore it
+       ELSE
          lda   $0B,y
          ldb   $0D,y
          std   >DAT.Regs+5
+       ENDIF
 ***** AND HERE...........
          puls  cc
          ldd   $0E,s
--- a/level2/modules/kernel/fsrqmem.asm	Mon Apr 17 22:59:28 2017 +0100
+++ b/level2/modules/kernel/fsrqmem.asm	Thu Apr 20 20:15:19 2017 +0100
@@ -258,7 +258,7 @@
 * Link to module and execute
 L090C    lda   #Systm+Objct
          os9   F$Link
-         bcs   L08F3        return with error
+         bcs   L08F3        return with error.
          lda   #'b          calling boot
          jsr   <D.BtBug
          jsr   ,y           load boot file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/level2/modules/kernel/mc09krn.asm	Thu Apr 20 20:15:19 2017 +0100
@@ -0,0 +1,1271 @@
+********************************************************************
+* krn - NitrOS-9 Level 2 Kernel
+*
+* $Id$
+*
+* Edt/Rev  YYYY/MM/DD  Modified by
+* Comment
+* ------------------------------------------------------------------
+*  19r6    2002/08/21  Boisy G. Pitre
+* Assembles to the os9p1 module that works on my NitrOS-9 system.
+*
+*  19r7    2002/09/26  Boisy G. Pitre
+* Added check for CRC feature bit in init module
+*
+*  19r8    2003/09/22  Boisy G. Pitre
+* Back-ported to OS-9 Level Two.
+*
+*  19r8    2004/05/22  Boisy G. Pitre
+* Renamed to 'krn'
+*
+*  19r9    2004/07/12  Boisy G. Pitre
+* F$SRqMem now properly scans the DAT images of the system to update
+* the D.SysMem map.
+
+        nam     krn
+        ttl     NitrOS-9 Level 2 Kernel
+
+        IFP1
+        use     defsfile
+        ENDC
+
+* defines for customizations
+Revision        set     9       module revision
+Edition set     19      module Edition
+Where   equ     $F000   absolute address of where Kernel starts in memory
+
+        mod     eom,MName,Systm,ReEnt+Revision,entry,0
+
+MName   fcs     /Krn/
+        fcb     Edition
+
+* The 8K RAM block that is mapped to $E000-$FFFF and holds
+* the kernel and I/O space. $3f for COCO, $7 for mc09.
+KrnBlk  set     $7
+
+
+* Might as well have this here as just past the end of Kernel...
+DisTable
+        fdb     L0CD2+Where     D.Clock absolute address at the start
+        fdb     XSWI3+Where     D.XSWI3
+        fdb     XSWI2+Where     D.XSWI2
+        fdb     D.Crash         D.XFIRQ crash on an FIRQ
+        fdb     XIRQ+Where      D.XIRQ
+        fdb     XSWI+Where      D.XSWI
+        fdb     D.Crash         D.XNMI crash on an NMI
+        fdb     $0055           D.ErrRst ??? Not used as far as I can tell
+        fdb     Sys.Vec+Where   Initial Kernel system call vector
+DisSize equ     *-DisTable
+* ^
+* Code using 'SubSiz', below, assumes that SubStrt follows on directly after
+* the end of DisTable. Therefore, DO NOT ADD ADD ANYTHING BETWEEN THESE 2 LABELS
+* v
+LowSub  equ     $0160           start of low memory subroutines
+SubStrt equ     *
+* D.Flip0 - switch to system task 0
+R.Flip0 equ     *
+        IFNE    H6309
+        aim     #$FE,<D.TINIT   map type 0
+        lde     <D.TINIT        another 2 bytes saved if GRFDRV does: tfr cc,e
+        ste     >DAT.Task       and we can use A here, instead of E
+        ELSE
+        pshs    a
+        lda     <D.TINIT        Get value from shadow
+      IFNE  mc09
+        anda    #$BF            force TR=0
+        sta     <D.TINIT        Update shadow
+        sta     >MMUADR         Update MMU
+      ELSE
+        anda    #$FE            force TR=0
+        sta     <D.TINIT
+        sta     >DAT.Task
+      ENDC
+        puls    a
+        ENDC
+        clr     <D.SSTskN
+        tfr     x,s
+        tfr     a,cc
+        rts
+SubSiz  equ     *-SubStrt
+* ^
+* Code around L0065, below, assumes that Vectors follows on directly after
+* the end of R.Flip0. Therefore, DO NOT ADD ADD ANYTHING BETWEEN THESE 2 LABELS
+* v
+* Interrupt service routine
+Vectors jmp     [<-(D.SWI3-D.XSWI3),x]  (-$10) (Jmp to 2ndary vector)
+
+      IFNE  mc09
+CPUVect fdb SWI3VCT+Where       SWI3  at $FFF2
+        fdb SWI2VCT+Where       SWI2  at $FFF4
+        fdb FIRQVCT+Where       FIRQ  at $FFF6
+        fdb IRQVCT+Where        IRQ   at $FFF8
+        fdb SWIVCT+Where        SWI   at $FFFA
+        fdb NMIVCT+Where        NMI   at $FFFC
+        fdb $0000+Where         RESET at $FFFE
+      ENDC
+
+* [NAC HACK 2016Dec07] to do a real reset on Multicomp09 need first to
+* disable the MMU and re-enable the ROM. Maybe implement a little blob
+* of code to do that? Otherwise, implement some kind of crash/dump.
+
+* Initialize the system block (the lowest 8Kbytes of memory)
+* rel.asm has cleared the DP already, so start at address $100.
+entry   equ     *
+      IFNE    H6309
+        ldq     #$01001f00      start address to clear & # bytes to clear
+        leay    <entry+2,pc     point to a 0
+        tfm     y,d+
+        std     <D.CCStk        set pointer to top of global memory to $2000
+        lda     #$01            set task user table to $0100
+      ELSE
+        ldx     #$100           start address
+        ldy     #$2000-$100     bytes to clear
+        clra
+        clrb
+L001C   std     ,x++            clear it 16-bits at a time
+        leay    -2,y
+        bne     L001C
+        stx     <D.CCStk        Set pointer to top of global memory to $2000
+        inca                    D = $0100
+      ENDC
+
+* Set up system variables in DP
+        std     <D.Tasks        set Task Structure pointer to $0100
+        addb    #$20
+        std     <D.TskIPt       set Task image table pointer to $0120
+        clrb
+
+********************************************************************
+* The memory block map is a data structure that is used to manage
+* physical memory. Physical memory is assigned in 8Kbyte "blocks".
+* 256 bytes are reserved for the map and so the maximum physical
+* memory size is 256*8Kbyte=2Mbyte. D.BlkMap is a pointer to the
+* start of the map (set to $0200, below). D.BlkMap+2 is a pointer
+* to the end of the map. Rather than simply setting it to $0300,
+* the end pointer is set by the memory sizing routine at L0111.
+* (Presumably) this makes it faster to search for unused pages
+* and also acts as the mechanism to avoid assigning non-existent
+* memory. A value of 0 indicates an unused block and since the
+* system block has been initialised to 0 (above) every block starts
+* off marked as unused. Initial reservation of blocks occurs
+* below, after the memory sizing.
+* See "Level 2 flags" in os9.d for other byte values.
+
+        inca                    set memory block map start pointer
+        std     <D.BlkMap       to $0200
+
+        inca                    set system service dispatch table pointer
+        std     <D.SysDis       to 0x300
+        inca                    set user dispatch table pointer to $0400
+        std     <D.UsrDis
+        inca                    set process descriptor block pointer to $0500
+        std     <D.PrcDBT
+        inca                    set system process descriptor pointer to $0600
+        std     <D.SysPrc
+        std     <D.Proc         set user process descriptor pointer to $0600
+        adda    #$02            set stack pointer to $0800
+        tfr     d,s
+        inca                    set system stack base pointer to $0900
+        std     <D.SysStk
+        std     <D.SysMem       set system memory map ptr $0900
+        inca                    set module directory start ptr to $0a00
+        std     <D.ModDir
+        std     <D.ModEnd       set module directory end ptr to $0a00
+        adda    #$06            set secondary module directory start to $1000
+        std     <D.ModDir+2
+        std     <D.ModDAT       set module directory DAT pointer to $1000
+        std     <D.CCMem        set pointer to beginning of global memory to $1000
+* In following line, CRC=ON if it is STA <D.CRC, CRC=OFF if it is a STB <D.CRC
+        stb     <D.CRC          set CRC checking flag to off
+
+* Initialize interrupt vector tables in DP by moving pointer data down from DisTable
+
+      IFNE  mc09
+* Brett's ccbkrn identified this as a bug in the original code..
+* which has not been fixed. Should be easy to demonstrate which is
+* correct..
+        leay    DisTable,pcr   point to table of absolute vector addresses
+      ELSE
+        leay    <DisTable,pcr   point to table of absolute vector addresses
+      ENDC
+        ldx     #D.Clock        where to put it in memory
+        IFNE    H6309
+        ldf     #DisSize        size of the table - E=0 from TFM, above
+        tfm     y+,x+           move it over
+        ELSE
+        ldb     #DisSize
+l@
+        lda     ,y+             load a byte from source
+        sta     ,x+             store a byte to dest
+        decb                    bump counter
+        bne     l@              loop if we're not done
+        ENDC
+
+* Initialize D.Flip0 routine in low memory by copying lump of code down from R.Flip0.
+* ASSUME: Y left pointing to R.Flip0 by previous copy loop.
+
+        ldu     #LowSub         somewhere in block 0 that's never modified
+        stu     <D.Flip0        switch to system task 0
+        IFNE    H6309
+        ldf     #SubSiz         size of it
+        tfm     y+,u+           copy it over
+        ELSE
+        ldb     #SubSiz
+Loop2   lda     ,y+             load a byte from source
+        sta     ,u+             and save to destination
+        decb                    bump counter
+        bne     Loop2           loop if not done
+        ENDC
+
+* Initialize secondary interrupt vectors to all point to Vectors for now
+* ASSUME: Y left pointing to Vectors by previous copy loop
+        tfr     y,u             move the pointer to a faster register
+L0065   stu     ,x++            Set all IRQ vectors to go to Vectors for now
+        cmpx    #D.NMI
+        bls     L0065
+
+      IFNE  mc09
+* Initialize CPU vectors
+        leay    CPUVect,pcr     Data source
+        ldx     #$FFF2          Data destination
+        ldb     #14             7 vectors to copy
+L0067   lda     ,y+
+        sta     ,x+
+        decb
+        bne     L0067
+      ENDC
+
+* Initialize user interupt vectors
+        ldx     <D.XSWI2        Get SWI2 (os9 command) service routine pointer
+        stx     <D.UsrSvc       Save it as user service routine pointer
+        ldx     <D.XIRQ         Get IRQ service routine pointer
+        stx     <D.UsrIRQ       Save it as user IRQ routine pointer
+
+        leax    >SysCall,pc     Setup System service routine entry vector
+        stx     <D.SysSvc
+        stx     <D.XSWI2
+
+        leax    >S.SysIRQ,pc    Setup system IRQ service vector
+        stx     <D.SysIRQ
+        stx     <D.XIRQ
+
+        leax    >S.SvcIRQ,pc    Setup in system IRQ service vector
+        stx     <D.SvcIRQ
+        leax    >S.Poll,pc      Setup interrupt polling vector
+        stx     <D.Poll         ORCC #$01;RTS
+        leax    >S.AltIRQ,pc    Setup alternate IRQ vector: pts to an RTS
+        stx     <D.AltIRQ
+
+        lda     #'K             debug: signal that we are in Kernel
+        jsr     <D.BtBug
+
+        leax    >S.Flip1,pc     Setup change to task 1 vector
+        stx     <D.Flip1
+
+* Setup System calls
+        leay    >SysCalls,pc    load y with address of table, below
+        lbsr    SysSvc          copy table below into dispatch table
+
+* Initialize system process descriptor
+        ldu     <D.PrcDBT       get process table pointer
+        ldx     <D.SysPrc       get system process pointer
+
+* These overlap because it is quicker than trying to strip hi byte from X
+        stx     ,u              save it as first process in table
+        stx     1,u             save it as the second as well
+      IFNE    H6309
+        oim     #$01,P$ID,x     Set process ID to 1 (inited to 0)
+        oim     #SysState,P$State,x     Set to system state (inited to 0)
+      ELSE
+        ldd     #$01*256+SysState
+        sta     P$ID,x          set PID to 1
+        stb     P$State,x       set state to system (*NOT* zero )
+      ENDC
+        clra                    set System task as task #0
+        sta     <D.SysTsk
+        sta     P$Task,x
+        coma                    Setup its priority & age ($FF)
+        sta     P$Prior,x
+        sta     P$Age,x
+        leax    <P$DATImg,x     point to DAT image
+        stx     <D.SysDAT       save it as a pointer in DP
+* actually, since block 0 is tfm'd to be zero, we can skip the next 2 lines
+      IFNE    H6309
+        clrd
+      ELSE
+        clra
+        clrb
+      ENDC
+        std     ,x++            initialize 1st block to 0 (for this DP)
+
+********************************************************************
+* The DAT image is a data structure that is used to indicate which
+* Dynamic Address Translator (DAT) mapping registers are in use.
+
+* [NAC HACK 2016Dec06] future: I should be able to make this 7 if not 8..
+* DAT.BlCt-ROMCount-RAMCount = 8 - 1 - 1 = 6
+        lda     #$06            initialize the rest of the blocks to be free
+        ldu     #DAT.Free
+L00EF   stu     ,x++            store free "flag"
+        deca                    bump counter
+        bne     L00EF           loop if not done
+
+* [NAC HACK 2016Dec06] on the Coco, block $3F holds the I/O space so it cannot
+* be used for anything else. Future: We can remove that restriction for mc09
+        ldu     #KrnBlk         Block $3F is in use, at the top of system DAT image
+        stu     ,x
+
+        ldx     <D.Tasks        Point to task user table
+        inc     ,x              mark first 2 in use (system & GrfDrv)
+        inc     1,x
+
+********************************************************************
+* The system memory map is a data structure that is used to manage
+* the 64Kbyte CPU address space. D.SysMem is a pointer to the start
+* of the map (set to $0900, above) and the map is a fixed size of
+* 256 bytes. Each byte in the map represents one 256-byte "page"
+* (256 entries of 256 bytes is 64Kbytes). A value of 0 indicates
+* an unused page and since the system block has been initialised
+* to 0 (above) every page starts off marked as unused.
+* See "Level 2 flags" in os9.d for other byte values.
+
+* Update the system memory map to reserve the area used for
+* global memory.
+        ldx     <D.SysMem       Get system memory map pointer
+        ldb     <D.CCStk        Get MSB of top of CC memory
+* X indexes the system memory map.
+* B represents the number of 256-byte pages available.
+* Walk through the map changing the corresponding elements
+* from 0 (the initialisation value) to 1 (indicating 'used'). Higher
+* entries in the map remain as 0 (indicating 'unused').
+L0104   inc     ,x+             Mark it as used
+        decb                    Done?
+        bne     L0104           No, go back till done
+
+********************************************************************
+* Deduce how many 8Kbyte blocks of physical memory are available and
+* update the memory block map end pointer (D.BlkMap+2) accordingly
+        ldx     <D.BlkMap       get ptr to 8k block map
+        inc     <KrnBlk,x       mark block $3F as used (kernel)
+      IFNE  mc09
+        inc     <$00,x          mark block $00 as used (global memory)
+* For mc09 memory size is 512Kbyte or 1MByte. For now, hard-wire
+* the memory size to 512Kbyte.
+        ldd     #$0240
+      ELSE
+* This memory sizing routine uses location at X (D.BlkMap) as
+* a scratch location. At exit, it leaves this location at 1 which
+* has the (until now) undocumented side-effect of marking block 0
+* as used. It is essential that this is done because that block
+* does need to be reserved; it's used for global memory.
+        IFNE    H6309
+        ldq     #$00080100      e=Marker, D=Block # to check
+L0111   asld                    get next block #
+        stb     >DAT.Regs+5     Map block into block 6 of my task
+        ste     >-$6000,x       save marker to that block
+        cmpe    ,x              did it ghost to block 0?
+        bne     L0111           No, keep going till ghost is found
+        stb     <D.MemSz        Save # 8k mem blocks that exist
+        addr    x,d             add number of blocks to block map start
+        ELSE
+        ldd     #$0008
+L0111   aslb
+        rola
+        stb     >DAT.Regs+5
+        pshs    a
+        lda     #$01
+        sta     >-$6000,x
+        cmpa    ,x
+        puls    a
+        bne     L0111
+        stb     <D.MemSz
+        pshs    x
+        addd    ,s++
+        ENDC
+      ENDC
+        std     <D.BlkMap+2     save memory block map end pointer
+
+********************************************************************
+* Initial reservation of blocks in the memory block map. Code above
+* reserved one block (block 0) for global memory and one block
+* (usually block $3F) for krn.
+*
+* At this point, the value of D indicates the memory size:
+* $0210 - 128k  ( 16, 8KByte blocks)
+* $0220 - 256k  ( 32, 8KByte blocks)
+* $0240 - 512k  ( 64, 8KByte blocks)
+* $0280 - 1024k (128, 8KByte blocks)
+* $0300 - 2048k (256, 8KByte blocks)
+        bitb    #%00110000      block above 128K-256K?
+        beq     L0170           yes, no need to mark block map
+        tstb                    2 meg?
+        beq     L0170           yes, skip this
+* Mark blocks from 128k-256K to block $3F as NOT RAM
+        abx                     add maximum block number to block map start
+        leax    -1,x            Skip good blocks that are RAM
+        lda     #NotRAM         Not RAM flag
+        subb    #$3F            Calculate # blocks to mark as not RAM
+L0127   sta     ,x+             Mark them all
+        decb
+        bne     L0127
+
+* ASSUME: however we got here, B=0
+L0170   ldx     #Bt.Start       start address of the boot track in memory
+        lda     #18             size of the boot track is $1800
+
+* Verify the modules in the boot track and update/build a module index
+        lbsr    I.VBlock
+        bsr     L01D2           go mark system map
+
+* See if init module is in memory already
+L01B0   leax    <init,pc        point to 'Init' module name
+        bsr     link            try & link it
+        bcc     L01BF           no error, go on
+L01B8   os9     F$Boot          error linking init, try & load boot file
+        bcc     L01B0           got it, try init again
+        bra     L01CE           error, re-booting do D.Crash
+
+* So far, so good. Save pointer to init module and execute krnp2
+L01BF   stu     <D.Init         Save init module pointer
+        lda     Feature1,u      Get feature byte #1 from init module
+        bita    #CRCOn          CRC feature on?
+        beq     ShowI           if not, continue
+        inc     <D.CRC          else inc. CRC flag
+
+ShowI   lda     #'i             debug: signal that we found the init module
+        jsr     <D.BtBug
+
+L01C1   leax    <krnp2,pc       Point to its name
+        bsr     link            Try to link it
+        bcc     L01D0           It worked, execute it
+        os9     F$Boot          It doesn't exist try re-booting
+        bcc     L01C1           No error's, let's try to link it again
+L01CE   jmp     <D.Crash        obviously can't do it, crash machine
+L01D0   jmp     ,y              execute krnp2
+
+* Update the system memory map to reserve the area used by the kernel
+L01D2   ldx     <D.SysMem       Get system memory map pointer
+        ldd     #NotRAM*256+(Bt.Start/256)      B = MSB of start of the boot
+        abx                     point to Bt.Start - start of boot track
+        comb                    we have $FF-$ED pages to mark as inUse
+        sta     b,x             Mark I/O as not RAM
+L01DF   lda     #RAMinUse       get inUse flag
+L01E1   sta     ,x+             mark this page
+        decb                    done?
+        bne     L01E1           no, keep going
+        ldx     <D.BlkMap       get pointer to start of block map
+        sta     <KrnBlk,x       mark kernel block as RAMinUse, instead of ModInBlk
+S.AltIRQ        rts             return
+
+* Link module pointed to by X
+link    lda     #Systm          Attempt to link system module
+        os9     F$Link
+        rts
+
+init    fcs     'Init'
+krnp2   fcs     'krnp2'
+
+* Service vector call pointers
+SysCalls        fcb     F$Link
+        fdb     FLink-*-2
+        fcb     F$PrsNam
+        fdb     FPrsNam-*-2
+        fcb     F$CmpNam
+        fdb     FCmpNam-*-2
+        fcb     F$CmpNam+SysState
+        fdb     FSCmpNam-*-2
+        fcb     F$CRC
+        fdb     FCRC-*-2
+        fcb     F$SRqMem+SysState
+        fdb     FSRqMem-*-2
+        fcb     F$SRtMem+SysState
+        fdb     FSRtMem-*-2
+        fcb     F$AProc+SysState
+        fdb     FAProc-*-2
+        fcb     F$NProc+SysState
+        fdb     FNProc-*-2
+        fcb     F$VModul+SysState
+        fdb     FVModul-*-2
+        fcb     F$SSvc+SysState
+        fdb     FSSvc-*-2
+        fcb     F$SLink+SysState
+        fdb     FSLink-*-2
+        fcb     F$Boot+SysState
+        fdb     FBoot-*-2
+        fcb     F$BtMem+SysState
+        fdb     FSRqMem-*-2
+        IFNE    H6309
+        fcb     F$CpyMem
+        fdb     FCpyMem-*-2
+        ENDC
+        fcb     F$Move+SysState
+        fdb     FMove-*-2
+        fcb     F$AllImg+SysState
+        fdb     FAllImg-*-2
+        fcb     F$SetImg+SysState
+        fdb     FFreeLB-*-2
+        fcb     F$FreeLB+SysState
+        fdb     FSFreeLB-*-2
+        fcb     F$FreeHB+SysState
+        fdb     FFreeHB-*-2
+        fcb     F$AllTsk+SysState
+        fdb     FAllTsk-*-2
+        fcb     F$DelTsk+SysState
+        fdb     FDelTsk-*-2
+        fcb     F$SetTsk+SysState
+        fdb     FSetTsk-*-2
+        fcb     F$ResTsk+SysState
+        fdb     FResTsk-*-2
+        fcb     F$RelTsk+SysState
+        fdb     FRelTsk-*-2
+        fcb     F$DATLog+SysState
+        fdb     FDATLog-*-2
+        fcb     F$LDAXY+SysState
+        fdb     FLDAXY-*-2
+        fcb     F$LDDDXY+SysState
+        fdb     FLDDDXY-*-2
+        fcb     F$LDABX+SysState
+        fdb     FLDABX-*-2
+        fcb     F$STABX+SysState
+        fdb     FSTABX-*-2
+        fcb     F$ELink+SysState
+        fdb     FELink-*-2
+        fcb     F$FModul+SysState
+        fdb     FFModul-*-2
+        fcb     F$VBlock+SysState
+        fdb     FVBlock-*-2
+        IFNE    H6309
+        fcb     F$DelRAM
+        fdb     FDelRAM-*-2
+        ENDC
+        fcb     $80
+
+* SWI3 vector entry
+XSWI3   lda     #P$SWI3         point to SWI3 vector
+        fcb     $8C             skip 2 bytes
+
+* SWI vector entry
+XSWI    lda     #P$SWI          point to SWI vector
+        ldx     <D.Proc         get process pointer
+        ldu     a,x             user defined SWI[x]?
+        beq     L028E           no, go get option byte
+GoUser  lbra    L0E5E           Yes, go call users's routine
+
+* SWI2 vector entry
+XSWI2   ldx     <D.Proc         get current process descriptor
+        ldu     P$SWI2,x        any SWI vector?
+        bne     GoUser          yes, go execute it
+
+* Process software interupts from a user state
+* Entry: X=Process descriptor pointer of process that made system call
+*        U=Register stack pointer
+L028E   ldu     <D.SysSvc       set system call processor to system side
+        stu     <D.XSWI2
+        ldu     <D.SysIRQ       do the same thing for IRQ's
+        stu     <D.XIRQ
+        IFNE    H6309
+        oim     #SysState,P$State,x     mark process as in system state
+        ELSE
+        lda     P$State,x
+        ora     #SysState
+        sta     P$State,x
+        ENDC
+* copy register stack to process descriptor
+        sts     P$SP,x          save stack pointer
+        leas    (P$Stack-R$Size),x      point S to register stack destination
+
+        IFNE    H6309
+        leau    R$Size-1,s      point to last byte of destination register stack
+        leay    -1,y            point to caller's register stack in $FEE1
+        ldw     #R$Size         size of the register stack
+        tfm     y-,u-
+        leau    ,s              needed because the TFM is u-, not -u (post, not pre)
+        ELSE
+* Note!  R$Size MUST BE an EVEN number of bytes for this to work!
+        leau    R$Size,s        point to last byte of destination register stack
+        lda     #R$Size/2
+Loop3   ldx     ,--y
+        stx     ,--u
+        deca
+        bne     Loop3
+        ENDC
+        andcc   #^IntMasks
+* B=function code already from calling process: DON'T USE IT!
+        ldx     R$PC,u          get where PC was from process
+        leax    1,x             move PC past option
+        stx     R$PC,u          save updated PC to process
+* execute function call
+        ldy     <D.UsrDis       get user dispatch table pointer
+        lbsr    L033B           go execute option
+        IFNE    H6309
+        aim     #^IntMasks,R$CC,u       Clear interrupt flags in caller's CC
+        ELSE
+        lda     R$CC,u
+        anda    #^IntMasks
+        sta     R$CC,u
+        ENDC
+        ldx     <D.Proc         get current process ptr
+        IFNE    H6309
+        aim     #^(SysState+TimOut),P$State,x   Clear system & timeout flags
+        ELSE
+        lda     P$State,x
+        anda    #^(SysState+TimOut)
+        sta     P$State,x
+        ENDC
+
+* Check for image change now, which lets stuff like F$MapBlk and F$ClrBlk
+* do the short-circuit thing, too.  Adds about 20 cycles to each system call.
+        lbsr    TstImg          it doesn't hurt to call this twice
+        lda     P$State,x       get current state of the process
+        ora     <P$Signal,x     is there a pending signal?
+        sta     <D.Quick        save quick return flag
+        beq     AllClr          if nothing's have changed, do full checks
+
+DoFull  bsr     L02DA           move the stack frame back to user state
+        lbra    L0D80           go back to the process
+
+* add ldu P$SP,x, etc...
+AllClr  equ     *
+        IFNE    H6309
+        inc     <D.QCnt
+        aim     #$1F,<D.QCnt
+        beq     DoFull          every 32 system calls, do the full check
+        ldw     #R$Size         --- size of the register stack
+        ldy     #Where+SWIStack --- to stack at top of memory
+        orcc    #IntMasks
+        tfm     u+,y+           --- move the stack to the top of memory
+        ELSE
+        lda     <D.QCnt
+        inca
+        anda    #$1F
+        sta     <D.QCnt
+        beq     DoFull
+        ldb     #R$Size
+        ldy     #Where+SWIStack
+        orcc    #IntMasks
+Loop4   lda     ,u+
+        sta     ,y+
+        decb
+        bne     Loop4
+        ENDC
+        lbra    BackTo1         otherwise simply return to the user
+
+* Copy register stack from user to system
+* Entry: U=Ptr to Register stack in process dsc
+L02CB   pshs    cc,x,y,u        preserve registers
+        ldb     P$Task,x        get task #
+        ldx     P$SP,x  get stack pointer
+        lbsr    L0BF3           calculate block offset (only affects A&X)
+        leax    -$6000,x        adjust pointer to where memory map will be
+        bra     L02E9           go copy it
+
+* Copy register stack from system to user
+* Entry: U=Ptr to Register stack in process dsc
+L02DA   pshs    cc,x,y,u        preserve registers
+        ldb     P$Task,x        get task # of destination
+        ldx     P$SP,x          get stack pointer
+        lbsr    L0BF3           calculate block offset (only affects A&X)
+        leax    -$6000,x        adjust pointer to where memory map will be
+        exg     x,y             swap pointers & copy
+* Copy a register stack
+* Entry: X=Source
+*        Y=Destination
+*        A=Offset into DAT image of stack
+*        B=Task #
+L02E9   leau    a,u             point to block # of where stack is
+      IFNE  mc09
+        orcc    #IntMasks       shutdown interupts while we do this
+
+        lda     #5
+        bsr     prepmmu         Select block 5
+
+        lda     1,u             get first block
+        ldb     3,u             get a second just in case of overlap
+
+        sta     >MMUDAT         Set value for block 5
+
+        lda     #6
+        bsr     prepmmu         Select block 6
+
+        stb     >MMUDAT         Set value for block 6
+
+        ldb     #R$Size
+Loop5   lda     ,x+
+        sta     ,y+
+        decb
+        bne     Loop5
+        ldx     <D.SysDAT       remap the blocks we took out
+
+        lda     #5
+        bsr     prepmmu         Select block 5
+
+        lda     $0B,x
+        ldb     $0D,x
+
+        sta     >MMUDAT         Restore value for block 5
+        lda     #6
+        bsr     prepmmu         Select block 6
+
+        stb     >MMUDAT         Restore value for block 6
+      ELSE
+        lda     1,u             get first block
+        ldb     3,u             get a second just in case of overlap
+        orcc    #IntMasks       shutdown interupts while we do this
+        std     >DAT.Regs+5     map blocks in
+      IFNE    H6309
+        ldw     #R$Size         get size of register stack
+        tfm     x+,y+           copy it
+      ELSE
+        ldb     #R$Size
+Loop5   lda     ,x+
+        sta     ,y+
+        decb
+        bne     Loop5
+      ENDC
+        ldx     <D.SysDAT       remap the blocks we took out
+        lda     $0B,x
+        ldb     $0D,x
+        std     >DAT.Regs+5
+      ENDIF
+        puls    cc,x,y,u,pc     restore & return
+
+      IFNE  mc09
+* A holds the MMU register we want to select. Merge in
+* the stored value and write the result to MMUADR. This is
+* a desperate attempt to save a few bytes..
+prepmmu
+        ora     <D.TINIT        Merge with current MMU mask
+        sta     >MMUADR         Select block
+        rts
+      ENDIF
+
+
+* Process software interupts from system state
+* Entry: U=Register stack pointer
+SysCall leau    ,s              get pointer to register stack
+        lda     <D.SSTskN       Get system task # (0=SYSTEM, 1=GRFDRV)
+        clr     <D.SSTskN       Force to System Process
+        pshs    a               Save the system task number
+        lda     ,u              Restore callers CC register (R$CC=$00)
+        tfr     a,cc            make it current
+        ldx     R$PC,u          Get my caller's PC register
+        leax    1,x             move PC to next position
+        stx     R$PC,u          Save my caller's updated PC register
+        ldy     <D.SysDis       get system dispatch table pointer
+        bsr     L033B           execute system call
+        puls    a               restore system state task number
+        lbra    L0E2B           return to process
+
+* Entry: X = system call vector to jump to
+Sys.Vec jmp     ,x              execute service call
+
+* Execute system call
+* Entry: B=Function call #
+*        Y=Function dispatch table pointer (D.SysDis or D.UsrDis)
+L033B
+        lslb                    is it a I/O call? (Also multiplys by 2 for offset)
+        bcc     L0345           no, go get normal vector
+* Execute I/O system calls
+        ldx     IOEntry,y       get IOMan vector
+* Execute the system call
+L034F   pshs    u               preserve register stack pointer
+        jsr     [D.SysVec]      perform a vectored system call
+        puls    u               restore pointer
+L0355   tfr     cc,a            move CC to A for stack update
+        bcc     L035B           go update it if no error from call
+        stb     R$B,u           save error code to caller's B
+L035B   ldb     R$CC,u          get callers CC, R$CC=$00
+        IFNE    H6309
+        andd    #$2FD0          [A]=H,N,Z,V,C [B]=E,F,I
+        orr     b,a             merge them together
+        ELSE
+        anda    #$2F            [A]=H,N,Z,V,C
+        andb    #$D0            [B]=E,F,I
+        pshs    b
+        ora     ,s+
+        ENDC
+        sta     R$CC,u          return it to caller, R$CC=$00
+        rts
+
+* Execute regular system calls
+L0345
+        clra                    clear MSB of offset
+        ldx     d,y             get vector to call
+        bne     L034F           it's initialized, go execute it
+        comb                    set carry for error
+        ldb     #E$UnkSvc       get error code
+        bra     L0355           return with it
+
+        use     fssvc.asm
+
+        use     flink.asm
+
+        use     fvmodul.asm
+
+        use     ffmodul.asm
+
+        use     fprsnam.asm
+
+        use     fcmpnam.asm
+
+        use     fsrqmem.asm
+
+*         use   fallram.asm
+
+
+        IFNE    H6309
+        use     fdelram.asm
+        ENDC
+
+        use     fallimg.asm
+
+        use     ffreehb.asm
+
+        use     fdatlog.asm
+
+        use     fld.asm
+
+        IFNE    H6309
+        use     fcpymem.asm
+        ENDC
+
+        use     fmove.asm
+
+        use     fldabx.asm
+
+        use     falltsk.asm
+
+        use     faproc.asm
+
+* System IRQ service routine
+XIRQ    ldx     <D.Proc         get current process pointer
+        sts     P$SP,x          save the stack pointer
+        lds     <D.SysStk       get system stack pointer
+        ldd     <D.SysSvc       set system service routine to current
+        std     <D.XSWI2
+        ldd     <D.SysIRQ       set system IRQ routine to current
+        std     <D.XIRQ
+        jsr     [>D.SvcIRQ]     execute irq service
+        bcc     L0D5B
+
+        ldx     <D.Proc         get current process pointer
+        ldb     P$Task,x
+        ldx     P$SP,x          get it's stack pointer
+
+        pshs    u,d,cc          save some registers
+        leau    ,s              point to a 'caller register stack'
+        lbsr    L0C40           do a LDB 0,X in task B
+        puls    u,d,cc          and now A ( R$A,U ) = the CC we want
+
+        ora     #IntMasks       disable it's IRQ's
+        lbsr    L0C28           save it back
+L0D5B   orcc    #IntMasks       shut down IRQ's
+        ldx     <D.Proc         get current process pointer
+        tst     <D.QIRQ         was it a clock IRQ?
+        lbne    L0DF7           if not, do a quick return
+
+        lda     P$State,x       Get it's state
+        bita    #TimOut         Is it timed out?
+        bne     L0D7C           yes, wake it up
+* Update active process queue
+        ldu     #(D.AProcQ-P$Queue)     point to active process queue
+        ldb     #Suspend        get suspend flag
+L0D6A   ldu     P$Queue,u       get a active process pointer
+        beq     L0D78
+        bitb    P$State,u       is it suspended?
+        bne     L0D6A           yes, go to next one in chain
+        ldb     P$Prior,x       get current process priority
+        cmpb    P$Prior,u       do we bump this one?
+        blo     L0D7C
+
+L0D78   ldu     P$SP,x
+        bra     L0DB9
+
+L0D7C   anda    #^TimOut
+        sta     P$State,x
+
+L0D80   equ     *
+L0D83   bsr     L0D11           activate next process
+
+        use     fnproc.asm
+
+* The following routines must appear no earlier than $E00 when assembled, as
+* they have to always be in the vector RAM pages ($FE00-$FEFF)
+
+      IFNE  mc09
+* Copied nicer automatic padding from ccbkrn
+* CCB: this code (after pad) start assembling *before* 0xfe00, it's too big to
+* fit into the memory as stated above!!!!
+
+PAD     fill    $00,($0dfc-*)   fill memory to ensure the above happens
+      ELSE
+PAD     fill    $00,($0df1-*)   fill memory to ensure the above happens
+      ENDC
+
+
+* Default routine for D.SysIRQ
+S.SysIRQ
+        lda     <D.SSTskN       Get current task's GIME task # (0 or 1)
+        beq     FastIRQ         Use super-fast version for system state
+        clr     <D.SSTskN       Clear out memory copy (task 0)
+        jsr     [>D.SvcIRQ]     (Normally routine in Clock calling D.Poll)
+        inc     <D.SSTskN       Save task # for system state
+      IFNE  mc09
+        lda     #$40            mc09 MMU Task 1
+        ora     <D.TINIT        Merge task bit into Shadow version
+        sta     <D.TINIT        Update shadow
+        sta     >MMUADR         Save to MMU as well
+      ELSE
+        lda     #1              Task 1
+        ora     <D.TINIT        Merge task bit into Shadow version
+        sta     <D.TINIT        Update shadow
+        sta     >DAT.Task       Save to GIME as well
+      ENDC
+        bra     DoneIRQ         Check for error and exit
+
+FastIRQ jsr     [>D.SvcIRQ]     (Normally routine in Clock calling D.Poll)
+DoneIRQ bcc     L0E28   No error on IRQ, exit
+        IFNE    H6309
+        oim     #IntMasks,0,s   Setup RTI to shut interrupts off again
+        ELSE
+        lda     ,s
+        ora     #IntMasks
+        sta     ,s
+        ENDC
+L0E28   rti
+
+* return from a system call
+L0E29   clra                    Force System task # to 0 (non-GRDRV)
+L0E2B   ldx     <D.SysPrc       Get system process dsc. ptr
+        lbsr    TstImg          check image, and F$SetTsk (PRESERVES A)
+        orcc    #IntMasks       Shut interrupts off
+        sta     <D.SSTskN       Save task # for system state
+        beq     Fst2            If task 0, we're done
+      IFNE  mc09
+        lda     #$40            [NAC HACK 2016Dec07] hope only 1 bit means anything..
+        ora     <D.TINIT        Merge task bit into Shadow version
+        sta     <D.TINIT        Update shadow
+        sta     >MMUADR         Save to MMU
+      ELSE
+        ora     <D.TINIT        Merge task bit into Shadow version
+        sta     <D.TINIT        Update shadow
+        sta     >DAT.Task       Save to GIME as well
+      ENDC
+Fst2    leas    ,u              Stack ptr=U & return
+        rti
+
+* Switch to new process, X=Process descriptor pointer, U=Stack pointer
+L0E4C   equ     *
+        IFNE    H6309
+        oim     #$01,<D.TINIT   switch GIME shadow to user state
+        lda     <D.TINIT
+        ELSE
+        lda     <D.TINIT
+      IFNE  mc09
+        ora     #$40
+      ELSE
+        ora     #$01
+      ENDC
+        sta     <D.TINIT
+        ENDC
+      IFNE  mc09
+        sta     >MMUADR         save it to MMU
+      ELSE
+        sta     >DAT.Task       save it to GIME
+      ENDC
+        leas    ,y              point to new stack
+        tstb                    is the stack at SWISTACK?
+        bne     MyRTI           no, we're doing a system-state rti
+
+        IFNE    H6309
+        ldf     #R$Size         E=0 from call to L0E8D before
+        ldu     #Where+SWIStack point to the stack
+        tfm     u+,y+           move the stack from top of memory to user memory
+        ELSE
+        ldb     #R$Size
+        ldu     #Where+SWIStack point to the stack
+RtiLoop lda     ,u+
+        sta     ,y+
+        decb
+        bne     RtiLoop
+        ENDC
+MyRTI   rti                     return from IRQ
+
+
+* Execute routine in task 1 pointed to by U
+* comes from user requested SWI vectors
+L0E5E   equ     *
+        IFNE    H6309
+        oim     #$01,<D.TINIT   switch GIME shadow to user state
+        ldb     <D.TINIT
+        ELSE
+        ldb     <D.TINIT
+      IFNE  mc09
+        orb     #$40
+      ELSE
+        orb     #$01
+      ENDC
+        stb     <D.TINIT
+        ENDC
+      IFNE  mc09
+        stb     >MMUADR
+      ELSE
+        stb     >DAT.Task
+      ENDC
+        jmp     ,u
+
+* Flip to task 1 (used by GRF/WINDInt to switch to GRFDRV) (pointed to
+*  by <D.Flip1). All regs are already preserved on stack for the RTI
+S.Flip1 ldb     #2              get Task image entry numberx2 for Grfdrv (task 1)
+        bsr     L0E8D           copy over the DAT image
+        IFNE    H6309
+        oim     #$01,<D.TINIT
+        lda     <D.TINIT        get copy of GIME Task side
+        ELSE
+        lda     <D.TINIT
+      IFNE  mc09
+        ora     #$40            force TR=1 in mc09 MMU
+      ELSE
+        ora     #$01            force TR=1
+      ENDC
+        sta     <D.TINIT
+        ENDC
+      IFNE  mc09
+        sta     >MMUADR         save it to MMU register
+      ELSE
+        sta     >DAT.Task       save it to GIME register
+      ENDC
+        inc     <D.SSTskN       increment system state task number
+        rti                     return
+
+* Setup MMU in task 1, B=Task # to swap to, shifted left 1 bit
+L0E8D   cmpb    <D.Task1N       are we going back to the same task
+        beq     L0EA3           without the DAT image changing?
+        stb     <D.Task1N       nope, save current task in map type 1
+      IFNE  mc09
+        ldu     <D.TskIPt       get task image pointer table
+        ldu     b,u             get address of DAT image
+
+        lda     <D.TINIT
+        adda    #8              1st MMU value for process's mappings
+
+* COME HERE FROM FALLTSK
+* Update 8 MMU mappings.
+* A = MMUADR value for 1st MMU register to update
+* U = address of DAT image to update into MMU
+L0E93   ldb     #8              number of MMU mappings to set
+        pshs    b               squirrel it away
+        leau    1,u             point to actual MMU block for 1st mapping
+
+L0E9B   ldb     ,u++            get a bank, point to next bank
+        std     >MMUADR         save it to MMU
+        inca                    next mapsel value
+        dec     ,s
+        bne     L0E9B           no, keep going
+        leas    1,s             done. Tidy up the stack
+      ELSE
+        ldx     #DAT.Regs+8     get MMU start register for process's
+        ldu     <D.TskIPt       get task image pointer table
+        ldu     b,u             get address of DAT image
+* COME HERE FROM FALLTSK
+* Update 8 MMU mappings.
+* X = address of 1st DAT MMU register to update
+* U = address of DAT image to update into MMU
+L0E93   leau    1,u             point to actual MMU block
+        IFNE    H6309
+        lde     #4              get # banks/2 for task
+        ELSE
+        lda     #4
+        pshs    a
+        ENDC
+L0E9B   lda     ,u++            get a bank
+        ldb     ,u++            and next one
+        std     ,x++            Save it to MMU
+        IFNE    H6309
+        dece                    done?
+        ELSE
+        dec     ,s
+        ENDC
+        bne     L0E9B           no, keep going
+        IFEQ    H6309
+        leas    1,s             done. Tidy up the stack
+        ENDC
+      ENDC
+L0EA3   rts                     return
+
+* Execute FIRQ vector (called from $FEF4)
+FIRQVCT ldx     #D.FIRQ         get DP offset of vector
+        bra     L0EB8           go execute it
+
+* Execute IRQ vector (called from $FEF7)
+IRQVCT  orcc    #IntMasks       disable IRQ's
+        ldx     #D.IRQ  get DP offset of vector
+
+* Execute interrupt vector, B=DP Vector offset
+      IFNE mc09
+L0EB8   lda     #$a0            [NAC HACK 2016Dec08] add equates..
+        sta     >MMUADR         Force to System State (Task 0)
+        clra
+        tfr     a,dp            ASSUME: A=0 from earlier
+MapGrf  equ     *               come here from elsewhere, too.
+        lda     <D.TINIT
+        anda    #$BF            force TR=0 in mc09 MMU shadow
+        sta     <D.TINIT
+MapT0   sta     >MMUADR         come here from elsewhere, too.
+        jmp     [,x]            execute it
+      ELSE
+* Execute interrupt vector, B=DP Vector offset
+L0EB8   clra                    (faster than CLR >$xxxx)
+        sta     >DAT.Task       Force to Task 0 (system state)
+        IFNE    H6309
+        tfr     0,dp            setup DP
+        ELSE
+        tfr     a,dp            ASSUME: A=0 from earlier
+        ENDC
+MapGrf  equ     *               come here from elsewhere, too.
+        IFNE    H6309
+        aim     #$FE,<D.TINIT   switch GIME shadow to system state
+        lda     <D.TINIT        set GIME again just in case timer is used
+        ELSE
+        lda     <D.TINIT
+        anda    #$FE
+        sta     <D.TINIT
+        ENDC
+MapT0   sta     >DAT.Task       come here from elsewhere, too.
+        jmp     [,x]            execute it
+      ENDC
+
+
+
+* Execute SWI3 vector (called from $FEEE)
+SWI3VCT orcc    #IntMasks       disable IRQ's
+        ldx     #D.SWI3         get DP offset of vector
+        bra     SWICall         go execute it
+
+* Execute SWI2 vector (called from $FEF1)
+SWI2VCT orcc    #IntMasks       disasble IRQ's
+        ldx     #D.SWI2         get DP offset of vector
+
+* This routine is called from an SWI, SWI2, or SWI3
+* saves 1 cycle on system-system calls
+* saves about 200 cycles (calls to I.LDABX and L029E) on grfdrv-system,
+*  or user-system calls.
+SWICall ldb     [R$PC,s]        get callcode of the system call
+      IFNE  mc09
+* [NAC HACK 2016Dec08] confused? it says, "go to map type 1" but
+* it is setting a 0.
+        lda     #$a0            [NAC HACK 2016Dec08] add equates..
+        sta     >MMUADR         Force to System State (Task 0)
+        clra
+      ELSE
+* NOTE: Alan DeKok claims that this is BAD.  It crashed Colin McKay's
+* CoCo 3.  Instead, we should do a clra/sta >DAT.Task.
+*         clr   >DAT.Task       go to map type 1
+        clra
+        sta     >DAT.Task
+      ENDC
+* set DP to zero
+        IFNE    H6309
+        tfr     0,dp
+        ELSE
+        tfr     a,dp            ASSUME: A=0 from earlier
+        ENDC
+
+* These lines add a total of 81 addition cycles to each SWI(2,3) call,
+* and 36 bytes+12 for R$Size in the constant page at $FExx
+*  It takes no more time for a SWI(2,3) from system state than previously,
+* ... and adds 14 cycles to each SWI(2,3) call from grfdrv... not a problem.
+* For processes that re-vector SWI, SWI3, it adds 81 cycles.  BUT SWI(3)
+* CANNOT be vectored to L0EBF cause the user SWI service routine has been
+* changed
+        lda     <D.TINIT        get map type flag
+      IFNE  mc09
+        bita    #$40            check it without changing it in mc09 MMU
+      ELSE
+        bita    #$01            check it without changing it
+      ENDC
+
+* Change to LBEQ R.SysSvc to avoid JMP [,X]
+* and add R.SysSvc STA >DAT.Task ???
+        beq     MapT0           in map 0: restore hardware and do system service
+        tst     <D.SSTskN       get system state 0,1
+        bne     MapGrf          if in grfdrv, go to map 0 and do system service
+
+* the preceding few lines are necessary, as all SWI's still pass thru
+* here before being vectored to the system service routine... which
+* doesn't copy the stack from user state.
+      IFNE  mc09
+        sta     >MMUADR         go to map type X again to get user's stack
+      ELSE
+        sta     >DAT.Task       go to map type X again to get user's stack
+      ENDC
+* a byte less, a cycle more than ldy #$FEED-R$Size, or ldy #$F000+SWIStack
+        leay    <SWIStack,pc    where to put the register stack: to $FEDF
+        tfr     s,u             get a copy of where the stack is
+        IFNE    H6309
+        ldw     #R$Size         get the size of the stack
+        tfm     u+,y+           move the stack to the top of memory
+        ELSE
+        pshs    b
+        ldb     #R$Size
+Looper  lda     ,u+
+        sta     ,y+
+        decb
+        bne     Looper
+        puls    b
+        ENDC
+        bra     L0EB8           and go from map type 1 to map type 0
+
+* Execute SWI vector (called from $FEFA)
+SWIVCT  ldx     #D.SWI          get DP offset of vector
+        bra     SWICall         go execute it
+
+* Execute NMI vector (called from $FEFD)
+NMIVCT  ldx     #D.NMI          get DP offset of vector
+        bra     L0EB8           go execute it
+
+* The end of the kernel module is here
+        emod
+eom     equ     *
+
+* What follows after the kernel module is the register stack, starting
+* at $FEDD (6309) or $FEDF (6809).  This register stack area is used by
+* the kernel to save the caller's registers in the $FEXX area of memory
+* because it doesn't get "switched out" no matter the contents of the
+* MMU registers.
+SWIStack
+        fcc     /REGISTER STACK/ same # bytes as R$Size for 6809
+        IFNE    H6309
+        fcc     /63/             if 6309, add two more bytes of space
+        ENDC
+
+        fcb     $55              D.ErrRst
+
+      IFNE  mc09
+* For Multicomp09, the processor vectors are in RAM so they can be loaded
+* with the service addresses directly, instead of requiring another indirection
+* The vectors are set up by a data table copy of CPUVect
+      ELSE
+* This list of addresses ends up at $FEEE after the kernel track is loaded
+* into memory.  All interrupts come through the 6809 vectors at $FFF0-$FFFE
+* and get directed to here.  From here, the BRA takes CPU control to the
+* various handlers in the kernel.
+        bra     SWI3VCT SWI3 vector comes here
+        nop
+        bra     SWI2VCT SWI2 vector comes here
+        nop
+        bra     FIRQVCT FIRQ vector comes here
+        nop
+        bra     IRQVCT  IRQ vector comes here
+        nop
+        bra     SWIVCT  SWI vector comes here
+        nop
+        bra     NMIVCT  NMI vector comes here
+        nop
+      ENDC
+
+* The final byte (eg the NOP after bra NMIVCT) should be at offset $EFF
+* and will end up at address $FEFF in physical memory. If any code above
+* is changed, you must inspect the listing and adjust the addresses at
+* the label PAD.
+        end