OSDN Git Service

part way through conversion to subroutine call threading
authorJoel Matthew Rees <joel.rees@gmail.com>
Sun, 4 Jun 2023 10:14:58 +0000 (19:14 +0900)
committerJoel Matthew Rees <joel.rees@gmail.com>
Sun, 4 Jun 2023 10:14:58 +0000 (19:14 +0900)
FIG68K.S
FIG68KRT.S
FIG68KSB.S [new file with mode: 0644]

index 1b9bec1..d3cab65 100644 (file)
--- a/FIG68K.S
+++ b/FIG68K.S
@@ -1380,7 +1380,7 @@ ALGNB     DC.L    *+NATWID
 *\r
 * ######>> screen 26 <<\r
 * ======>>  23  <<\r
-* ( --- adr )\r
+* ( anything --- anything adr )\r
 * Fetch the parameter stack pointer (before it is pushed).\r
 * This points at whatever was on the top of stack before.\r
        EVEN\r
@@ -1399,7 +1399,7 @@ SPAT      DC.L    *+NATWID
        EVEN\r
        DC.B    $83\r
        DC.B    'SP'    ; 'SP!'\r
-       DC.B    $A1\r
+       DC.B    '!'|$80\r
        DC.L    SPAT-4-NATWID\r
 SPSTOR DC.L    *+NATWID\r
        MOVE.L  XSPZER-UORIG(UP),PSP\r
index e7d6d18..f8b9f96 100644 (file)
@@ -1399,7 +1399,7 @@ ALGNB     DC.L    *+NATWID
 *\r
 * ######>> screen 26 <<\r
 * ======>>  23  <<\r
-* ( --- adr )\r
+* ( anything --- anything adr )\r
 * Fetch the parameter stack pointer (before it is pushed).\r
 * This points at whatever was on the top of stack before.\r
        EVEN\r
@@ -1418,7 +1418,7 @@ SPAT      DC.L    *+NATWID
        EVEN\r
        DC.B    $83\r
        DC.B    'SP'    ; 'SP!'\r
-       DC.B    $A1\r
+       DC.B    '!'|$80\r
        DC.L    SPAT-4-NATWID\r
 SPSTOR DC.L    *+NATWID\r
        MOVE.L  XSPZER-UORIG(UP),PSP\r
diff --git a/FIG68KSB.S b/FIG68KSB.S
new file mode 100644 (file)
index 0000000..a556223
--- /dev/null
@@ -0,0 +1,6103 @@
+       OPT LIST,SYMTAB\r
+       MACHINE MC68000\r
+       OPT DEBUG\r
+       OUTPUT\r
+* fig-FORTH FOR 68000\r
+* ASSEMBLY SOURCE LISTING\r
+\r
+* RELEASE 0\r
+* JAN-FEB 2023\r
+* WITH COMPILER SECURITY\r
+* AND VARIABLE LENGTH NAMES\r
+* Try again with literal subroutine substitution mode, one step at a time.\r
+*\r
+* Adapted by Joel Matthew Rees \r
+* from fig-FORTH for 6800 (via buggy fig-FORTH for 6809) by Dave Lion, et. al.\r
+\r
+* This free/libre/open source publication is provided\r
+* through the courtesy of:\r
+* FORTH\r
+* INTEREST\r
+* GROUP\r
+* fig\r
+* and other interested parties.\r
+\r
+* Ancient address:\r
+* P.O. Box 8231 - San Jose, CA 95155 - (408) 277-0668\r
+* URL: http://www.forth.org\r
+* Further distribution must include this notice.\r
+       PAGE\r
+       TTL     Copyright: FORTH Interest Group, original authors, and Joel Matthew Rees\r
+*      OPT     NOG,PAG\r
+* filename fig-forth-hand68000.asm\r
+* === FORTH-68000 {date} {time}\r
+\r
+\r
+* Permission is hereby granted, free of charge, to any person obtaining a copy\r
+* of this software and associated documentation files (the "Software"), to deal\r
+* in the Software without restriction, including without limitation the rights\r
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
+* copies of the Software, and to permit persons to whom the Software is\r
+* furnished to do so, subject to the following conditions:\r
+*\r
+* The above copyright notice and this permission notice shall be included in\r
+* all copies or substantial portions of the Software.\r
+\r
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r
+* THE SOFTWARE.\r
+*\r
+* "Associated documentation" for this declaration of license\r
+* shall be interpreted to include only the comments in this file,\r
+* or, if the code is split into multiple files,\r
+* all files containing the complete source.\r
+* \r
+* This is the MIT model license, as published by the Open Source Consortium,\r
+* with associated documentation defined.\r
+* It was chosen to reflect the spirit of the original \r
+* terms of use, which used archaic legal terminology.\r
+*\r
+* Authors of the 6800 model:\r
+* === Primary: Dave Lion,\r
+* ===  with help from\r
+* === Bob Smith,\r
+* === LaFarr Stuart,\r
+* === The Forth Interest Group\r
+* === PO Box 1105\r
+* === San Carlos, CA 94070\r
+* ===  and\r
+* === Unbounded Computing\r
+* === 1134-K Aster Ave.\r
+* === Sunnyvale, CA 94086\r
+*\r
+       PAGE\r
+\r
+*********\r
+* NOTICE! the fig Forth model has problems, \r
+* including known bugs and unknown, \r
+* and including vulnerabilities.\r
+*\r
+* While it might be used to bootstrap more correct and secure systems,\r
+* it should be primarily used for study, practice, and research.\r
+*********\r
+\r
+* Some processor-specific stuff:\r
+NATWID EQU     4       ; bytes per natural integer/pointer\r
+* The assembler ought to have defined these, but I don't see them in the manual:\r
+* User program condition codes:\r
+F_CARY EQU     $0001\r
+F_OVER EQU     $0002\r
+F_ZERO EQU     $0004\r
+F_NEG  EQU     $0008\r
+F_EXT  EQU     $0010\r
+* System status flags (68000/68010/CPU32):\r
+F_SYS  EQU     $2000\r
+F_TRAC EQU     $8000\r
+* Ignoring the interrupt flags for now\r
+*\r
+*  The original version was developed on an AMI EVK 300 PROTO\r
+*  system using an ACIA for the I/O.\r
+*  This version is developed targeting the Atar ST.\r
+\r
+*  All terminal 1/0\r
+*  is done in three subroutines:\r
+*   PEMIT  ( word # 182 )\r
+*   PKEY   (        183 )\r
+*   PQTERM (        184 )\r
+*\r
+*  The FORTH words for disc related I/O follow the model\r
+*  of the FORTH Interest Group, but have not yet been\r
+*  tested using a real disc.\r
+*\r
+*  Addresses in the 6800 implementation reflect the fact that,\r
+*  on the development system, it was convenient to\r
+*  write-protect memory at hex 1000, and leave the first\r
+*  4K bytes write-enabled. As a consequence, code from\r
+*  location $1000 to label ZZZZ could be put in ROM.\r
+*  Minor deviations from the model were made in the\r
+*  initialization and words ?STACK and FORGET\r
+*  in order to do this.\r
+*\r
+*  Those definitions will be altered somewhat in this \r
+*  implementation for the 68000 -- Atari ST.\r
+*  \r
+       PAGE\r
+*  MEMORY MAP for this approximately 128K system:\r
+*  ( arranged for systems with high-memory ROM/write-protect )\r
+*\r
+* Won't be using the ACIA directly, no need to define addresses.\r
+* ACIAC        EQU     $XXXXXXXX       the ACIA control address and\r
+* ACIAD        EQU     ACIAC+1 data address for PROTO\r
+*\r
+* Moving the definitions of the memory area since the usual 68000 assemblers are \r
+* so kind as to make sure that definitions dependent on negative offsets and such\r
+* are not supported as ORG arguments, etc.\r
+*\r
+* These will be defined elsewhere:\r
+*\r
+* NBLK EQU     4       # of disc buffer blocks for virtual memory\r
+* MEMEND       EQU     132*NBLK+ENDofCODE end of ram\r
+*  each block is 132 bytes in size,\r
+*  holding 128 characters\r
+*\r
+* MEMTOP       EQU     $WAYupHIGH      absolute end of all ram\r
+*  MEMORY MAP for this 16K system:\r
+*  ( positioned so that systems with 4k byte write-\r
+*   protected segments can write protect FORTH )\r
+*\r
+* addr.                contents                pointer init by\r
+* **** ******************************* ******* ******\r
+* MEMTOP                                       HI\r
+*      substitute for disc mass memory\r
+* MEMEND                                       LO\r
+* MEMEND-1\r
+*      4 buffer sectors of VIRTUAL MEMORY\r
+* ENDofCODE+1                                  FIRST\r
+* >>>>>> memory from here up must be RAM <<<<<<\r
+*\r
+* ENDofCODE\r
+* >>>>>>--------Two words to start RAMmable dictionary--------<<<<<<\r
+*\r
+*      ~12k of romable "FORTH"         <== IP  ABORT\r
+*                                      <== W\r
+*      the VIRTUAL FORTH MACHINE\r
+*\r
+* ENTRY+4 <<< WARM START ENTRY >>>\r
+* ENTRY <<< COLD START ENTRY >>>\r
+*\r
+* >>>>>> memory from here down must be RAM <<<<<<\r
+*  IRP RETURN STACK base               <== RP  RINIT\r
+*\r
+*  SFTBND\r
+*      INPUT LINE BUFFER\r
+*      holds up to 132 characters\r
+*      and is scanned upward by IN\r
+*      starting at TIB\r
+*  ITIB                                        <== IN  TIB\r
+*  IPSP        DATA STACK                      <== SP  SP0,SINIT\r
+*    | grows downward from here\r
+*    v\r
+*  - -\r
+*    ^\r
+*    | DICTIONARY grows upward\r
+* \r
+* These two entries will be copied from the end of the "ROMmable" dictionary\r
+* into the bottom of the "RAMmable" dictionary area to link the two parts together.\r
+* \r
+*      end of ram-dictionary.          <== DP  DPINIT\r
+*      "TASK"\r
+*\r
+*      "FORTH" ( a word )              <=, <== CONTEXT\r
+*                                      `==== CURRENT\r
+*      start of RAM dictionary area.\r
+*\r
+*  RTDICT+(something)  "FORTH" ( definition )          <=, <== CONTEXT\r
+*                                      `==== CURRENT\r
+*  RTDICT      start of ram-dictionary.\r
+*\r
+*  USERSP      user #1 table of variables      <= UP   DPINIT\r
+*   ---        No need for registers & pointers for the virtual machine\r
+*      No need for scratch area used by various words\r
+*   ---        lowest address used by FORTH\r
+* Linker/loader structures produced by assembler and linker\r
+* CODEBEG\r
+* >>>>>> memory from here down left alone <<<<<<\r
+* >>>>>> so we can safely call ROM routines <<<<<<\r
+*\r
+* UNK    don't care stuff, if anything\r
+*\r
+* $400\r
+* EXCVCT 68000 exception vectors\r
+* 0000==RSTVCT\r
+\r
+       PAGE\r
+\r
+*      ORG $30000      ; Not on the Atari ST under EMUTOS.\r
+\r
+* Edit this according to the desired size for the dictionary.\r
+RTDCSZ EQU     8*1024  ; Must be even on 68000. For now, keep total size under 32K.\r
+\r
+* This should be adjusted to the target:\r
+* CODEBG       EQU $800\r
+CODEBG EQU     *       ; On the Atari ST, the assembler should determine this.\r
+*\r
+*      per-task (per-user) tables\r
+USERAL EQU     64*NATWID       ; allocatable\r
+USERCT EQU     4               ; maybe, someday?\r
+*\r
+* USERSP       EQU     *       ; (task-local variable space, addressable by UP)        ; NOPE!\r
+USERSP EQU     USERAL*USERCT   ; (task-local variable space, addressable by UP)\r
+* IUP  EQU     USERSP  ; USERSZ*USERCT ; Nope!\r
+* The per-user (or task-local) table definitions are moved to the end \r
+* to avoid using BSS segments, because I don't know how well they are \r
+* supported in various 68K assemblers.\r
+\r
+*      This system is built for one "user", or task, \r
+*       but additional users (tasks) may be added\r
+*      by allocating additional user tables.\r
+*\r
+*      Some of this stuff gets initialized during\r
+*      COLD start and WARM start:\r
+*      [ names correspond to FORTH words of similar (no X) name ]\r
+*\r
+*              A few useful VM variables --\r
+* Will be removed when they are no longer needed.\r
+* All are replaced by 68000 registers.\r
+\r
+* The Atari apparently wants the beginning of the image to be a jump to the entry point.\r
+* Put a jump around stuff here, anyway.\r
+START:\r
+*      MOVE.L  #ORIG-SURPRISE,D7\r
+* SURPRISE:\r
+*      JMP     (PC,D7) ; monku monku mutter mutter mumble mumble butsu butsu\r
+       JMP     ORIG    ; In case the distance is greater than 32K.\r
+* And this is why people don't understand true position independent coding.\r
+RSRV   DS.L    8\r
+N      DS.L    8       ; might be used as scratch if we really needed it.\r
+\r
+*      These locations could be used by a TRACE routine :\r
+TRLIM  DS.W    1       ; the count for tracing without user intervention\r
+TRACEM DS.W    1       ; non-zero = trace mode\r
+BRKPT  DS.L    1       ; the breakpoint address at which\r
+*                        the program will go into trace mode\r
+VECT   DS.L    1       ; vector to machine code\r
+*      (only needed if the TRACE routine is resident)\r
+\r
+*      Registers used by the FORTH virtual machine:\r
+*      Starting at $OOFO in the 6800, unneeded here:\r
+*\r
+* All of these are defined below, with explanation.\r
+* W    RMB     NATWID  ; the instruction register remembers IP.\r
+* IP   RMB     NATWID  ; the instruction pointer points to pointer to 6800 code\r
+* RP   RMB     NATWID  ; the return stack pointer\r
+* PSP  RMB     NATWID  ; the parameter stack pointer (Forth SP)\r
+* UP   RMB     NATWID  ; the pointer to base of current user's 'USER' table\r
+*              ( altered by a task switch )\r
+*\r
+GAP    EQU     *\r
+       DS.B    USERAL-(GAP-START)\r
+*\r
+UORIG  DS.L    3       ; 3 reserved variables\r
+XSPZER DS.L    1       ; initial top of data stack for this user\r
+XRZERO DS.L    1       ; initial top of return stack\r
+XTIB   DS.L    1       ; start of terminal input buffer\r
+XWIDTH DS.L    1       ; name field width ****** could be byte\r
+XWARN  DS.L    1       ; warning message mode (0 = no disc) ****** could be byte\r
+XFENCE DS.L    1       ; fence for FORGET\r
+XDICTP DS.L    1       ; dictionary pointer\r
+XVOCL  DS.L    1       ; vocabulary linking\r
+XBLK   DS.L    1       ; disc block being accessed\r
+XIN    DS.L    1       ; scan pointer into the block ****** could be 16-bit\r
+XOUT   DS.L    1       ; cursor position ****** could be 16-bit\r
+XSCR   DS.L    1       ; disc screen being accessed ( O=terminal )\r
+XOFSET DS.L    1       ; disc sector offset for multi-disc\r
+XCONT  DS.L    1       ; last word in primary search vocabulary\r
+XCURR  DS.L    1       ; last word in extensible vocabulary\r
+XSTATE DS.L    1       ; flag for 'interpret' or 'compile' modes ****** could be byte?\r
+XBASE  DS.L    1       ; number base for I/O numeric conversion ****** could be byte\r
+XDPL   DS.L    1       ; decimal point place ****** could be 16-bit\r
+XFLD   DS.L    1       ; conversion field ****** could be 16-bit\r
+XCSP   DS.L    1       ; current stack position, for compile checks\r
+XRNUM  DS.L    1       ; ****** could be 16-bit? \r
+XHLD   DS.L    1       ; ****** could be 16-bit?\r
+XDELAY DS.L    1       ; carriage return delay count ****** could be byte\r
+XCOLUM DS.L    1       ; carriage width ****** could be 16-bit\r
+IOSTAT DS.L    1       ; last acia status from write/read ****** could be byte or 16-bit\r
+*\r
+*   end of user table, start of (theoretical) common system variables\r
+*\r
+* These need to be moved to where they will be \r
+* initialized globals in variable space, not in the USER table.\r
+* Or, more accurately, need to be turned into monitored or semaphored resources.\r
+XUSE   DS.L    1\r
+XPREV  DS.L    1\r
+       DS.L    2       ( spares )\r
+*\r
+XUCURR DS.L    1       ; user table current allocation\r
+*\r
+XDEF   EQU     *\r
+       DS.B    USERAL-(XDEF-UORIG)     ; allocatable\r
+*\r
+*USERSZ        EQU     *-UORIG\r
+       DS.B    USERAL*(USERCT-1)\r
+*\r
+       PAGE\r
+***** Need to come back to these later.\r
+VOCFLG EQU     $832020A0       ; flag (dummy) entry to switch vocabularies by.\r
+*  These things, up through the label 'REND', are overwritten\r
+*  at time of cold load and should have the same contents\r
+*  as shown here:\r
+*\r
+       EVEN\r
+RBEG   EQU     *\r
+       DC.B    $C5     immediate\r
+       DC.B    'FORT'  ; 'FORTH'\r
+       DC.B    'H'|$80\r
+       DC.L    NOOP-5-NATWID\r
+FORTH: DC.L    DODOES,DOVOC,VOCFLG,TASK-5-NATWID\r
+       DC.L    0\r
+*\r
+       DC.B    "Copyright 1979 Forth Interest Group, David Lion,"\r
+       DC.B    $0D\r
+       DC.B    "Parts Copyright 2019 Joel Matthew Rees"\r
+       DC.B    $0D\r
+*\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $84\r
+       DC.B    'TAS'   ; 'TASK'\r
+       DC.B    'K'|$80\r
+       DC.L    FORTH-6-NATWID\r
+TASK:  DC.L    DOCOL,SEMIS\r
+* \r
+REND   EQU     *       ( first empty location in dictionary )\r
+RSIZE  EQU     *-RBEG  ; So we can look at it.\r
+       PAGE\r
+***\r
+*\r
+* CONVENTIONS USED IN THIS PROGRAM ARE AS FOLLOWS :\r
+*\r
+* IP points to the next FORTH VM instruction ( pre-increment mode )\r
+IP     EQUR    A5      ; post-inc mode, as opposed to 6800 model.\r
+* RP points to last return address pushed on return stack\r
+RP     EQUR    A7      ; Yes, we are going to break with fig false traditions.\r
+* PSP points to last item pushed on data (parameter) stack\r
+PSP    EQUR    A6      ; SP is already defined as A7 on 68K.\r
+* may conflict with using A6 as frame pointer? Not really.\r
+* Note that 6800 S points one below last byte pushed. We don't have to do that.\r
+*\r
+* A5 must be IP when NEXT is entered (when using the inner loop).\r
+*\r
+*      D0 handles all of what is A:B on 6801/6809.\r
+*\r
+* UP (could be DP on 6809) is the base of per-task ("user") variables.\r
+UP     EQUR    A3\r
+* (Be careful of the stray semantics of "user".)\r
+*\r
+* W (hardware X) is the pointer to the "code field" address of native CPU\r
+* But W is now ephemeral, maybe in VEC, but always top of return stack at entry.\r
+W      EQUR    A4 \r
+* Points to pointer to machine code to be executed for the definition \r
+* of the dictionary word to be executed/currently executing.\r
+* The following natural integer (word) begins any "parameter section" \r
+* (body) -- similar to a "this" pointer, but not the same.\r
+* It may be native CPU machine code, or it may be a global variable, \r
+* or it may be a list of Forth definition words (addresses).\r
+*\r
+* Since we have it, give it a handle. The execute vector:\r
+* (Only valid until used elsewhere.)\r
+VEC    EQUR    A2\r
+*\r
+* A0 and A1 used as scratch indexes.\r
+* D0 through D7 used as scratch registers.\r
+* Some related routines (for example, LOOP) use D0 as a shared parameter.\r
+*\r
+* Except that I want to keep this close to the fig model:\r
+** We've got the registers, might as well use 'em.\r
+** Defined for the I-level loop variables:\r
+* LUPLIM       EQUR    D5      ; limit was pushed first, \r
+* LUPCT        EQUR    D4      ; then index/count\r
+** J-level is on the return stack.\r
+*\r
+* ======\r
+* This implementation uses the indirect subroutine architecture \r
+* -- a postponed-push call that the 6800 model VM also uses\r
+* to save code and time in leaf routines. \r
+*\r
+* It won't allow mixing assembly language directly into Forth word lists.\r
+* ======\r
+*\r
+* boolean flags:\r
+* 0 is false, anything else is true.\r
+* Most places in this model that set a boolean flag set true as 1.\r
+* This is in contrast to many models that set a boolean flag as -1.\r
+*\r
+***\r
+\r
+* The run-time dictionary allocation area begins here, \r
+* initialized with the FORTH and TASK definitions that will be \r
+* actually used.\r
+\r
+RTDICT DS.B    RTDCSZ          ; dictionary allocation space\r
+*\r
+PSPSPC EQU     256*NATWID      ; for the parameter stack\r
+       DS.B    PSPSPC\r
+SPBUMP EQU     4*NATWID\r
+IPSP   DS.L    SPBUMP          ; initial PSP below, bumper zone above\r
+*\r
+* Don't want terminal input and parameter underflow collisions\r
+TIBSZ  EQU     80              ; bytes of input buffer, must be even on 68000.\r
+ITIB   DS.B    TIBSZ           ; Also, must match terminal width. (Bad design.)\r
+*\r
+* *** This is quite clearly a vulnerability! ***\r
+SFTBND EQU     *               ; (pseudo boundary between TIB and return stack)\r
+*\r
+RPSPAC EQU     128*NATWID      ; for the return stack\r
+       DS.B    RPSPAC\r
+RPBUMP EQU     4*NATWID\r
+IRP    DS.B    RPBUMP          ; initial RP below, bumper zone above\r
+\r
+       PAGE\r
+* Expecting 8K to 12K for the kernel, because pointers are 4 bytes.\r
+VMBASE EQU     *\r
+\r
+*   "ROMmable" init tables and pre-compiled dictionary\r
+*\r
+*    The FORTH interpreter will be organized\r
+*    so that it can be in a ROM, or write-protected if desired,\r
+* but right now we're just getting it running.\r
+\r
+* ######>> screen 3 <<\r
+*\r
+***************************\r
+**  C O L D   E N T R Y  **\r
+***************************\r
+*\r
+ORIG   NOP\r
+       BRA.W   CENT            ; ROMmable dictionary size is less than 32K\r
+***************************\r
+**  W A R M   E N T R Y  **\r
+***************************\r
+       NOP\r
+       BRA.W   WENT    warm-start code, keeps current dictionary intact\r
+\r
+*\r
+MAXNML EQU     32      ; max name length of words (symbols) in the dictionary\r
+NMLMSK EQU     MAXNML-1        ; MAXNML must be a power of 2.\r
+******* startup parmeters **************************\r
+*\r
+       DC.L    $68000,00000000 ; cpu & revision\r
+       DC.L    0               ; topmost word in FORTH vocabulary\r
+* BACKSP       DC.L    $7F     ; backspace character for editing \r
+BACKSP DC.L    $08     ; backspace character for editing \r
+UPINIT DC.L    UORIG   ; initial user area\r
+SINIT  DC.L    IPSP    ; initial top of data stack\r
+RINIT  DC.L    IRP     ; initial top of return stack\r
+       DC.L    ITIB    ; terminal input buffer\r
+IWIDTH DC.L    MAXNML  ; initial name field width\r
+       DC.L    0       ; initial warning mode (0 = no disc)\r
+FENCIN DC.L    REND    ; initial fence\r
+DPINIT DC.L    REND    ; cold start value for DICTPT\r
+BUFINT DC.L    BUFBAS  ; Start of the disk buffers area        \r
+VOCINT DC.L    FORTH+4*NATWID  \r
+COLINT DC.L    TIBSZ   ; initial terminal carriage width\r
+DELINT DC.L    4       ; initial carriage return delay\r
+****************************************************\r
+*\r
+*\r
+       PAGE\r
+*\r
+* ######>> screen 13 <<\r
+* These are of questionable use anyway, \r
+* and are too much trouble to use with native subroutine call anyway.\r
+* POPD0X       MOVE.L  (PSP)+,D0       ; These may actually not end up being used.\r
+* STD0X        MOVE.L  D0,(A0)\r
+*      BRA.S   NEXT\r
+* GETX MOVE.L  (A0),D0\r
+* PUSHD0       MOVE.L  D0,-(PSP)       ; fall through to NEXT\r
+\r
+* "NEXT" takes ?? cycles if TRACE is removed,\r
+*\r
+* and ?? cycles if trace is present and NOT tracing.\r
+*\r
+* = = = = = = =   t h e   v i r t u a l   m a c h i n e   = = = = =\r
+*                                                                 =\r
+* NEXT itself might just completely go away.\r
+* About the only reason to keep it is to allow executing a list\r
+* which allows a cheap TRACE routine.\r
+*\r
+* NEXT is a loop which implements the Forth VM.\r
+* It basically cycles through calling the code out of code lists,\r
+* one at a time.\r
+* Using a native CPU return for this uses a few extra cycles per call,\r
+* compared to simply jumping to each definition and jumping back \r
+* to the known beginning of the loop,\r
+* but the loop itself is really only there for convenience,\r
+* in the first place.\r
+* \r
+* This implementation uses indirect threading,\r
+* leaving a wall between Forth VM code and non-Forth VM code.\r
+*\r
+NEXT:  ; IP is a register.\r
+NEXT2  MOVE.L  (IP)+,VEC       ; IP is list of code pointers, W is now ephemeral (top of R at entry)\r
+* NEXT2        MOVE.L  (IP)+,W ; get W which points to CFA of word to be done\r
+* NEXT3        MOVE.L  (W)+,VEC        ; get characteristic address, point to Parameter Field.\r
+* These NOPs can be patched at run-time to JMP TRACE              =\r
+* if a TRACE routine is available:                                =\r
+*      NOP                                                       =     \r
+*      NOP                                                       =\r
+*      NOP                                                       =\r
+*      NOP                                                       =\r
+*      NOP                                                       =\r
+       TST.W   TRACEM-UORIG(UP)                                  =\r
+       BEQ.S   NEXTJ                                             =\r
+        BSR.W  PTRACE                                            =\r
+NEXTJ: JSR     (VEC)                                             =\r
+       BRA.S   NEXT                                              =\r
+* In other words, with the call and the NOP,\r
+* there is room to patch the loop with a call to your TRACE \r
+* routine, which you have to provide.\r
+*                                                                 =\r
+* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =\r
+\r
+       PAGE\r
+*\r
+* ======>>  1  <<\r
+* ( --- n )\r
+* Pushes the following natural width integer from the instruction stream\r
+* as a literal, or immediate value.\r
+*\r
+*      DC.L {OP}\r
+*      DC.L {OP}\r
+*      DC.L LIT\r
+*      DC.L LITERAL-TO-BE-PUSHED\r
+*      DC.L {OP}\r
+*\r
+* In native processor code, there should be a better way, use that instead.\r
+* More specifically, DO NOT CALL THIS from assembly language code.\r
+* (Note that there is no compile-only flag in the fig model.)\r
+*\r
+* See (FIND), or PFIND , for layout of the header format.\r
+*\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'LI'    ; 'LIT' :       NOTE: this is different from LITERAL\r
+       DC.B    'T'|$80 ; character code for T, with high bit set.\r
+       DC.L    0       ; link of zero to terminate dictionary scan\r
+*LIT   DC.L    *+NATWID        ; Note also that LIT is meaningless in native code.\r
+* And, in fact, we simply should not be using it in this version.\r
+* But if we were to use it, it would look like this:\r
+LIT    MOVE.L  (IP)+,-(PSP)\r
+       RTS\r
+*\r
+* ######>> screen 14 <<\r
+* ======>>  2  <<\r
+* ( --- n )\r
+* Save a little dictionary space by pushing a half-width value as a full-width value.\r
+* LIT8 won't really work with the 68000 because of alignment problems,\r
+* but LIT16 will save a little space.\r
+* Pushes the following 16-bit word from the instruction stream\r
+* as a literal, or immediate value.\r
+*\r
+* If this is kept, it should have a header for TRACE to read.\r
+* If the data bus is wider than a byte, consider whether you want to do this.\r
+* Byte shaving like this is often counter-productive anyway.\r
+* Changing the name to LIT16, hoping that will be more understandable.\r
+* Also, see comments for LIT: DO NOT CALL THIS from assembly language code.\r
+* (Note that there is no compile-only flag in the fig model.)\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    'LIT1'  ; 'LIT16'       ; half a LIT\r
+       DC.B    '6'|$80\r
+       DC.L    LIT-4-NATWID\r
+*LIT16 DC.L    *+NATWID        ; (this was an invisible word, with no header)\r
+* See comments on LIT. If we were to use it, it would look like this:\r
+LIT16  CLR.L   -(PSP)          ; The fig model does not sign extend.\r
+       MOVE.W  (IP)+,NATWID/2(PSP)\r
+       RTS\r
+*\r
+* ======>>  3  <<\r
+* ( adr --- )\r
+* Jump to address on stack.  Used by the "outer" interpreter to\r
+* interactively invoke routines.  \r
+* Might be useful to have EXECUTE test the pointer, as done in BIF-6809.\r
+       EVEN\r
+       DC.B    $87\r
+       DC.B    'EXECUT'        ; 'EXECUTE'\r
+       DC.B    'E'|$80 ; $C5\r
+       DC.L    LIT16-6-NATWID\r
+*EXEC  DC.L    *+NATWID\r
+*      MOVE.L  (PSP)+,W        ; Get the adr parameter.\r
+*      MOVE.L  (W)+,VEC        ; Or, pretend we are the inner interpreter\r
+EXEC   MOVE.L  (PSP)+,VEC      ; The adr parameter now points directly to code.\r
+       JMP     (VEC)           ; tail return\r
+*      \r
+*\r
+* ######>> screen 15 <<\r
+* ======>>  4  <<\r
+*\r
+* *** Since we are using NEXT (i-code lists), we are using BRANCH, et. al.\r
+\r
+* ( --- )                                                 C\r
+* Add the following word from the instruction stream to the\r
+* instruction pointer (Y++).  Causes a program branch in Forth code stream.\r
+*\r
+* In native processor code, there should be a better way, use that instead.\r
+* More specifically, DO NOT CALL THIS from assembly language code.\r
+* This is only for Forth code stream.\r
+* Also, see comments for LIT.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $86\r
+       DC.B    'BRANC' ; 'BRANCH'\r
+       DC.B    'H'|$80\r
+       DC.L    EXEC-8-NATWID\r
+*BRAN  DC.L    *+NATWID\r
+*ZBYES:                ; No more code stealing needed here.\r
+BRAN   MOVE.L  (IP)+,D1\r
+       LEA     (IP,D1.L),IP    ; IP is postinc\r
+       RTS\r
+* ======>>  5  <<\r
+* ( f --- )                                               C\r
+* BRANCH if flag is zero.\r
+*\r
+* In native processor code, there should be a better way, use that instead.\r
+* More specifically, DO NOT CALL THIS from assembly language code.\r
+* This is only for Forth code stream.\r
+* Also, see comments for LIT.\r
+       EVEN\r
+       DC.B    $87\r
+       DC.B    '0BRANC'        ; '0BRANCH'\r
+       DC.B    'H'|$80\r
+       DC.L    BRAN-7-NATWID\r
+*ZBRAN DC.L    *+NATWID\r
+* No more code stealing needed here.\r
+*ZBRAN TST.L   (PSP)+\r
+*      BNE.S   ZBNO\r
+*ZBYES MOVE.L  (IP)+,D0\r
+*      LEA     (IP,D0.L),IP    ; IP is postinc\r
+*      RTS\r
+*ZBNO  LEA     NATWID(IP),IP ; No branch.\r
+*      RTS\r
+ZBRAN  MOVE.L  (IP)+,D1        ; Grab offset and update IP first.\r
+       TST.L   (PSP)+\r
+       BNE.S   ZBNO\r
+       LEA     (IP,D1.L),IP    ; IP is postinc\r
+ZBNO   RTS\r
+*\r
+\r
+* ######>> screen 16 <<\r
+\r
+* ======>>  6  <<\r
+* ( --- )         ( limit index *** limit index+1)        C\r
+*                 ( limit index *** )\r
+* Counting loop primitive.  The counter and limit are the top two\r
+* words on the return stack.  If the updated index/counter does\r
+* not exceed the limit, a branch occurs.  If it does, the branch\r
+* does not occur, and the index and limit are dropped from the\r
+* return stack.\r
+*\r
+* Loop words share the counter increment via D0.\r
+*\r
+* In native processor code, there should be a better way, use that instead.\r
+* More specifically, DO NOT CALL THIS from assembly language code.\r
+* This is only for Forth code stream.\r
+* Also, see comments for LIT.\r
+* D0 and various code paths are shared with XPLOOP.\r
+* Having to dodge the return address on the stack might be reason\r
+* for loop variables in registers, but not yet.\r
+LUPLIM EQU     NATWID*2        ; limit was pushed first, \r
+LUPCT  EQU     NATWID          ; then index/count\r
+* \r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $86\r
+       DC.B    '(LOOP' ; '(LOOP)'\r
+       DC.B    ')'|$80\r
+       DC.L    ZBRAN-8-NATWID\r
+*XLOOP DC.L    *+NATWID\r
+*XLOOP MOVEQ   #1,D0   ; Loop counter and limit on return stack.\r
+*XLOOPA        ADD.L   LUPCT(RP),D0\r
+*      MOVE.L  D0,LUPCT(RP)\r
+*      CMP.L   LUPLIM(RP),D0\r
+*      BMI.S   ZBYES   ; pseudo-signed-unsigned\r
+*XLOOPN        LEA     NATWID(IP),IP\r
+*      MOVE.L  (RP),A0 ; Get the return to NEXT.\r
+*      LEA     LUPLIM+NATWID(RP),RP    ; drop loop control variables\r
+*      JMP     (A0)\r
+XLOOP  MOVEQ   #1,D0   ; Loop counter and limit on return stack.\r
+XLOOPA MOVE.L  (IP)+,D1        ; Grab offset and update IP first.\r
+       ADD.L   LUPCT(RP),D0\r
+       MOVE.L  D0,LUPCT(RP)\r
+       CMP.L   LUPLIM(RP),D0\r
+       BPL.S   XLOOPN  ; pseudo-signed-unsigned\r
+XLOOPY LEA     (IP,D1.L),IP    ; IP is postinc\r
+       RTS\r
+XLOOPN MOVE.L  (RP),A0 ; Get the return to NEXT.\r
+       LEA     LUPLIM+NATWID(RP),RP    ; drop loop control variables, too\r
+       JMP     (A0)\r
+*\r
+* Old notes for loop counter and limit in registers:\r
+*      MOVEQ   #1,D0   ; Loop counter and limit in registers.\r
+* XLOOPA       ADD.L   D0,LUPCT\r
+*      CMP.L   LUPLIM,LUPCT\r
+*      BMI.S   ZBYES   ; pseudo-signed-unsigned\r
+* XLOOPN       LEA     NATWID(IP),IP\r
+*      MOVEM.L (RP)+,LUPLIM/LUPCT      ; restore possible outer loop controls\r
+*      RTS     \r
+*\r
+* ======>>  7  <<\r
+* ( n --- )       ( limit index *** limit index+n )       C\r
+*                 ( limit index *** )\r
+* Loop with a variable increment.  Terminates when the index\r
+* crosses the boundary from one below the limit to the limit.  A\r
+* positive n will cause termination if the result index equals the\r
+* limit.  A negative n must cause the index to become less than\r
+* the limit to cause loop termination.\r
+*\r
+* Note that the end conditions are not symmetric around zero.\r
+*\r
+* In native processor code, there should be a better way, use that instead.\r
+* More specifically, DO NOT CALL THIS from assembly language code.\r
+* This is only for Forth code stream.\r
+* Also, see comments for LIT.\r
+* D0 and various code paths are shared with XLOOP.\r
+       EVEN\r
+       DC.B    $87\r
+       DC.B    '(+LOOP'        ; '(+LOOP)'\r
+       DC.B    ')'|$80\r
+       DC.L    XLOOP-7-NATWID\r
+*XPLOOP        DC.L    *+NATWID        ; Loop counter and limit in registers.\r
+XPLOOP MOVE.L  (PSP)+,D0       ; inc val\r
+       BPL.S   XLOOPA          ; Steal plain loop code for forward count.\r
+       ADD.L   LUPCT(RP),D0\r
+       MOVE.L  D0,LUPCT(RP)\r
+       CMP.L   LUPLIM(RP),D0\r
+       BPL.S   XLOOPY          ; pseudo-signed-unsigned\r
+       BRA.S   XLOOPN          ; Which path is less time-sensitive?\r
+*\r
+* Notes for loop counter and limit in registers:\r
+*      MOVE.L  (PSP)+,D0       ; inc val\r
+*      BPL.S   XLOOPA          ; Steal plain loop code for forward count.\r
+*      ADD.L   D0,LUPCT\r
+*      CMP.L   LUPLIM,LUPCT\r
+*      BPL.S   ZBYES           ; pseudo-signed-unsigned\r
+*      BRA.S   XLOOPN          ; This path might be less time-sensitive.\r
+*\r
+* ######>> screen 17 <<\r
+* ======>>  8  <<\r
+* ( limit index --- )     ( *** outerlimit outerindex )\r
+* Save whatever is in limit and index registers, Load the loop parameters. \r
+* This would NOT be a synonym for D>R (2>R) if we were keeping the control variables in registers.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $84\r
+       DC.B    '(DO'   ; '(DO)'\r
+       DC.B    ')'|$80\r
+       DC.L    XPLOOP-8-NATWID\r
+*XDO   DC.L    *+NATWID        ; This is the RUNTIME DO, not the COMPILING DO\r
+XDO    MOVEM.L (PSP)+,D0/D1    ; MOVEM preserves the order.\r
+       MOVE.L  (RP)+,A0        ; get the return to NEXT out of the way.\r
+       MOVEM.L D0/D1,-(RP)     ; Control variables are now on the return stack.\r
+       JMP     (A0)            ; Back to NEXT\r
+*\r
+* Notes for loop counter and limit in registers:\r
+*      MOVE.L  (RP)+,A0        ; Get the reurn to NEXT out of the way\r
+*      MOVEM.L LUPLIM/LUPCT,-(RP)      ; save possible outer loop limit and count\r
+*      MOVEM.L (PSP)+,LUPLIM/LUPCT     ; limit must be higher register number to be deeper in stack. \r
+*      JMP     (A0)    ; Back to NEXT\r
+*\r
+* ======>>  9  <<\r
+* ( --- index )           ( limit index *** limit index )\r
+* Copy the loop index from the index register. \r
+* This would NOT be a synonym for R if we were keeping the control variables in registers.\r
+       EVEN\r
+       DC.B    $81\r
+       DC.B    'I'|$80 ; I\r
+       DC.L    XDO-5-NATWID    \r
+*I     DC.L    *+NATWID\r
+I      MOVE.L  LUPCT(RP),-(PSP)        ; hide dodge in LUPCT\r
+       RTS\r
+*\r
+* Notes for loop counter and limit in registers:\r
+*      MOVE.L  LUPCT,-(PSP)    ; nothing to dodge\r
+*      RTS\r
+*\r
+* ######>> screen 18 <<\r
+* ======>>  10  <<\r
+* ( c base --- false )\r
+* ( c base --- n true )\r
+* Translate C in base, yielding a translation valid flag.  \r
+* If the translation is not valid in the specified base,\r
+* only the false flag is returned.\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    'DIGI'  ; 'DIGIT'\r
+       DC.B    'T'|$80\r
+       DC.L    I-2-NATWID\r
+*DIGIT DC.L    *+NATWID        ; NOTE: legal input range is 0-9, A-Z\r
+DIGIT  MOVE.L  NATWID(PSP),D0  ; Check the whole 32 bits.\r
+       CMP.L   #'Z',D0         ; Allow byte width from here.\r
+       BHI.S   DIGITN\r
+       SUB.L   #'0',D0         ; ascii zero\r
+       BLO.S   DIGITN          ; IF LESS THAN '0', ILLEGAL\r
+       CMP.B   #9,D0\r
+       BLS.S   DIGITB          ; IF '9' OR LESS\r
+       SUB.B   #'A'-('9'+1),D0 ; translate 'A' thru 'Z'\r
+       CMP.B   #$A,D0          ; between '9' and 'A'?\r
+       BLO.S   DIGITN          ; if less than 'A'\r
+DIGITB CMP.B   NATWID-1(PSP),D0        ; Check the base.\r
+       BHS.S   DIGITN          ; error if not less than the base\r
+       MOVE.L  D0,NATWID(PSP)  ; Store converted digit. (High bytes known zero.)\r
+       MOVE.L  #1,(PSP)        ; store valid flag \r
+       RTS\r
+DIGITN LEA     NATWID(PSP),PSP ; pop base\r
+       MOVE.L  #0,(PSP)        ; set not valid flag\r
+       RTS\r
+*\r
+* ######>> screen 19 <<\r
+*\r
+* The word definition format in the dictionary:\r
+*\r
+* (Symbol names are bracketed by bytes with the high bit set, rather than linked.)\r
+*\r
+* EVEN address alignment on 68K.\r
+* Optional byte of zero for odd name fields on 68K.\r
+* NFA (name field address):\r
+* char-count + $80     Length of symbol name, flagged with high bit set.\r
+* char 1               Characters of symbol name.\r
+* char 2\r
+* ...\r
+* char n  + $80      symbol termination flag (char set < 128 code points)\r
+* LFA (link field address):\r
+* link high byte \\r
+* ... inner byte  \___pointer to previous word in list\r
+* ... inner byte  /   (List is combined allocation/dictionary list.)\r
+* link low byte  /\r
+* The definition label is now the code field.\r
+* Code follows immediately after the allocation link.\r
+* When there is a parameter field, the code here is a branch to the characteristic code.\r
+* When the characteristic is near, use/look for BSR.W.\r
+* Figure out far/intermodule characteristics later.\r
+* A BSR.W is 16-bit op-code and 16-bit address == 32 bits, so --\r
+* PFA (parameter field address) is NATWID after the definition label in the near case:\r
+* parameter fields   -- Machine code for low-level native machine CPU code starts at label,\r
+*    "                  instruction list for high-level Forth code,\r
+*    "                  constant data for constants, pointers to per task variables,\r
+*    "                  space for variables, for global variables, etc.\r
+*\r
+* Note that CFA and PFA entanglement is now much tighter.\r
+\r
+* Definition attributes:\r
+FIMMED EQU     $40     ; Immediate word flag.\r
+FSMUDG EQU     $20     ; Smudged => definition not ready.\r
+CTMASK EQU     ($FF&(~($80|FIMMED)))   ; For unmasking the length byte.\r
+* Note that the SMUDGE bit is not masked out.\r
+*\r
+* But we really want more flags (Thinking for a new model, need one more byte):\r
+* FCOMPI       EQU     $10     ; Compile-time-only.\r
+* FASSEM       EQU     $08     ; Assembly-language code only.\r
+* F4THLV       EQU     $04     ; Must not be called from assembly language code.\r
+* These would require some significant adjustments to the model.\r
+* We also want to put the low-level VM stuff in its own vocabulary, eventually.\r
+*\r
+* ======>>  11  <<\r
+* (FIND)  ( name vocptr --- locptr length true )\r
+*         ( name vocptr --- false )\r
+* Search vocabulary for a symbol called name. \r
+* name is a pointer to a high-bit bracketed string with length head.\r
+* vocptr is a pointer to the NFA of the tail-end (LATEST) definition \r
+* in the vocabulary to be searched.\r
+* Hidden (SMUDGEd) definitions are lexically not equal to their name strings.\r
+* Use the stack and registers instead of temp area N.\r
+PA0    EQU     NATWID  ; pointer to the length byte of name being searched against\r
+YPA0   EQUR    A2      ; ditto\r
+PD     EQU     0       ; pointer to NFA of dict word being checked\r
+XPD    EQUR    A1      ; ditto\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $86\r
+       DC.B    '(FIND' ; '(FIND)'\r
+       DC.B    ')'|$80\r
+       DC.L    DIGIT-6-NATWID\r
+*PFIND DC.L    *+NATWID\r
+PFIND  MOVE.L  PD(PSP),XPD     ; Start in on the vocabulary (NFA).\r
+PFNDLP MOVE.L  PA0(PSP),YPA0   ; Point to the name to check against.\r
+       MOVE.B  (XPD)+,D1       ; get dict name length byte\r
+       MOVE.B  D1,D0           ; Save it in case it matches.\r
+       AND.B   #CTMASK,D1 \r
+       CMP.B   (YPA0)+,D1      ; Compare lengths\r
+       BNE.S   PFNDUN\r
+PFNDBR MOVE.B  (XPD)+,D1       ; Is high bit of character in dictionary entry set?\r
+       BPL.S   PFNDCH\r
+       AND.B   #$7F,D1         ; Clear high bit in char from dictionary.\r
+       CMP.B   (YPA0)+,D1      ; Compare "last" characters.\r
+       BEQ.S   PFOUND          ; Matches even if dictionary actual length is shorter.\r
+PFNDLN MOVE.L  (XPD)+,D0       ; Get previous link in vocabulary. (Note flag entry to switch vocabularies by.)\r
+       MOVE.L  D0,XPD          ; On 68K, flags not in effect for MOVEA, TST not available, and this is what we wanted.\r
+       BNE.S   PFNDLP          ; Continue if link not=0\r
+*\r
+*      not found :\r
+       LEA     NATWID(PSP),PSP ; Return only false flag.\r
+       CLR.L   (PSP)\r
+       RTS\r
+*\r
+PFNDCH CMP.B   (YPA0)+,D1      ; Compare characters.\r
+       BEQ.S   PFNDBR\r
+PFNDUN:\r
+PFNDSC MOVE.B  (XPD)+,D1       ; scan forward to end of this name in dictionary\r
+       BPL.S   PFNDSC\r
+       BRA.S   PFNDLN\r
+*\r
+*      found :\r
+*\r
+PFOUND LEA     2*NATWID(XPD),XPD       ; point to parameter field\r
+       MOVE.L  XPD,NATWID(PSP)\r
+       CLR.L   D1              ; make sure count is valid\r
+       MOVE.B  D0,D1\r
+       MOVE.L  D1,(PSP)\r
+       MOVEQ   #1,D1           ; set a true flag\r
+       MOVE.L  D1,-(PSP)\r
+       RTS\r
+*\r
+* ######>> screen 20 <<\r
+* ======>>  12  <<\r
+* ( buffer ch --- buffer symboloffset delimiteroffset scancount )\r
+* ( buffer ch --- buffer symboloffset nuloffset scancount ) ( Scan count == nuloffset )\r
+* ( buffer ch --- buffer nuloffset onepast scancount )\r
+* Scan buffer for a symbol delimited by ch or ASCII NUL, \r
+* return the length of the buffer region scanned,\r
+* the offset to the trailing delimiter,\r
+* and the offset of the first character of the symbol. \r
+* Leave the buffer on the stack.\r
+* Scancount is also offset to first character not yet looked at.\r
+* If no symbol in buffer, scancount and symboloffset point to NUL\r
+* and delimiteroffset points one beyond for some reason. \r
+* On trailing NUL, delimiteroffset == scancount.\r
+* (Buffer is the address of the buffer array to scan.)\r
+* (This is a bit too tricky, really.)\r
+* NOTE :\r
+* FC means offset (bytes) to First Character of next word\r
+* EW  "     "   to End of Word\r
+* NC  "     "   to Next Character to start next enclose at\r
+       EVEN\r
+       DC.B    $87\r
+       DC.B    'ENCLOS'        ; 'ENCLOSE'\r
+       DC.B    'E'|$80\r
+       DC.L    PFIND-7-NATWID\r
+*ENCLOS        DC.L    *+NATWID\r
+ENCLOS MOVE.B  NATWID-1(PSP),D0        ; Delimiter character to match against in D0.\r
+       MOVE.L  NATWID(PSP),A0  ; Buffer to scan in.\r
+       CLR.L   D1              ; Initialize offset. (No particular limit on Buffer width.)\r
+*      Scan to a non-delimiter or a NUL\r
+ENCDEL TST.B   (A0,D1.W)               ; NUL ?\r
+       BEQ.S   ENCNUL\r
+       CMP.B   (A0,D1.W),D0    ; Delimiter?\r
+       BNE.S   ENC1ST\r
+       ADDQ.L  #1,D1           ; count character\r
+       BRA.S   ENCDEL\r
+*      Found first character. Save the offset.\r
+ENC1ST MOVE.L  D1,(PSP)        ; Found first non-delimiter character -- store the count.\r
+*      Scan to a delimiter or a NUL\r
+ENCSYM TST.B   (A0,D1.W)       ; NUL ?\r
+       BEQ.S   ENC0TR\r
+       CMP.B   (A0,D1.W),D0    ; delimiter?\r
+       BEQ.S   ENCEND\r
+       ADDQ.L  #1,D1\r
+       BRA.S   ENCSYM\r
+*      Found end of symbol. Push offset to delimiter found.\r
+ENCEND MOVE.L  D1,-(PSP)       ; Offset to seen delimiter.\r
+*      Advance and push address of next character to check.\r
+       ADDQ.L  #1,D1   ; one past \r
+       MOVE.L  D1,-(PSP)\r
+       RTS\r
+*      Found NUL before non-delimiter, therefore there is no word\r
+ENCNUL MOVE.L  D1,(PSP)        ; offset to NUL.\r
+       ADDQ.L  #1,D1           ; Point after NUL to allow (FIND) to match it.\r
+       MOVE.L  D1,-(PSP)       ;\r
+       SUBQ.L  #1,D1           ; Next is not passed NUL.\r
+       MOVE.L  D1,-(PSP)       ; Stealing code will save only one byte.\r
+       RTS\r
+*      Found NUL following the word instead of delimiter.\r
+ENC0TR\r
+       MOVE.L  D1,-(PSP)       ; Save offset to first after symbol (NUL)\r
+       MOVE.L  D1,-(PSP)       ; and count scanned.\r
+       RTS\r
+*\r
+       PAGE\r
+*\r
+* ######>> screen 21 <<\r
+* The next 4 words call system dependant I/O routines\r
+* which are listed after word "-->" ( label: "arrow" )\r
+* in the dictionary.\r
+*\r
+* ======>>  13  <<\r
+* ( c --- )\r
+* Write c to the output device (screen or printer).\r
+******* Need to write this for the ST ROM BIOS.\r
+******* Probably want to go ahead and define PEMIT, PKEY, PQTER, and PCR.\r
+******* Also might want to tune UORIG variable sizes.\r
+******* Need to find a way to set default operand size to Long.\r
+* ROM Uses the ECB device number at address $6F,\r
+* -2 is printer, 0 is screen.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $84\r
+       DC.B    'EMI'   ; 'EMIT'\r
+       DC.B    'T'|$80\r
+       DC.L    ENCLOS-8-NATWID\r
+*EMIT  DC.L    *+NATWID\r
+EMIT   MOVE.L  (PSP)+,D1\r
+       BSR.W   PEMIT   ; PEMIT expects the character in D1.\r
+       ADDQ.L  #1,XOUT-UORIG(UP)       ; Bump the output count.\r
+EMITDN RTS\r
+*\r
+* ======>>  14  <<\r
+* ( --- c )\r
+* ( --- BREAK )\r
+* Wait for a key from the keyboard. \r
+* If the key is BREAK, set the high byte (result $FF03).\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'KE'    ; 'KEY'\r
+       DC.B    'Y'|$80\r
+       DC.L    EMIT-5-NATWID\r
+*KEY   DC.L    *+NATWID\r
+KEY    BSR.W   PKEY    ; PKEY leaves the scancode|key/break in D1.\r
+       AND.L   #$000000FF,D1\r
+       MOVE.L  D1,-(PSP)\r
+       RTS\r
+*\r
+* ======>>  15  <<\r
+* ( --- f )\r
+* Scan keyboard, but do not wait.  \r
+* Return 0 if no key,\r
+* BREAK ($ff03) if BREAK is pressed,\r
+* or key currently pressed.    \r
+       EVEN\r
+       DC.B    $89\r
+       DC.B    '?TERMINA'      ; '?TERMINAL'\r
+       DC.B    $CC\r
+       DC.L    KEY-4-NATWID\r
+*QTERM DC.L    *+NATWID\r
+QTERM  BSR.W   PQTER   ; PQTER leaves the flag/key in D1.\r
+       MOVE.L  D1,-(PSP)\r
+       RTS\r
+*\r
+* ======>>  16  <<\r
+* ( --- )\r
+* EMIT a Carriage Return (ASCII CR).\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    'C'     ; 'CR'\r
+       DC.B    'R'|$80\r
+       DC.L    QTERM-10-NATWID\r
+*CR    DC.L    *+NATWID\r
+CR     BSR.W   PCR     ; Nothing really to do here.\r
+       RTS\r
+*\r
+* ######>> screen 22 <<\r
+* ======>>  17  <<\r
+* ( source target count --- )\r
+* Copy/move count bytes from source to target.  \r
+* Moves ascending addresses,\r
+* so that overlapping only works if the source is above the destination.\r
+* CMOVE provides a nice testbed for the intersection between clever and real.\r
+* It also raises questions about why one might want to move all of memory.\r
+* The 68000 DBF instruction only does up to 2^16 moves, which is probably a reasonable limit;\r
+* but, rather than answer that question and/or the logic of split count, use a straight count.\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    'CMOV'  ; 'CMOVE' :     source, destination, count\r
+       DC.B    'E'|$80\r
+       DC.L    CR-3-NATWID\r
+*CMOVE DC.L    *+NATWID\r
+CMOVE  MOVEM.L (PSP)+,D1/A0/A1 ; No effect in flags.\r
+       TST.L   D1      ; Don't let zero count equal 2^32.\r
+       BEQ.S   CMOVEX  ; Stack clean.\r
+CMOVEL MOVE.B  (A1)+,(A0)+\r
+       SUBQ.L  #1,D1\r
+       BNE.S   CMOVEL\r
+CMOVEX RTS\r
+*\r
+**     One possible way to use DBcc (untested):\r
+*      MOVEM.L (PSP)+,D1/A0/A1 ; No effect in flags.\r
+*      TST.L   D1      ; Don't let zero count equal 2^32.\r
+*      BEQ.L   CMOVEX  ; Stack clean.\r
+*      SUBQ.W  #1,D1   ; Adjust for DBcc\r
+*CMOVEL        MOVE.B  (A1)+,(A0)+\r
+*      DBF     D1,CMOVEL\r
+*      SUB.L   #$10000,D1\r
+*      BCC.S   CMOVEL\r
+*CMOVEX        RTS     ;\r
+*\r
+* ( source target count --- )\r
+* Copy/move count bytes from source to target.  \r
+* Moves descending addresses,\r
+* so that overlapping does work if the source is below the destination.\r
+* And, conversely, does not work if the source is above the destination.\r
+* Not in fig, provided here for aligning header names in CREATE.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $86\r
+       DC.B    'CMOVE' ; 'CMOVED' :    source, destination, count\r
+       DC.B    'D'|$80\r
+       DC.L    CMOVE-6-NATWID\r
+*CMOVD DC.L    *+NATWID\r
+CMOVD  MOVEM.L (PSP)+,D1/A0/A1 ; No effect in flags.\r
+       TST.L   D1      ; Don't let zero count equal 2^32.\r
+       BEQ.S   CMOVDX  ; Stack clean.\r
+       LEA     (A1,D1.L),A1    ; Point to (one past) the ends.\r
+       LEA     (A0,D1.L),A0\r
+CMOVDL MOVE.B  -(A1),-(A0)\r
+       SUBQ.L  #1,D1\r
+       BNE.S   CMOVDL\r
+CMOVDX RTS\r
+* Could use MOVE.B     (A1,D0.L),(A0,D0.L), too, but that would take extra cycles.\r
+*\r
+* ######>> screen 23 <<\r
+* ======>>  18  <<\r
+* ( u1 u2 --- ud )\r
+* Multiplies the top two unsigned integers,\r
+* yielding a double integer product.\r
+* Word at a time, but significantly faster than bit-at-a-time.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    'U'     ; 'U*'\r
+       DC.B    '*'|$80\r
+       DC.L    CMOVD-7-NATWID\r
+*USTAR DC.L    *+NATWID\r
+USTAR  MOVEM.W (PSP),D0/D1/D2/D3       ; MOVEM is a cheap way to split the low and high words.\r
+       MULU.W  D3,D1           ; U2 low by U1 low, and it's in place\r
+       MULU.W  D2,D0           ; U2 high by U1 high, and it's in place\r
+       MULU.W  NATWID/2(PSP),D2        ; U1 high by U2 low\r
+       MULU.W  (PSP),D3        ; U1 low by U2 high\r
+       ADD.L   D3,D2           ; sum of inner products\r
+       CLR.L   D3              ; X-carry is not affected\r
+       ADDX.L  D3,D3           ; grab the X-carry (no ADDX #0!)\r
+       SWAP    D3              ; move the carry into place\r
+       SWAP    D2              ; fast 16 bit rotate\r
+       MOVE.W  D2,D3           ; high half of inner product, carry in place\r
+       AND.L   #$FFFF0000,D2   ; low half of inner product\r
+       ADD.L   D2,D1\r
+       ADDX.L  D3,D0           ; along with both carries!\r
+       MOVEM.L D0/D1,(PSP)     ; stack is as we want it.\r
+       RTS\r
+*\r
+*\r
+* ######>> screen 24 <<\r
+* ======>>  19  <<\r
+* ( ud u --- uremainder uquotient )\r
+* Divides the top unsigned integer\r
+* into the second and third words on the stack\r
+* as a single unsigned double integer,\r
+* leaving the remainder and quotient (quotient on top)\r
+* as unsigned integers.\r
+*\r
+* The reason for this oddity is that U/ was intended to be the inverse of U* :\r
+* in other words, \r
+* U/ can only divide without overflow if the dividend is the result of \r
+* the divisor multiplied by the quotient using U* , \r
+* with an added constant less than the divisor (the remainder portion).\r
+*\r
+* This is particularly useful in columnar division,\r
+* when the divisor fits within the defined column:\r
+*              \r
+*    The smaller the divisor, the more likely dropping the high word \r
+*    of the quotient loses significant bits. See M/MOD .\r
+*\r
+* An example of a dividend/divisor pair that would not work:\r
+* HEX 200000000 2 U/\r
+* -- The largest multiple of 2 that U* could produce in a 32-bit environment would be\r
+* HEX 1FFFFFFFE\r
+* Thus, HEX 1FFFFFFFF would be the maximum 64-bit number\r
+* that U/ would divide by 2 without overflow.\r
+*\r
+* Note (from M/MOD) that U/ can be chained, as long as the divisor is single-width.\r
+*\r
+* For a library routine, I would probably want to run-time optimize the divide,\r
+* following four paths:\r
+* If divisor is zero, (1) give saturation result of max quotient, max remainder --\r
+* else if divisor fits in 16 bits, \r
+*   if dividend fits in 16 bits, (2) use native DIVU --\r
+*   else (3) use chained native DIVU (can be one less than full divide);\r
+* else, (4) for each 16-bit column,\r
+*   use native DIVU to guess high word of quotient\r
+*   multiply and subtract intermediate product\r
+*   if too guess too large, decrement guess and add divisor to get remainder\r
+*   shift to the next right column\r
+* But light testing would not be sufficient.\r
+* Each path would need to be tested against its next more optimal path.\r
+* And the resulting routine could be full M/MOD, if paths 3 and 4 are fully worked out.\r
+*\r
+* For now, for the fig model --\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    'U'     ; 'U/'\r
+       DC.B    '/'|$80\r
+       DC.L    USTAR-3-NATWID\r
+* Using the bit divide to reduce testing burden, working in registers.\r
+USLASH:\r
+*      DC.L    *+NATWID\r
+       MOVEM.L (PSP),D0/D1/D2  ; D1:D2 by D0   (40~ ignore attempts to count cycles)\r
+       MOVE.W  #32,D3  ; bit ct for DBcc       (8~)\r
+USLDIV:\r
+       CMP.L   D0,D1   ; divisor               (6~)\r
+       BHS.S   USLSUB                          (8/10~)\r
+       AND     #~F_EXT,CCR     ; X-carry clear         (20~)\r
+       BRA.S   USLBIT                          (10~)\r
+USLSUB:\r
+       SUB.L   D0,D1                           (6~)\r
+       OR      #F_EXT,CCR      ; quotient, (X-carry set)       (20~)\r
+USLBIT:\r
+       ROXL.L  #1,D2   ; save it               (8~)\r
+       DBF     D3,USLMOR       ; more bits? Don't mess with CCR        ((12/14)/10~)\r
+USLR:\r
+       LEA     NATWID(PSP),PSP                 (8~)\r
+       MOVE.L  D1,NATWID(PSP)                  (16~)\r
+       MOVE.L  D2,(PSP)                        (12~)\r
+       RTS\r
+USLMOR:\r
+       ROXL.L  #1,D1   ; remainder             (8~)\r
+       BCC.S   USLDIV                          (8/10~)\r
+       BRA.S   USLSUB                          (10~)   (~90*32=~2880+entry+exit, about 800 Î¼S at 4 MHz)\r
+\r
+* The following is not yet functional, only here to help me remember:\r
+* cUSLASH      DC.L    *+NATWID\r
+*      MOVE.W  (PSP)+,D0\r
+*      BNE     USL32\r
+*      MOVE.W  (PSP)+,D0       ; stack pre-adjusted\r
+*      BNE     USL16   ; avoid DIV by 0 exception\r
+*      MOVE.L  #-1,(PSP)       ; quotient too large\r
+*      MOVE.L  #-1,NATWID(PSP) ; remainder too large\r
+*      RTS\r
+* cUSL16       CLR.L   D1\r
+*      MOVE.W  (PSP),D1        ; start with highest half\r
+*      DIVU.W  D0,D1           ; can't overflow\r
+*      MOVE.W  D1,(PSP)        ; remainder in high half\r
+*      MOVE.W  NATWID/2(PSP),D1        ; 2nd half\r
+*      DIVU.W  D0,D1\r
+*      MOVE.W  D1,NATWID/2(PSP)\r
+*      MOVE.W  NATWID(PSP),D1          ; 3rd half\r
+*      DIVU.W  D0,D1\r
+*      MOVE.W  D1,NATWID(PSP)\r
+*      MOVE.W  3*NATWID/2(PSP),D1      ; lowest half\r
+*      DIVU.W  D0,D1                   ; (140~) (~140*4=560+smallstuff)\r
+*      MOVE.W  D1,3*NATWID/2(PSP)      \r
+*      CLR.W   D1\r
+*      SWAP.W  D1\r
+*      RTS\r
+* cUSL32\r
+*\r
+* Following the 6809 code, working on the stack.\r
+* Untested:\r
+* B0USLASH:\r
+*      DC.L    *+NATWID\r
+*      MOVE.W  #33,D3  ; bit ct\r
+*      MOVE.L  NATWID(PSP),D2  ; dividend\r
+* B0USLDIV:\r
+*      CMP.L   (PSP),D2        ; divisor\r
+*      BHS.S   B0USLSUB\r
+*      AND     #~F_EXT,CCR     ; X-carry clear\r
+*      BRA.S   B0USLBIT\r
+* B0USLSUB:\r
+*      SUB.L   (PSP),D2\r
+*      OR      #F_EXT,CCR      ; quotient, (X-carry set)\r
+* B0USLBIT:\r
+*      ROXL.W  2*NATWID+NATWID/2(PSP)  ; save it\r
+*      ROXL.W  2*NATWID(PSP)           ; in memory has only 16-bit by 1 bit form\r
+*      SUBQ.W  #1,D3   ; more bits?\r
+*      BEQ.S   B0USLR\r
+*      ROXL.L  D2      ; remainder\r
+*      BCC.S   B0USLDIV\r
+*      BRA.S   B0USLSUB\r
+* B0USLR:\r
+*      LEA     NATWID(PSP),PSP\r
+*      MOVE.L  NATWID(PSP),D1\r
+*      MOVEM.L D1/D2,(PSP)\r
+*      RTS\r
+*\r
+\r
+       PAGE\r
+* ######>> screen 25 <<\r
+* ======>>  20  <<\r
+* ( n1 n2 --- n )\r
+* Bitwise and the top two integers.\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'AN'    ; 'AND'\r
+       DC.B    "D"|$80\r
+*      DC.L    I-2-NATWID      ; ***** debug link *****\r
+       DC.L    USLASH-3-NATWID ; correct link\r
+*AND   DC.L    *+NATWID\r
+AND    MOVE.L  (PSP)+,D0\r
+       AND.L   D0,(PSP)\r
+       RTS\r
+*\r
+* ======>>  21  <<\r
+* ( n1 n2 --- n )\r
+* Bitwise or the top two integers.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    'O'     ; 'OR'\r
+       DC.B    'R'|$80\r
+       DC.L    AND-4-NATWID\r
+*OR    DC.L    *+NATWID\r
+OR     MOVE.L  (PSP)+,D0\r
+       OR.L    D0,(PSP)\r
+       RTS\r
+*      \r
+* ======>>  22  <<\r
+* ( n1 n2 --- n )\r
+* Bitwise exclusive or the top two integers.\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'XO'    ; 'XOR'\r
+       DC.B    'R'|$80\r
+       DC.L    OR-3-NATWID\r
+*XOR   DC.L    *+NATWID\r
+XOR    MOVE.L  (PSP)+,D0\r
+       EOR.L   D0,(PSP)\r
+       RTS\r
+*\r
+* Not in fig,\r
+* for CPUs that don't like odd addresses.\r
+* Test whether top of stack is odd, push flag: 0 => even, 1 => odd.\r
+* ( n --- n f )\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $84\r
+       DC.B    '?OD'   ; '?ODD'\r
+       DC.B    'D'|$80\r
+       DC.L    XOR-4-NATWID\r
+*QODD  DC.L    *+NATWID\r
+QODD   MOVE.L  (PSP),-(PSP)\r
+       AND.L   #1,(PSP)\r
+       RTS\r
+*      MOVE.L  (PSP),D0\r
+*      AND.L   #1,D0\r
+*      MOVE.L  D0,-(PSP)\r
+*      RTS\r
+*\r
+* Not in fig --\r
+* Calculate the bump adjustment necessary for odd or even alignment.\r
+* Odd for odd alignment, even for even.\r
+* bump is 0 (no adjustment) or 1 (adjustment needed)\r
+* ( n alignment --- n bump )\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $8A\r
+       DC.B    'ALIGN-BUM'     ; 'ALIGN-BUMP'\r
+       DC.B    'P'|$80\r
+       DC.L    QODD-5-NATWID\r
+*ALGNB DC.L    *+NATWID\r
+ALGNB  MOVE.L  (PSP),D0\r
+       AND.L   #1,D0   ; Even or odd alignment?\r
+       MOVE.L  NATWID(PSP),D1\r
+       AND.W   #1,D1   ; Even address or odd?\r
+       EOR.W   D0,D1   ; odd on even or even on odd is 1, else 0\r
+       MOVE.L  D1,(PSP)\r
+       RTS\r
+*\r
+** Not in fig,\r
+** for CPUs that don't like odd addresses.\r
+** Floor top of stack even.\r
+** ( n --- even )\r
+*      EVEN\r
+*      DC.B    0\r
+*      DC.B    $86\r
+*      DC.B    'FLOOR' ; 'FLOOR2'\r
+*      DC.B    '2'|$80\r
+*      DC.L    ALGNB-11-NATWID\r
+** FLOOR2      DC.L    *+NATWID\r
+* FLOOR2       AND.W   #$FFFE,NATWID/2(PSP)\r
+*      RTS\r
+**\r
+** Not in fig,\r
+** for CPUs that don't like odd addresses.\r
+** Make top of stack even by adjusting it up.\r
+** ( n --- even )\r
+*      EVEN\r
+*      DC.B    0\r
+*      DC.B    $88\r
+*      DC.B    'CIELING'       ; 'CIELING2'\r
+*      DC.B    '2'|$80\r
+*      DC.L    FLOOR2-7-NATWID\r
+** CIEL2       DC.L    *+NATWID\r
+* CIEL2        BCLR    #0,NATWID-1(PSP)\r
+*      BEQ.S   CIEL2X\r
+*      ADDQ.L  #2,(PSP)\r
+* CIEL2X       RTS\r
+*\r
+* ######>> screen 26 <<\r
+* ======>>  23  <<\r
+* ( anything --- anything adr )\r
+* Fetch the parameter stack pointer (before it is pushed).\r
+* This points at whatever was on the top of stack before.\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'SP'    ; 'SP@'\r
+       DC.B    '@'|$80\r
+       DC.L    ALGNB-11-NATWID\r
+*SPAT  DC.L    *+NATWID\r
+SPAT   MOVE.L  PSP,-(PSP)\r
+       RTS\r
+*\r
+* ======>>  24  <<\r
+* ( whatever --- nothing )\r
+* Initialize the parameter stack pointer from the USER variable S0. \r
+* Effectively clears the stack.\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'SP'    ; 'SP!'\r
+       DC.B    $A1\r
+       DC.L    SPAT-4-NATWID\r
+*SPSTOR        DC.L    *+NATWID\r
+SPSTOR MOVE.L  XSPZER-UORIG(UP),PSP\r
+       RTS\r
+*\r
+       PAGE\r
+*\r
+* ======>>  25  <<\r
+* ( whatever *** nothing )\r
+* Initialize the return stack pointer from the initialization table\r
+* instead of the user variable R0, for some reason.\r
+* Quite possibly, this should be from R0.\r
+* Effectively aborts all in-process definitions, except the active one. \r
+* An emergency measure, to be sure.\r
+* The routine that calls this must never execute a return.\r
+* So this should never be executed from the terminal, I guess.\r
+* This is another that should be compile-time only, and in a separate vocabulary.\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'RP'    ; 'RP!'\r
+       DC.B    '!'|$80\r
+       DC.L    SPSTOR-4-NATWID\r
+*RPSTOR        DC.L    *+NATWID\r
+RPSTOR MOVE.L  RINIT(PC),RP\r
+       BRA.W   NEXT    ; This is correct here, but what will we do when NEXT goes away?\r
+*\r
+* ======>>  26  <<\r
+* ( ip *** )\r
+* Pop IP from return stack (return from high-level definition).\r
+* Can be used in a screen to force interpretion to terminate.\r
+* Must not be executed when temporaries are saved on top of the return stack.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    ';'     ; ';S'\r
+       DC.B    'S'|$80\r
+       DC.L    RPSTOR-4-NATWID\r
+*SEMIS DC.L    *+NATWID\r
+SEMIS  MOVEM.L (RP)+,A0/IP     ; A0 will be TOS\r
+       JMP     (A0)    ; return to NEXT\r
+*                      ; SEMIS will almost disappear when NEXT goes away.\r
+*      MOVE.L  (RP)+,A0\r
+*      MOVE.L  (RP)+,IP\r
+*      JMP     (A0)\r
+*\r
+* ######>> screen 27 <<\r
+* ======>>  27  <<\r
+* ( limit index *** index index )\r
+* Force the terminating condition for the innermost loop by\r
+* copying its index to its limit. \r
+* Termination is postponed until the next\r
+* LOOP or +LOOP instruction is executed. \r
+* The index remains available for use until\r
+* the LOOP or +LOOP instruction is encountered.\r
+* Note that the assumption is that the current count is the correct count \r
+* to end at, rather than pushing the count to the final count.\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    'LEAV'  ; 'LEAVE'\r
+       DC.B    'E'|$80\r
+       DC.L    SEMIS-3-NATWID\r
+*LEAVE DC.L    *+NATWID\r
+LEAVE  MOVE.L  LUPCT(RP),LUPLIM(RP)    ; Return address hidden in offset EQUs.\r
+       RTS\r
+*\r
+* Notes for loop counter and limit in registers:\r
+*      MOVE.L  LUPCT,LUPLIM    ; No return address to dodge.\r
+*      RTS\r
+*\r
+* ======>>  28  <<\r
+* ( n --- )              \r
+* ( *** n ) \r
+* Move top of parameter stack to top of return stack.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    '>'     ; '>R'\r
+       DC.B    'R'|$80\r
+       DC.L    LEAVE-6-NATWID\r
+*TOR   DC.L    *+NATWID\r
+TOR    MOVE.L  (RP),A0\r
+       MOVE.L  (PSP)+,(RP)\r
+       JMP     (A0)\r
+*\r
+* ======>>  29  <<\r
+* ( --- n )              \r
+* ( n *** )  \r
+* Move top of return stack to top of parameter stack.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    'R'     ; 'R>'\r
+       DC.B    '>'|$80\r
+       DC.L    TOR-3-NATWID\r
+*FROMR DC.L    *+NATWID\r
+*      MOVEM.L (RP)+,A0/A1     ; A0 will be TOS\r
+*      MOVE.L  A1,-(PSP)\r
+*      JMP     (A0)\r
+FROMR  MOVE.L  (RP)+,A0\r
+       MOVE.L  (RP)+,-(PSP)\r
+       JMP     (A0)\r
+*\r
+* ======>>  30  <<\r
+* ( --- n )             \r
+* ( n *** n )\r
+* Copy the top of return stack to top of parameter stack. \r
+* This would NOT be a synonym for I if we were keeping the control variables in registers.\r
+       EVEN\r
+       DC.B    $81     ; R\r
+       DC.B    'R'|$80\r
+       DC.L    FROMR-3-NATWID\r
+*R     DC.L    I+NATWID        ; Can't do as synonym any more.\r
+R      MOVE.L  NATWID(RP),-(PSP)       ; dodge return address\r
+       RTS\r
+*\r
+       PAGE\r
+*\r
+* ######>> screen 28 <<\r
+* ======>>  31  <<\r
+* ( n --- ~n )\r
+* Bit-invert top.\r
+* Not part of fig model.\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'NO'    ; 'NOT'\r
+       DC.B    'T'|$80\r
+       DC.L    R-2-NATWID\r
+*LNOT  DC.L    *+NATWID\r
+LNOT   NOT     (PSP)\r
+       RTS\r
+*\r
+* ( n --- n=0 )\r
+* Logically invert top of stack;\r
+* or flag true if top is zero, otherwise false.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    '0'     ; '0='\r
+       DC.B    '='|$80\r
+       DC.L    LNOT-4-NATWID\r
+*ZEQU  DC.L    *+NATWID\r
+ZEQU   CLR.L   D0\r
+       TST.L   (PSP)\r
+       SEQ     D0      ; faster than branch\r
+ZEQMSK AND.W   #1,D0\r
+       MOVE.L  D0,(PSP)\r
+       RTS\r
+*\r
+* Option using branch and increment:\r
+** ZEQU        DC.L    *+NATWID\r
+* ZEQU CLR.L   D0\r
+*      TST.L   (PSP)\r
+*      BEQ.S   ZEQUS\r
+*      MOVEQ   #1,D0   ; ADDQ.W would work. ADDQ.L takes 8 cycles instead of 4.\r
+* ZEQUS        MOVE.L  D0,(PSP)\r
+*      RTS\r
+*\r
+* If TRUE were -1:\r
+** ZEQU        DC.L    *+NATWID\r
+* ZEQU TST.L   (PSP)\r
+*      SEQ     D0\r
+*      EXT.B   D0\r
+*      EXT.W   D0\r
+*      MOVE.L  D0,(PSP)\r
+*      RTS\r
+*\r
+* ======>>  32  <<\r
+* ( n --- n<0 )\r
+* Flag true if top is negative (MSbit set), otherwise false.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    '0'     ; '0<'\r
+       DC.B    '<'|$80\r
+       DC.L    ZEQU-3-NATWID\r
+*ZLESS DC.L    *+NATWID\r
+ZLESS  CLR.L   D0\r
+       TST.L   (PSP)\r
+       SMI     D0\r
+       BRA.S   ZEQMSK  ; trade a few cycles for several bytes\r
+*\r
+* ######>> screen 29 <<\r
+* ======>>  33  <<\r
+* ( n1 n2 --- n1+n2 )\r
+* Add top two words.\r
+       EVEN\r
+       DC.B    $81     ; '+'\r
+       DC.B    '+'|$80\r
+       DC.L    ZLESS-3-NATWID\r
+*PLUS  DC.L    *+NATWID\r
+PLUS   MOVE.L  (PSP)+,D0       ; Addition is commutative.\r
+       ADD.L   D0,(PSP)        ; This order will not work for subtraction.\r
+       RTS             ; Remember, my son --\r
+*                              ; the left hand operator is one deeper in the stack,\r
+*                              ; and it is the target.\r
+*\r
+* ======>>  34  <<\r
+* ( d1 d2 --- d1+d2 )\r
+* Add top two double integers.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    'D'     ; 'D+'\r
+       DC.B    '+'|$80\r
+       DC.L    PLUS-2-NATWID\r
+*DPLUS DC.L    *+NATWID\r
+DPLUS  MOVEM.L (PSP)+,D0/D1/D2/D3      ; ADDX memory requires too much setup\r
+       ADD.L   D1,D3                   ; This order will work for subtraction, too.\r
+       ADDX.L  D0,D2\r
+       MOVEM.L D2/D3,-(PSP)\r
+       RTS\r
+*\r
+* ======>>  35  <<\r
+* ( n --- -n )\r
+* Negate (two's complement) top of stack.\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    'MINU'  ; 'MINUS'\r
+       DC.B    'S'|$80\r
+       DC.L    DPLUS-3-NATWID\r
+*MINUS DC.L    *+NATWID\r
+MINUS  NEG.L   (PSP)\r
+       RTS\r
+*\r
+* ======>>  36  <<\r
+* ( d --- -d )\r
+* Negate (two's complement) top two words on stack as a double integer.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $86\r
+       DC.B    'DMINU' ; 'DMINUS'\r
+       DC.B    'S'|$80\r
+       DC.L    MINUS-6-NATWID\r
+*DMINUS        DC.L    *+NATWID\r
+DMINUS NEG.L   NATWID(PSP)\r
+       NEGX.L  (PSP)\r
+       RTS\r
+*\r
+* ######>> screen 30 <<\r
+* ======>>  37  <<\r
+* ( n1 n2 --- n1 n2 n1 )\r
+* Push a copy of the second word on stack.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $84\r
+       DC.B    'OVE'   ; 'OVER'\r
+       DC.B    'R'|$80\r
+       DC.L    DMINUS-7-NATWID\r
+*OVER  DC.L    *+NATWID\r
+OVER   MOVE.L  NATWID(PSP),-(PSP)\r
+       RTS\r
+*\r
+* ======>>  38  <<\r
+* ( n --- )\r
+* Discard the top word on stack.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $84\r
+       DC.B    'DRO'   ; 'DROP'\r
+       DC.B    'P'|$80\r
+       DC.L    OVER-5-NATWID\r
+*DROP  DC.L    *+NATWID\r
+DROP   LEA     NATWID(PSP),PSP\r
+       RTS\r
+*\r
+* ======>>  39  <<\r
+* ( n1 n2 --- n2 n1 )\r
+* Swap the top two words on stack.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $84\r
+       DC.B    'SWA'   ; 'SWAP'\r
+       DC.B    'P'|$80\r
+       DC.L    DROP-5-NATWID\r
+*SWAP  DC.L    *+NATWID\r
+SWAP   MOVEM.L (PSP),D0/D1\r
+       EXG     D0,D1\r
+       MOVEM.L D0/D1,(PSP)\r
+       RTS\r
+*      MOVE.L  (PSP),D0\r
+*      MOVE.L  NATWID(PSP),(PSP)\r
+*      MOVE.L  D0,NATWID(POS)\r
+*      RTS\r
+*\r
+* ======>>  40  <<\r
+* ( n1 --- n1 n1 )\r
+* Push a copy of the top word on stack.\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'DU'    ; 'DUP'\r
+       DC.B    'P'|$80\r
+       DC.L    SWAP-5-NATWID\r
+*DUP   DC.L    *+NATWID\r
+DUP    MOVE.L  (PSP),-(PSP)\r
+       RTS\r
+*\r
+* ######>> screen 31 <<\r
+* ======>>  41  <<\r
+* ( n adr --- )\r
+* Add the second word on stack to the word at the adr on top of stack.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    '+'     ; '+!'\r
+       DC.B    '!'|$80\r
+       DC.L    DUP-4-NATWID\r
+*PSTORE        DC.L    *+NATWID\r
+PSTORE MOVEM.L (PSP)+,D0/A0\r
+       EXG     D0,A0\r
+       ADD.L   D0,(A0)\r
+       RTS\r
+*\r
+* ======>>  42  <<\r
+* ( adr b --- )\r
+* Exclusive or byte at adr with low byte of top word.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $86\r
+       DC.B    'TOGGL' ; 'TOGGLE'\r
+       DC.B    'E'|$80\r
+       DC.L    PSTORE-3-NATWID\r
+*TOGGLE        DC.L    *+NATWID\r
+TOGGLE MOVEM.L (PSP)+,D0/A0\r
+       EOR.B   D0,(A0)\r
+       RTS\r
+* Using the model code would be less likely to introduce bugs, \r
+* but that would sort-of defeat my purposes here.\r
+* Anyway, I can imitate known good bif-6809 code\r
+* and it's fewer bytes and much faster code this way.\r
+* TOGGLE\r
+*      DC.L    DOCOL,OVER,CAT,XOR,SWAP,CSTORE\r
+*      DC.L    SEMIS\r
+*\r
+* ######>> screen 32 <<\r
+* ======>>  43  <<\r
+* ( adr --- n )\r
+* Replace address on stack with the word at the address.\r
+       EVEN\r
+       DC.B    $81     ; @\r
+       DC.B    '@'|$80\r
+       DC.L    TOGGLE-7-NATWID\r
+*AT    DC.L    *+NATWID\r
+AT     MOVE.L  (PSP),A0\r
+       MOVE.L  (A0),(PSP)\r
+       RTS\r
+*\r
+* ======>>  44  <<\r
+* ( adr --- b )\r
+* Replace address on top of stack with the byte at the address.\r
+* High byte of result is clear.\r
+* Unfortunate naming. 8 bits doth not a character code point make.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    'C'     ; 'C@'\r
+       DC.B    '@'|$80\r
+       DC.L    AT-2-NATWID\r
+**CAT  DC.L    *+NATWID\r
+*CAT   MOVE.L  (PSP),A0        ; Memory indirect is 68020 and after, but not CPU32.\r
+*      CLR.L   D0              ; Reduce bus activity and un-aligned access.\r
+*      MOVE.B  (A0),D0\r
+*      MOVE.L  D0,(PSP)\r
+*      RTS\r
+CAT    MOVE.L  (PSP),A0\r
+       CLR.L   (PSP)\r
+       MOVE.B  (A0),NATWID-1(PSP)\r
+       RTS\r
+* But optimization is not my primary purpose here, \r
+* so I'm not going to count bytes and cycles and compare.\r
+*\r
+* ( adr --- h )\r
+* Yeah, we're gonna need this.\r
+* Replace address on top of stack with the 16-bit half-word at the address.\r
+* High half-word of result is clear.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    'H'     ; 'H@'\r
+       DC.B    '@'|$80\r
+       DC.L    CAT-3-NATWID\r
+**HAT  DC.L    *+NATWID\r
+*HAT   MOVE.L  (PSP),A0        ; Memory indirect is 68020 and after, but not CPU32.\r
+*      CLR.L   D0              ; Reduce bus activity.\r
+*      MOVE.W  (A0),D0\r
+*      MOVE.L  D0,(PSP)\r
+*      RTS\r
+HAT    MOVE.L  (PSP),A0\r
+       CLR.L   (PSP)\r
+       MOVE.W  (A0),NATWID/2(PSP)\r
+       RTS\r
+*\r
+* ======>>  45  <<\r
+* ( n adr --- )\r
+* Store second word on stack at address on top of stack.\r
+       EVEN\r
+       DC.B    $81     ; !\r
+       DC.B    '!'|$80\r
+       DC.L    HAT-3-NATWID\r
+**STORE        DC.L    *+NATWID\r
+*STORE MOVEM.L (PSP)+,D0/A0\r
+*      EXG     D0,A0\r
+*      MOVE.L  D0,(A0)\r
+*      RTS\r
+STORE  MOVE.L  (PSP)+,A0\r
+       MOVE.L  (PSP)+,(A0)\r
+       RTS\r
+*\r
+* ======>>  46  <<\r
+* ( b adr --- )\r
+* Store low byte of second word on stack at address on top of stack. \r
+* High byte is ignored.\r
+* Unfortunate naming. 8 bits doth not a character code point make.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    'C'     ; 'C!'\r
+       DC.B    '!'|$80\r
+       DC.L    STORE-2-NATWID\r
+**CSTORE       DC.L    *+NATWID\r
+*CSTORE        MOVEM.L (PSP)+,D0/A0\r
+*      EXG     D0,A0\r
+*      MOVE.B  D0,(A0)\r
+*      RTS\r
+CSTORE MOVE.L  (PSP)+,A0\r
+       MOVE.L  (PSP)+,D0\r
+       MOVE.B  D0,(A0)\r
+       RTS\r
+*\r
+* ( b adr --- )\r
+* Yeah, we're gonna need this.\r
+* Store low 16-bit half-word of second word on stack at address on top of stack. \r
+* High half-word is ignored.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    'H'     ; 'H!'\r
+       DC.B    '!'|$80\r
+       DC.L    CSTORE-3-NATWID\r
+**HSTORE       DC.L    *+NATWID\r
+*HSTORE        MOVEM.L (PSP)+,D0/A0\r
+*      EXG     D0,A0\r
+*      MOVE.W  D0,(A0)\r
+*      RTS\r
+HSTORE MOVE.L  (PSP)+,A0\r
+       MOVE.L  (PSP)+,D0\r
+       MOVE.B  D0,(A0)\r
+       RTS\r
+*\r
+       PAGE\r
+*\r
+* ######>> screen 33 <<\r
+* ======>>  47  <<\r
+* ( --- )                                                 P\r
+* { : name sundry-activities ; } typical input\r
+* ( Termination of recursive definition, or eating our own dogfood --\r
+*   lots of forward references here.)\r
+* If executing (not compiling), \r
+* record the data stack mark in CSP,\r
+* Set the CONTEXT vocabulary to CURRENT,\r
+* CREATE a header,\r
+* set state to compile,\r
+* and compile the call to the trailing native CPU machine code DOCOL.\r
+*\r
+* This would not be hard to flatten to native code,\r
+* especially in the 6809 or 68000.\r
+* But that's not the purpose of a model.\r
+*\r
+       EVEN\r
+       DC.B    $C1     ; : immediate\r
+       DC.B    ':'|$80\r
+       DC.L    HSTORE-3-NATWID\r
+*COLON DC.L    DOCOL\r
+COLON  BSR.S   DOCOL\r
+       DC.L    QEXEC,SCSP,CURENT,AT,CONTXT,STORE\r
+       DC.L    CREATE,RBRAK\r
+       DC.L    PSCODE\r
+*COLON BSR.W   QEXEC\r
+*      BSR.W   SCSP\r
+*      MOVE.L  XCURR-UORIG(UP),XCONT-UORIG(UP)\r
+*      BSR.W   CREATE\r
+*      BSR.W   RBRAK\r
+*      BSR.W   PSCODE\r
+\r
+* Here is the IP pusher for allowing\r
+* nested words in the virtual machine:\r
+* ( ;S is the equivalent un-nester )\r
+\r
+* ( *** oldIP ) \r
+* Characteristic of a colon (:) definition.  \r
+* Begins execution of a high-level definition,\r
+* i. e., nests the definition and begins processing icodes. \r
+* Mechanically, it pushes the IP \r
+* and loads the Parameter Field Address of the definition which\r
+* called it into the IP.\r
+*DOCOL MOVE.L  (RP),A0\r
+*      MOVE.L  IP,(RP)\r
+*      MOVE.L  W,IP\r
+*      JMP     (A0)    ; Return to NEXT.\r
+DOCOL  MOVEM.L (RP)+,A0/A1     ; new i-code list address and return to NEXT\r
+       MOVE.L  IP,-(RP)        ; nest IP\r
+       MOVE.L  A0,IP           ; address of list saved by call here\r
+       JMP     (A1)    ; Return to caller, usually or often NEXT.\r
+*\r
+* ======>>  48  <<\r
+* ( --- )                                                 P\r
+* { : name sundry-activities ; } typical input\r
+* ERROR check data stack against mark in CSP,\r
+* compile ;S,\r
+* unSMUDGE LATEST definition,\r
+* and set state to interpretation.\r
+       EVEN\r
+       DC.B    $C1     ; ;   imnediate code\r
+       DC.B    ';'|$80\r
+       DC.L    COLON-2-NATWID\r
+*SEMI  DC.L    DOCOL\r
+SEMI   BSR.S   DOCOL\r
+       DC.L    QCSP,COMPIL,SEMIS,SMUDGE,LBRAK\r
+       DC.L    SEMIS\r
+*\r
+* ######>> screen 34 <<\r
+* ======>>  49  <<\r
+* ( n --- )\r
+* { value CONSTANT name } typical input\r
+* CREATE a header,\r
+* unSMUDGE it,\r
+* compile the constant value,\r
+* and compile the call to the trailing native CPU machine code DOCON.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $88\r
+       DC.B    'CONSTAN'       ; 'CONSTANT'\r
+       DC.B    'T'|$80\r
+       DC.L    SEMI-2-NATWID\r
+*CON   DC.L    DOCOL\r
+CON    BSR.S   DOCOL\r
+       DC.L    CREATE,SMUDGE,COMMA,PSCODE\r
+* ( --- n ) \r
+* Characteristic of a CONSTANT. \r
+* A CONSTANT simply loads its value from its parameter field\r
+* and pushes it on the stack.\r
+DOCON  MOVE.L  (RP)+,A0        ; Get fake return address pushed by call here.\r
+       MOVE.L  (A0),-(PSP)     ; Push the first natural width word of the parameter field.\r
+       RTS                     ; Return to caller, usually or often NExT\r
+*\r
+* Tempting to do a space-saving DOHCON:\r
+* DOHCON       MOVE.L  (RP)+,A0        ; Get fake return address pushed by call here.\r
+*      MOVE.W  (A0),-(PSP)     ; Push the first half-width word of the parameter field.\r
+*      MOVEQ.W #0,-(PSP)       ; zero extend the half-width value on stack\r
+*      RTS                     ; Return to caller, usually or often NExT\r
+* But, as you can see, it'll be a bit slower,\r
+* and it just may not be worth it for the number of times it would be used.\r
+* And there's a bettwer way lurking around the corner.\r
+*\r
+* ======>>  50  <<\r
+* ( init --- )\r
+* { init VARIABLE name } typical input\r
+* Use CONSTANT to CREATE a header and compile the initial value, init, \r
+* then overwrite the characteristic to point to DOVAR.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $88\r
+       DC.B    'VARIABL'       ; 'VARIABLE'\r
+       DC.B    'E'|$80\r
+       DC.L    CON-9-NATWID\r
+*VAR   DC.L    DOCOL\r
+VAR    BSR.S   DOCOL\r
+       DC.L    CON,PSCODE\r
+* ( --- vadr ) \r
+* Characteristic of a VARIABLE. \r
+* A VARIABLE pushes its PFA address on the stack. \r
+* The parameter field of a VARIABLE is the actual allocation of the variable,\r
+* so that pushing its address allows its contents to be @ed (fetched). \r
+* Ordinary arrays and strings that do not subscript themselves\r
+* may be allocated by defining a variable\r
+* and immediately ALLOTting the remaining needed space.\r
+* VARIABLES are global to all users,\r
+* and thus should be hidden in resource monitors, but aren't.\r
+DOVAR  MOVE.L  (RP)+,-(PSP)    ; Get and push fake return address pushed by call here, \r
+       RTS                     ; as address of first natural width word of the parameters.\r
+*\r
+* ======>>  51  <<\r
+* ( ub --- )\r
+* { uboffset USER name } typical input\r
+* CREATE a header and compile the unsigned byte offset in the per-USER table, \r
+* then overwrite the header with a call to DOUSER.\r
+* The USER is entirely responsible for maintaining allocation!\r
+* (We really need a word that controls allocation of these.)\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $84\r
+       DC.B    'USE'   ; 'USER'\r
+       DC.B    'R'|$80\r
+       DC.L    VAR-9-NATWID\r
+*USER  DC.L    DOCOL\r
+USER   BSR.S   DOCOL\r
+       DC.L    CON,PSCODE\r
+* ( --- vadr ) \r
+* Characteristic of a per-USER variable. \r
+* USER variables are similiar to VARIABLEs,\r
+* but are allocated (by hand!) in the per-user table. \r
+* A USER variable's parameter field contains its offset in the per-user table.\r
+DOUSER MOVE.L  (RP)+,A0        ; Get fake return address pushed by call here.\r
+       MOVE.L  (A0),D0         ; Offset into the table.\r
+       LEA     (UP,D0.L),A0\r
+       MOVE.L  A0,-(PSP)\r
+       RTS\r
+* Hey, the per-user table can actually be larger than 256 bytes!\r
+*\r
+       PAGE\r
+*\r
+* ######>> screen 35 <<\r
+*\r
+* Some (theoretically) useful constants:\r
+* ======>>  52  <<\r
+* ( --- 0 )\r
+       EVEN\r
+       DC.B    $81     ; 0\r
+       DC.B    '0'|$80\r
+       DC.L    USER-5-NATWID\r
+*ZERO  DC.L    DOCON\r
+ZERO   BSR.S   DOCON\r
+       DC.L    0000\r
+*\r
+* ======>>  53  <<\r
+* ( --- 1 )\r
+       EVEN\r
+       DC.B    $81     ; 1\r
+       DC.B    '1'|$80\r
+       DC.L    ZERO-2-NATWID\r
+*ONE   BSR.S   DOCON\r
+ONE    DC.L    DOCON\r
+ONEV   DC.L    1\r
+*\r
+* ======>>  54  <<\r
+* ( --- 2 )\r
+       EVEN\r
+       DC.B    $81     ; 2\r
+       DC.B    '2'|$80\r
+       DC.L    ONE-2-NATWID\r
+*TWO   DC.L    DOCON\r
+TWO    BSR.S   DOCON\r
+TWOV   DC.L    2\r
+*\r
+* ======>>  55  <<\r
+* ( --- 3 )\r
+       EVEN\r
+       DC.B    $81     ; 3\r
+       DC.B    '3'|$80\r
+       DC.L    TWO-2-NATWID\r
+*THREE DC.L    DOCON\r
+THREE  BSR.W   DOCON\r
+       DC.L    3\r
+*\r
+*mOVE NATWC into BSR.S range, in front of THREE? Maybe not.\r
+* Useful constant, not in model, needed for abstraction:\r
+* The standard name is CELL, however.\r
+* ( --- NATWID )\r
+* The byte width of objects on stack.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $86\r
+       DC.B    'NATWI' ; 'NATWID'\r
+       DC.B    'D'|$80\r
+       DC.L    THREE-2-NATWID\r
+*NATWC DC.L    DOCON\r
+NATWC  BSR.W   DOCON\r
+NATWCV DC.L    NATWID\r
+*\r
+* Not in model, wanted for abstraction:\r
+* Note that this is not defined as an instance of an INCREMENTER here!\r
+* Coded to increment by the exact constant returned by NATWID\r
+* ( n --- n+NATWID )\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $84\r
+       DC.B    'NAT'   ; 'NAT+'\r
+       DC.B    '+'|$80\r
+       DC.L    NATWC-7-NATWID\r
+*NATP  DC.L    *+NATWID\r
+NATP   MOVE.L  (PSP),D0\r
+       ADD.L   NATWCV(PC),D0   ; late binding?\r
+       MOVE.L  D0,(PSP)\r
+       RTS\r
+*\r
+* Useful constant, not in model, needed for abstraction:\r
+* ( --- NATWID/2 )\r
+* Half the byte width of objects on stack.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $8A\r
+       DC.B    'HALFNATWI'     ; 'HALFNATWID'\r
+       DC.B    'D'|$80\r
+       DC.L    NATP-5-NATWID\r
+*HNATWC        DC.L    DOCON\r
+HNATWC BSR.W   DOCON\r
+HNATWCV        DC.L    NATWID/2\r
+*\r
+       PAGE\r
+*\r
+* ======>>  56  <<\r
+* ( --- SP ) \r
+* ASCII SPACE character\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    'B'     ; 'BL'\r
+       DC.B    'L'|$80\r
+       DC.L    HNATWC-11-NATWID\r
+*BL    DC.L    DOCON   ; ascii blank\r
+BL     BSR.W   DOCON   ; ascii blank\r
+       DC.L    $20\r
+*\r
+* ======>>  57  <<\r
+* This really shouldn't be a CONSTANT.\r
+* ( --- adr )    \r
+* The base of the disk buffer space.\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    'FIRS'  ; 'FIRST'\r
+       DC.B    'T'|$80\r
+       DC.L    BL-3-NATWID\r
+*FIRST DC.L    DOCON\r
+FIRST  BSR.W   DOCON\r
+       DC.L    BUFBAS\r
+*      FDB     MEMEND-528      ; (132 * NBLK)\r
+*\r
+* ======>>  58  <<\r
+* This really shouldn't be a CONSTANT.\r
+* ( --- adr ) \r
+* The limit of the disk buffer space.\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    'LIMI'  ; 'LIMIT' :     ( the end of memory +1 )\r
+       DC.B    'T'|$80\r
+       DC.L    FIRST-6-NATWID\r
+*LIMIT DC.L    DOCON\r
+LIMIT  BSR.W   DOCON\r
+       DC.L    BUFBAS+BUFSZ\r
+* In 6800 model, was\r
+*      FDB     MEMEND\r
+*\r
+* ======>>  59  <<\r
+* ( --- sectorsize )\r
+* The size, in bytes, of a buffer control region.\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    'B/CT'  ; 'B/CTL' :     (bytes/control region)\r
+       DC.B    'L'|$80\r
+       DC.L    LIMIT-6-NATWID\r
+*BCTL  DC.L    DOCON\r
+BCTL   BSR.W   DOCON\r
+       DC.L    SECTRL\r
+*\r
+* ( --- sectorsize )\r
+* The size, in bytes, of a buffer.\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    'B/BU'  ; 'B/BUF' :     (bytes/buffer)\r
+       DC.B    'F'|$80\r
+       DC.L    BCTL-6-NATWID\r
+*BBUF  DC.L    DOCON\r
+BBUF   BSR.W   DOCON\r
+       DC.L    SECTSZ\r
+* Hardcoded in 6800 model:\r
+*      FDB     128\r
+*\r
+* ======>>  60  <<\r
+* ( --- blocksperscreen )      \r
+* The size, in blocks, of a screen.\r
+* Should this be the same as NBLK, the number of block buffers maintained?\r
+* Only if you want to have a full screen in buffers at a time,\r
+* which might induce some bugs -- erk.\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    'B/SC'  ; 'B/SCR' :     (blocks/screen)\r
+       DC.B    'R'|$80\r
+       DC.L    BBUF-6-NATWID\r
+*BSCR  DC.L    DOCON\r
+BSCR   DBSR.W  DOCON\r
+       DC.L    SCRSZ/SECTSZ\r
+* Hardcoded in 6800 model as:\r
+*      FDB     8\r
+*      blocks/screen = 1024 / "B/BUF" = 8, if sectors are 128 bytes.\r
+*\r
+* ======>>  61  <<\r
+* ( n --- adr )\r
+* Calculate the address of entry (#n/NATWID) in the boot-up parameter table. \r
+* (Adds the base of the boot-up table to n.)\r
+       EVEN\r
+       DC.B    $87\r
+       DC.B    '+ORIGI'        ; '+ORIGIN'\r
+       DC.B    'N'|$80\r
+       DC.L    BSCR-6-NATWID\r
+*PORIG DC.L    DOCOL\r
+PORIG  BSR.W   DOCOL\r
+       DC.L    LIT,ORIG,PLUS\r
+       DC.L    SEMIS\r
+*\r
+* ######>> screen 36 <<\r
+* ======>>  62  <<\r
+* ( n --- adr )\r
+* This is the per-task variable recording the initial parameter stack pointer.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    'S'     ; 'S0'\r
+       DC.B    '0'|$80\r
+       DC.L    PORIG-8-NATWID\r
+*SZERO DC.L    DOUSER\r
+SZERO  BSR.W   DOUSER\r
+       DC.L    XSPZER-UORIG\r
+*\r
+* ======>>  63  <<\r
+* ( n --- adr )\r
+* This is the per-task variable recording the initial return stack pointer.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    'R'     ; 'R0'\r
+       DC.B    '0'|$80\r
+       DC.L    SZERO-3-NATWID\r
+*RZERO DC.L    DOUSER\r
+RZERO  BSR.W   DOUSER\r
+       DC.L    XRZERO-UORIG\r
+*\r
+* ======>>  64  <<\r
+* ( --- vadr )   \r
+* Terminal Input Buffer address. \r
+* Note that this is a variable, so users may allocate their own buffers, but it must be @ed.\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'TI'    ; 'TIB'\r
+       DC.B    'B'|$80\r
+       DC.L    RZERO-3-NATWID\r
+*TIB   DC.L    DOUSER\r
+TIB    BSR.W   DOUSER\r
+       DC.L    XTIB-UORIG\r
+*\r
+* ======>>  65  <<\r
+* ( --- maxnamewidth )\r
+* This is the maximum width to which symbol names will be recorded.\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    'WIDT'  ; 'WIDTH'\r
+       DC.B    'H'|$80\r
+       DC.L    TIB-4-NATWID\r
+*WIDTH DC.L    DOUSER\r
+WIDTH  BSR.W   DOUSER\r
+       DC.L    XWIDTH-UORIG\r
+*\r
+* ======>>  66  <<\r
+* ( --- vadr )   \r
+* Availability of error messages on disk.\r
+* Contains 1 if messages available, \r
+* 0 if not,\r
+* -1 if a disk error has occurred.\r
+       EVEN\r
+       DC.B    $87\r
+       DC.B    'WARNIN'        ; 'WARNING'\r
+       DC.B    'G'|$80\r
+       DC.L    WIDTH-6-NATWID\r
+*WARN  DC.L    DOUSER\r
+WARN   BSR.W   DOUSER\r
+       DC.L    XWARN-UORIG\r
+*\r
+* ======>>  67  <<\r
+* ( --- vadr )   \r
+* Boundary for FORGET.\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    'FENC'  ; 'FENCE'\r
+       DC.B    'E'|$80\r
+       DC.L    WARN-8-NATWID\r
+*FENCE DC.L    DOUSER\r
+FENCE  BSR.W   DOUSER\r
+       DC.L    XFENCE-UORIG\r
+*\r
+* ======>>  68  <<\r
+* ( --- vadr )   \r
+* Dictionary pointer, fetched by HERE.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    'D'     ; 'DP' :        points to first free byte at end of dictionary\r
+       DC.B    'P'|$80\r
+       DC.L    FENCE-6-NATWID\r
+*DICTPT        DC.L    DOUSER\r
+DICTPT BSR.W   DOUSER\r
+       DC.L    XDICTP-UORIG\r
+*\r
+* ======>>  68.5  <<\r
+* ( --- vadr ) ******* Need to check what this is!\r
+* Used in maintaining vocabularies.\r
+* I think it points to the current "parent" vocabulary, but I'm not sure.\r
+* Or maybe this is the CONTEXT vocabulary. I'll have to come back here. *****\r
+* According to the fig glossary, it is the pointer to the link field (parent link?)\r
+* of the most recently created vocabulary.\r
+* The glossary indicates that FORGET would use this to \r
+* "allow control for FORGETting thru multiple vocabularys",\r
+* which I am now guessing does not mean what I at one time thought it should mean.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $88\r
+       DC.B    'VOC-LIN'       ; 'VOC-LINK'\r
+       DC.B    'N'|$80\r
+       DC.L    DICTPT-3-NATWID\r
+*VOCLIN        DC.L    DOUSER\r
+VOCLIN BSR.W   DOUSER\r
+       DC.L    XVOCL-UORIG\r
+*\r
+* ======>>  69  <<\r
+* ( --- vadr )   \r
+* Disk block being interpreted. \r
+* Zero refers to terminal.\r
+* ******** Should be made a 64 bit user variable! ********\r
+* But the base system needs to have full 64 bit support, div and mul, etc.\r
+* before we can do that.\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'BL'    ; 'BLK'\r
+       DC.B    'K'|$80\r
+       DC.L    VOCLIN-9-NATWID\r
+*BLK   DC.L    DOUSER\r
+BLK    BSR.W   DOUSER\r
+       DC.L    XBLK-UORIG\r
+*\r
+* ======>>  70  <<\r
+* ( --- vadr )   \r
+* Input buffer offset/cursor.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    'I'     ; 'IN' :        scan pointer for input line buffer\r
+       DC.B    'N'|$80\r
+       DC.L    BLK-4-NATWID\r
+*IN    DC.L    DOUSER\r
+IN     BSR.W   DOUSER\r
+       DC.L    XIN-UORIG\r
+*\r
+* ======>>  71  <<\r
+* ( --- vadr )   \r
+* Output buffer offset/cursor.\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'OU'    ; 'OUT'\r
+       DC.B    'T'|$80\r
+       DC.L    IN-3-NATWID\r
+*OUT   DC.L    DOUSER\r
+OUT    BSR.W   DOUSER\r
+       DC.L    XOUT-UORIG\r
+*\r
+* ======>>  72  <<\r
+* ( --- vadr )   \r
+* Screen currently being edited, once we have an editor running. \r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'SC'    ; 'SCR'\r
+       DC.B    'R'|$80\r
+       DC.L    OUT-4-NATWID\r
+*SCR   DC.L    DOUSER\r
+SCR    BSR.W   DOUSER\r
+       DC.L    XSCR-UORIG\r
+* ######>> screen 37 <<\r
+*\r
+* ======>>  73  <<\r
+* ( --- vadr )   \r
+* Sector offset for LOADing screens,\r
+* set by DRIVE to make a new drive the default.\r
+* This should also be 64 bit, if we had full 64-bit math.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $86\r
+       DC.B    'OFFSE' ; 'OFFSET'\r
+       DC.B    'T'|$80\r
+       DC.L    SCR-4-NATWID\r
+*OFSET DC.L    DOUSER\r
+OFSET  BSR.W   DOUSER\r
+       DC.L    XOFSET-UORIG\r
+*\r
+* ======>>  74  <<\r
+* ( --- vadr )   \r
+* Current context of interpretation (vocabulary root).\r
+       EVEN\r
+       DC.B    $87\r
+       DC.B    'CONTEX'        ; 'CONTEXT' :   points to pointer to vocab to search first\r
+       DC.B    'T'|$80\r
+       DC.L    OFSET-7-NATWID\r
+*CONTXT        DC.L    DOUSER\r
+CONTXT BSR.W   DOUSER\r
+       DC.L    XCONT-UORIG\r
+*\r
+* ======>>  75  <<\r
+* ( --- vadr )   \r
+* Current context of definition (vocabulary root).\r
+       EVEN\r
+       DC.B    $87\r
+       DC.B    'CURREN'        ; 'CURRENT' :   points to ptr. to vocab being extended\r
+       DC.B    'T'|$80\r
+       DC.L    CONTXT-8-NATWID\r
+*CURENT        DC.L    DOUSER\r
+CURENT BSR.W   DOUSER\r
+       DC.L    XCURR-UORIG\r
+*\r
+* ======>>  76  <<\r
+* ( --- vadr )   \r
+* Compiler/interpreter state.\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    'STAT'  ; 'STATE' :     1 if compiling, 0 if not\r
+       DC.B    'E'|$80\r
+       DC.L    CURENT-8-NATWID\r
+*STATE DC.L    DOUSER\r
+STATE  BSR.W   DOUSER\r
+       DC.L    XSTATE-UORIG\r
+*\r
+* ======>>  77  <<\r
+* ( --- vadr )   \r
+* Numeric conversion base.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $84\r
+       DC.B    'BAS'   ; 'BASE' :      number base for all input & output\r
+       DC.B    'E'|$80\r
+       DC.L    STATE-6-NATWID\r
+*BASE  DC.L    DOUSER\r
+BASE   BSR.W   DOUSER\r
+       DC.L    XBASE-UORIG\r
+*\r
+* ======>>  78  <<\r
+* ( --- vadr ) \r
+* Decimal point location for output.\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'DP'    ; 'DPL'\r
+       DC.B    'L'|$80\r
+       DC.L    BASE-5-NATWID\r
+*DPL   DC.L    DOUSER\r
+DPL    BSR.W   DOUSER\r
+       DC.L    XDPL-UORIG\r
+*\r
+* ======>>  79  <<\r
+* ( --- vadr )   \r
+* Field width for I/O formatting.\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'FL'    ; 'FLD'\r
+       DC.B    'D'|$80\r
+       DC.L    DPL-4-NATWID\r
+*FLD   DC.L    DOUSER\r
+FLD    BSR.W   DOUSER\r
+       DC.L    XFLD-UORIG\r
+*\r
+* ======>>  80  <<\r
+* ( --- vadr )   \r
+* Compiler stack mark for stack check.\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'CS'    ; 'CSP'\r
+       DC.B    'P'|$80\r
+       DC.L    FLD-4-NATWID\r
+*CSP   DC.L    DOUSER\r
+CSP    BSR.W   DOUSER\r
+       DC.L    XCSP-UORIG\r
+*\r
+* ======>>  81  <<\r
+* ( --- vadr )   \r
+* Editing cursor location. \r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    'R'     ; 'R#'\r
+       DC.B    '#'|$80\r
+       DC.L    CSP-4-NATWID\r
+*RNUM  DC.L    DOUSER\r
+RNUM   BSR.W   DOUSER\r
+       DC.L    XRNUM-UORIG\r
+*\r
+* ======>>  82  <<\r
+* ( --- vadr )   \r
+* Pointer to last HELD character in PAD.\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'HL'    ; 'HLD'\r
+       DC.B    'D'|$80\r
+       DC.L    RNUM-3-NATWID\r
+*HLD   DC.L    DOCON\r
+HLD    BSR.W   DOCON\r
+       DC.L    XHLD\r
+*\r
+* ======>>  82.5  <<== SPECIAL\r
+* ( --- vadr )   \r
+* Line width of active terminal.\r
+       EVEN\r
+       DC.B    $87\r
+       DC.B    'COLUMN'        ; 'COLUMNS' :   line width of terminal\r
+       DC.B    'S'|$80\r
+       DC.L    HLD-4-NATWID\r
+*COLUMS        DC.L    DOUSER\r
+COLUMS BSR.W   DOUSER\r
+       DC.L    XCOLUM-UORIG\r
+*\r
+       PAGE\r
+*\r
+* ######>> screen 38 <<\r
+**\r
+** An INCREMENTER probably should not be defined without a defined CONSTANT increment?\r
+** Ergo, defined in pairs --\r
+**\r
+** Make an INCREMENTER compiling word (not in model):\r
+** ( n --- )\r
+** { n INCREMENTER name } typical input\r
+** CREATE a header and compile the increment constant, \r
+** then overwrite the header with a call to DOINC.\r
+*      DC.B    $8B\r
+*      DC.B    'INCREMENTE'    ; 'INCREMENTER'\r
+*      DC.B    'R'|$80\r
+*      DC.L    COLUMS-8-NATWID\r
+* INCR BSR.W   DOCOL\r
+*      CON,PSCODE\r
+** ( n --- ninc ) \r
+** Characteristic of an INCREMENTER.\r
+** This is probably too naive:\r
+* DOINC        MOVE.L  (RP)+,A0\r
+*      MOVE.L  (A0),D0 ; Get the increment,\r
+*      ADD.L   D0,(PSP)        ; and add it.\r
+*      RTS\r
+* Compiling word should check that it is compiling a CONSTANT.\r
+* On the other hand, there are reasons not to do this:\r
+*\r
+* ======>>  83  <<\r
+* ( n --- n+1 )\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    '1'     ; '1+'\r
+       DC.B    '+'|$80\r
+       DC.L    COLUMS-8-NATWID\r
+* Using the model keeps things semantically connected for other processors:\r
+*ONEP  DC.L    DOCOL,ONE,PLUS\r
+ONEP   BSR.W   DOCOL   ; ... or I shall convince myself of such for now.\r
+       DC.L    ONE,PLUS\r
+       DC.L    SEMIS\r
+** Greedy alternative:\r
+* ONEPG        MOVE.L  (PSP),D0\r
+*      ADD.L   ONEV(PC),D0\r
+*      MOVE.L  D0,(PSP)\r
+*      RTS\r
+* Naive alternative:\r
+* ONEPI        BSR.W   DOINC\r
+*      DC.L    1\r
+* Naive alternative:\r
+* ONEP1        ADDQ.L  #1,(PSP) ; It's hard to imagine 1+ being other than 1.\r
+*      RTS\r
+*\r
+* ======>>  84  <<\r
+* ( n --- n+2 )\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    '2'     ; '2+'\r
+       DC.B    '+'|$80\r
+       DC.L    ONEP-3-NATWID\r
+* Using the model keeps things semantically connected for other processors:\r
+*TWOP  DC.L    DOCOL\r
+TWOP   BSR.W   DOCOL\r
+       DC.L    TWO,PLUS\r
+       DC.L    SEMIS\r
+** Greedy alternative:\r
+* TWOPG        MOVE.L  (PSP),D0\r
+*      ADD.L   TWOV(PC),D0\r
+*      MOVE.L  D0,(PSP)\r
+*      RTS\r
+* Naive alternative:\r
+* TWOPI        BSR.W   DOINC\r
+*      DC.L    2\r
+* Naive alternative:\r
+* TWOP2        ADDQ.L  #2,(PSP) ; It's hard to imagine 2+ being other than 2.\r
+*      RTS\r
+*\r
+* ======>>  85  <<\r
+* ( --- adr )\r
+* Get the DICTPT allocation, like a USER constant.  \r
+* Should check the stack and heap for collision.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $84\r
+       DC.B    'HER'   ; 'HERE'\r
+       DC.B    'E'|$80\r
+       DC.L    TWOP-3-NATWID\r
+*HERE  DC.L    DOCOL\r
+HERE   BSR.W   DOCOL\r
+       DC.L    DICTPT,AT\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  86  <<\r
+* ( n --- )\r
+* Increase/decrease heap (add n to DP),\r
+* Should ERROR check stack/heap.\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    'ALLO'  ; 'ALLOT'\r
+       DC.B    'T'|$80\r
+       DC.L    HERE-5-NATWID\r
+*ALLOT DC.L    DOCOL\r
+ALLOT  BSR.W   DOCOL\r
+       DC.L    DICTPT,PSTORE\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  87  <<\r
+* ( n --- )\r
+* Store word n at DP++,\r
+* Should ERROR check stack/heap.\r
+       EVEN\r
+       DC.B    $81     ; , (COMMA)\r
+       DC.B    ','|$80\r
+       DC.L    ALLOT-6-NATWID\r
+*COMMA DC.L    DOCOL\r
+COMMA  BSR.W   DOCOL\r
+       DC.L    HERE,STORE,NATWC,ALLOT  ; race condition\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  88  <<\r
+* ( b --- )\r
+* Store byte b at DP+,\r
+* Should ERROR check stack/heap.\r
+* Unfortunate naming.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    'C'     ; 'C,'\r
+       DC.B    ','|$80\r
+       DC.L    COMMA-2-NATWID\r
+*CCOMM DC.L    DOCOL\r
+CCOMM  BSR.W   DOCOL\r
+       DC.L    HERE,CSTORE,ONE,ALLOT   ; race condition\r
+       DC.L    SEMIS\r
+*\r
+* ( n --- )\r
+* Bump the DICTPT if necessary to odd or even alignment, according to n,\r
+* by compiling in an extra NUL byte.\r
+* Odd n for odd alignment, even n for even.\r
+       EVEN\r
+       DC.B    $8B\r
+       DC.B    'ALIGN-COMM'    ; 'ALIGN-COMMA'\r
+       DC.B    'A'|$80\r
+       DC.L    CCOMM-3-NATWID\r
+*ALCOM DC.L    DOCOL\r
+ALCOM  BSR.W   DOCOL\r
+       DC.L    HERE,ZERO,ALGNB,ZBRAN\r
+       DC.L    ALCOMX-*-NATWID\r
+       DC.L    ZERO,CCOMM\r
+ALCOMX DC.L    DROP\r
+       DC.L    SEMIS\r
+*\r
+* Not in model, but needed for 32-bit.\r
+* ( h --- )\r
+* Store half cell h at DP+.\r
+* Should ERROR check stack/heap.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    'H'     ; 'H,'\r
+       DC.B    ','|$80\r
+       DC.L    ALCOM-12-NATWID\r
+*HCOMM DC.L    DOCOL\r
+HCOMM  BSR.W   DOCOL\r
+       DC.L    HERE,HSTORE,HNATWC,ALLOT        ; race condition\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  89  <<\r
+* ( n1 n2 --- n1-n2 )\r
+* Subtract top two words.\r
+       EVEN\r
+       DC.B    $81     ; -\r
+       DC.B    '-'|$80\r
+       DC.L    HCOMM-3-NATWID\r
+*SUB   DC.L    *+NATWID\r
+SUB    MOVE.L  (PSP)+,D0       ; Subtraction is not commutative.\r
+       SUB.L   D0,(PSP)        ; left side operand is the deeper one on the stack.\r
+       RTS\r
+* SUB  DC.L    DOCOL,MINUS,PLUS\r
+*      DC.L    SEMIS   ; Costs extra bytes and lots of cycles compared to native code.\r
+*\r
+* ( d1 d2 --- d1-d2 )\r
+* Subtract top two integers.\r
+* Yes, we do want this in the model.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    'D'     ; D-\r
+       DC.B    '-'|$80\r
+       DC.L    SUB-2-NATWID\r
+*DSUB  DC.L    *+NATWID\r
+DSUB   MOVEM.L (PSP)+,D0/D1/D2/D3      ; ADDX memory operand requires too much setup for just two long words.\r
+       SUB.L   D1,D3                   ; Right order for subtraction.\r
+       SUBX.L  D0,D2\r
+       MOVEM.L D2/D3,-(PSP)\r
+       RTS\r
+*\r
+* ======>>  90  <<\r
+* ( n1 n2 --- n1==n2 )\r
+* Return flag true if n1 and n2 are equal, otherwise false.\r
+       EVEN\r
+       DC.B    $81     ; =\r
+       DC.B    '='|$80\r
+       DC.L    DSUB-3-NATWID\r
+*EQUAL DC.L    DOCOL\r
+EQUAL  BSR.W   DOCOL\r
+       DC.L    SUB,ZEQU\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  91  <<\r
+* ( n1 n2 --- n1<n2 )\r
+* Return flag true if n1 is less than n2, otherwise false.\r
+* Signed compare.\r
+       EVEN\r
+       DC.B    $81     ; <\r
+       DC.B    '<'|$80 \r
+       DC.L    EQUAL-2-NATWID\r
+*LESS  DC.L    *+NATWID\r
+LESS   CLR.L   D2      ; Guess false.\r
+       MOVE.L  (PSP)+,D0\r
+       MOVE.L  (PSP),D1\r
+       SUB.L   D0,D1\r
+       BGE.S   LESSST\r
+TRUE   MOVEQ   #1,D2   ; MOVEQ is a little faster than ADDQ.L\r
+LESSST MOVE.L  D2,(PSP)\r
+       RTS\r
+* \r
+*\r
+* ======>>  92  <<\r
+* ( n1 n2 --- n1>n2 )\r
+* Return flag true if n1 is greater than n2, false otherwise.\r
+       EVEN\r
+       DC.B    $81     ; >\r
+       DC.B    '>'|$80\r
+       DC.L    LESS-2-NATWID\r
+GREAT  DC.L    DOCOL,SWAP,LESS\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  93  <<\r
+* ( n1 n2 n3 --- n2 n3 n1 )\r
+* Rotate the top three words on stack,\r
+* bringing the third word to the top.\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'RO'    ; 'ROT'\r
+       DC.B    'T'|$80\r
+       DC.L    GREAT-2-NATWID\r
+ROT    DC.L    *+NATWID\r
+       MOVEM.L (PSP),D0/D1/D2\r
+       MOVEM.L D0/D1,NATWID(PSP)\r
+       MOVE.L  D2,(PSP)\r
+       RTS\r
+*\r
+* ======>>  94  <<\r
+* ( --- )\r
+* EMIT a SPACE.\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    'SPAC'  ; 'SPACE'\r
+       DC.B    'E'|$80\r
+       DC.L    ROT-4-NATWID\r
+SPACE  DC.L    DOCOL,BL,EMIT\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  95  <<\r
+*  ( n0 n1 --- min(n0,n1) )\r
+* Leave the minimum of the top two integers.\r
+* Being too greedy here, but, whatever.\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'MI'    ; 'MIN'\r
+       DC.B    'N'|$80\r
+       DC.L    SPACE-6-NATWID\r
+MIN    DC.L    *+NATWID\r
+       MOVE.L  (PSP)+,D0\r
+       CMP.L   (PSP),D0\r
+       BGE.S   MINX\r
+       MOVE.L  D0,(PSP)        \r
+MINX   RTS     \r
+* MIN  DC.L    DOCOL,OVER,OVER,GREAT,ZBRAN\r
+*      DC.L    MIN2-*-NATWID\r
+*      DC.L    SWAP\r
+* MIN2 DC.L    DROP\r
+*      DC.L    SEMIS\r
+*\r
+* ======>>  96  <<\r
+* ( n0 n1 --- max(n0,n1) )\r
+* Leave the maximum of the top two integers.\r
+* Really should leave this as in the model, to reduce testing.\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'MA'    ; 'MAX'\r
+       DC.B    'X'|$80\r
+       DC.L    MIN-4-NATWID\r
+MAX    DC.L    *+NATWID\r
+       MOVE.L  (PSP)+,D0\r
+       CMP.L   (PSP),D0\r
+       BLE.S   MAXX\r
+       MOVE.L  D0,(PSP)        \r
+MAXX   RTS     \r
+* MAX  DC.L    DOCOL,OVER,OVER,LESS,ZBRAN\r
+*      DC.L    MAX2-*-NATWID\r
+*      DC.L    SWAP\r
+* MAX2 DC.L    DROP\r
+*      DC.L    SEMIS\r
+*\r
+* ======>>  97  <<\r
+* ( 0 --- 0 )\r
+* ( n --- n n )\r
+* DUP if non-zero.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $84\r
+       DC.B    '-DU'   ; '-DUP'\r
+       DC.B    'P'|$80\r
+       DC.L    MAX-4-NATWID\r
+DDUP   DC.L    *+NATWID        ; Just being greedy for speed.\r
+       MOVE.L  (PSP),D0\r
+       BEQ.S   DDUPX\r
+       MOVE.L  D0,-(PSP)\r
+DDUPX  RTS\r
+* DDUP DC.L    DOCOL,DUP,ZBRAN\r
+*      DC.L    DDUP2-*-NATWID\r
+*      DC.L    DUP\r
+* DDUP2        DC.L    SEMIS\r
+*\r
+* ######>> screen 39 <<\r
+* ======>> 98.1 <<\r
+* Supplemental, intended to be used in refactoring TRAVERSE,\r
+* But really would not work there without more code:\r
+* ( n<0 --- -1 )\r
+* ( n>=~ --- 1 )\r
+* Change top integer to its sign.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $86\r
+       DC.B    'SIGNU' ; 'SIGNUM'\r
+       DC.B    'M'|$80\r
+       DC.L    DDUP-5-NATWID\r
+SIGNUM DC.L    *+NATWID\r
+SIGNUE CLR.L   D0\r
+       TST.L   (PSP)\r
+       SMI     D0\r
+       EXT.W   D0\r
+       EXT.L   D0\r
+       MOVE.L  D0,(PSP)\r
+       RTS\r
+*\r
+* ======>>  98  <<\r
+* ( adr1 direction --- adr2 )\r
+* TRAVERSE the symbol name.\r
+* If direction is 1, find the end.\r
+* If direction is -1, find the beginning.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $88\r
+       DC.B    'TRAVERS'       ; 'TRAVERSE'\r
+       DC.B    'E'|$80\r
+       DC.L    SIGNUM-7-NATWID\r
+*TRAV  DC.L    *+NATWID\r
+*      MOVEQ   #1,D1   ; Convert negative to -1, zero or positive to 1.\r
+*      TST.L   (PSP)+\r
+*      BPL.S   TRAVG\r
+*      NEG.L   D1\r
+*TRAVG MOVE.L  (PSP),A0\r
+**     MOVEQ   #$7F,D0\r
+** TRAVLP      LEA     (A0,D1.L),A0    ; Don't look at the one we start at.\r
+**     CMP.B   (A0),D0 ; This follows the FORTH code, but, we could just look at sign bit.\r
+**     BCC.S   TRAVLP\r
+*      CLR.L   D0      ; Scan by indexing so we can limit it.\r
+*TRAVLP        ADD.L   D1,D0   ; Don't look at (A0).\r
+*      TST.B   (A0,D0.L)\r
+*      BMI.S   TRAVDN\r
+*      TST.L   D1      ; Limit the scan in the selected direction.\r
+*      BMI.S   TRAVLN\r
+*      CMP.W   #32,D0\r
+*      BCS.S   TRAVLP\r
+*TRAVLN        CMP.W   #-31,D0\r
+*      BPL.S   TRAVLP\r
+*TRAVDN        LEA     (A0,D0.L),A0\r
+*      MOVE.L  A0,(PSP)\r
+*      RTS\r
+* Doing this in 68000 or 6809 just because it can be done was getting too greedy.\r
+* Or not? I needed it to test that TRAVERSE was not screwing up.\r
+TRAV   DC.L    DOCOL\r
+*      DC.L    TRON    ; DBUG *****\r
+       DC.L    SWAP\r
+TRAV2  DC.L    OVER,PLUS,LIT16\r
+       DC.W    $7F\r
+       DC.L    OVER,CAT,LESS,ZBRAN\r
+       DC.L    TRAV2-*-NATWID\r
+       DC.L    SWAP,DROP\r
+*      DC.L    TROFF   ; DBG *****\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  99  <<\r
+* ( --- symptr )\r
+* Fetch CURRENT as a per-USER constant.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $86\r
+       DC.B    'LATES' ; 'LATEST'\r
+       DC.B    'T'|$80\r
+       DC.L    TRAV-9-NATWID\r
+LATEST DC.L    DOCOL,CURENT,AT,AT\r
+       DC.L    SEMIS\r
+* LATEST       DC.L    *+NATWID\r
+* Getting too greedy:\r
+*      MOVE.L  XCURR-UORIG(UP),D0\r
+*      MOVE.L  (UP,D0.L),A0\r
+*      MOVE.L  (A0),A0\r
+*      MOVE.L  A0,-(PSP)\r
+*      RTS\r
+* Too greedy, still too many smantic holes in the model to fall through.\r
+* Also, if the address at the CFA is made relative, \r
+* this is part of the code that would be affected --\r
+* especially if it is in native CPU code.\r
+*\r
+* ======>>  100  <<\r
+* Wanted to do these as INCREMENTERs,\r
+* but I need to stick with the model as much as possible,\r
+* (mostly, LOL) adding code only to make the model more clear.\r
+* ( pfa --- lfa )     \r
+* Convert PFA to LFA, unchecked. (Bump back from contents to allocation link.)\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'LF'    ; 'LFA'\r
+       DC.B    'A'|$80\r
+       DC.L    LATEST-7-NATWID\r
+LFA    DC.L    DOCOL,LIT16\r
+*      DC.W    4       ; on 6800\r
+       DC.W    2*NATWID\r
+       DC.L    SUB\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  101  <<\r
+* ( pfa --- cfa )    \r
+* Convert PFA to CFA, unchecked. (Bump back from contents to characterist code link.)\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'CF'    ; 'CFA'\r
+       DC.B    'A'|$80\r
+       DC.L    LFA-4-NATWID\r
+* CFA  DC.L    DOCOL,TWO,SUB   ; on 6800\r
+CFA    DC.L    DOCOL,NATWC,SUB\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  102  <<\r
+* ( pfa --- nfa )     \r
+* Convert PFA to NFA. (Bump back from contents to beginning of symbol name.)\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'NF'    ; 'NFA'\r
+       DC.B    'A'|$80\r
+       DC.L    CFA-4-NATWID\r
+NFA    DC.L    DOCOL,LIT16\r
+*      DC.W    5       ; on 6800\r
+       DC.W    NATWID*2+1\r
+       DC.L    SUB,ONE,MINUS,TRAV\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  103  <<\r
+* ( nfa --- pfa )     \r
+* Convert NFA to PFA. (Bump up from beginning of symbol name to contents.)\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'PF'    ; 'PFA'\r
+       DC.B    'A'|$80\r
+       DC.L    NFA-4-NATWID\r
+PFA    DC.L    DOCOL,ONE,TRAV,LIT16\r
+*      DC.W    5       ; on 6800\r
+       DC.W    NATWID*2+1\r
+       DC.L    PLUS\r
+       DC.L    SEMIS\r
+*\r
+* ######>> screen 40 <<\r
+* ======>>  104  <<\r
+* ( --- )\r
+* Save the parameter stack pointer in CSP for compiler checks.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $84\r
+       DC.B    '!CS'   ; '!CSP'\r
+       DC.B    'P'|$80\r
+       DC.L    PFA-4-NATWID\r
+SCSP   DC.L    DOCOL,SPAT,CSP,STORE\r
+       DC.L    SEMIS\r
+*\r
+       PAGE\r
+*\r
+* ======>>  105  <<\r
+* ( 0 n --- )             ( *** )\r
+* ( true n --- IN BLK )   ( anything *** nothing )\r
+* If flag is false, do nothing. \r
+* If flag is true, issue error MESSAGE and QUIT or ABORT, via ERROR. \r
+* Leaves cursor position (IN)\r
+* and currently loading block number (BLK) on stack, for analysis.\r
+*\r
+* This one is too important to be high-level Forth codes.\r
+* When we have an error, we want to disturb as little as possible.\r
+* But fixing that cascades through ERROR and MESSAGE \r
+* into the disk block system.\r
+* And we aren't ready for that yet.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $86\r
+       DC.B    '?ERRO' ; '?ERROR'\r
+       DC.B    'R'|$80\r
+       DC.L    SCSP-5-NATWID\r
+* QERR DC.L    *+NATWID\r
+*      TST.L   NATWID(PSP)\r
+*      BNE.S   QERROR\r
+*      LEA     NATWID(PSP),PSP\r
+*      RTS\r
+** this doesn't work anyway: \r
+* QERROR       BRA.W   ERROR\r
+QERR   DC.L    DOCOL,SWAP,ZBRAN\r
+       DC.L    QERR2-*-NATWID\r
+       DC.L    ERROR,BRAN\r
+       DC.L    QERR3-*-NATWID\r
+QERR2  DC.L    DROP\r
+QERR3  DC.L    SEMIS\r
+*      \r
+* ======>>  106  <<\r
+* STATE is compiling:\r
+* ( --- )                 ( *** )\r
+* STATE is not compiling:\r
+* ( --- IN BLK )          ( anything *** nothing )\r
+* ERROR if not compiling.\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    '?COM'  ; '?COMP'\r
+       DC.B    'P'|$80\r
+       DC.L    QERR-7-NATWID\r
+QCOMP  DC.L    DOCOL,STATE,AT,ZEQU,LIT16\r
+       DC.W    $11\r
+       DC.L    QERR\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  107  <<\r
+* STATE is executing:\r
+* ( --- )                 ( *** )\r
+* STATE is not executing:\r
+* ( --- IN BLK )          ( anything *** nothing )\r
+* ERROR if not executing.\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    '?EXE'  ; '?EXEC'\r
+       DC.B    'C'|$80\r
+       DC.L    QCOMP-6-NATWID\r
+QEXEC  DC.L    DOCOL,STATE,AT,LIT16\r
+       DC.W    $12\r
+       DC.L    QERR\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  108  <<\r
+* ( n1 n1 --- )           ( *** )\r
+* ( n1 n2 --- IN BLK )    ( anything *** nothing )\r
+* ERROR if top two are unequal. \r
+* MESSAGE says compiled conditionals do not match.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $86\r
+       DC.B    '?PAIR' ; '?PAIRS'\r
+       DC.B    'S'|$80\r
+       DC.L    QEXEC-6-NATWID\r
+QPAIRS DC.L    DOCOL,SUB,LIT16\r
+       DC.W    $13\r
+       DC.L    QERR\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  109  <<\r
+* CSP and parameter stack are balanced (equal):\r
+* ( --- )                 ( *** )\r
+* CSP and parameter stack are not balanced (unequal):\r
+* ( --- IN BLK )          ( anything *** nothing )\r
+* ERROR if return/control stack is not at same level as last !CSP.\r
+* Usually indicates that a definition has been left incomplete.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $84\r
+       DC.B    '?CS'   ; '?CSP'\r
+       DC.B    'P'|$80\r
+       DC.L    QPAIRS-7-NATWID\r
+QCSP   DC.L    DOCOL,SPAT,CSP,AT,SUB,LIT16\r
+       DC.W    $14\r
+       DC.L    QERR\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  110  <<\r
+* Active BLK input:\r
+* ( --- )         ( *** )\r
+* No active BLK input:\r
+* ( --- IN BLK )          ( anything *** nothing )\r
+* ERROR if not loading, i. e., if BLK is zero.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $88\r
+       DC.B    '?LOADIN'       ; '?LOADING'\r
+       DC.B    'G'|$80\r
+       DC.L    QCSP-5-NATWID\r
+QLOAD  DC.L    DOCOL,BLK,AT,ZEQU,LIT16\r
+       DC.W    $16\r
+       DC.L    QERR\r
+       DC.L    SEMIS\r
+*\r
+* ######>> screen 41 <<\r
+* ======>>  111  <<\r
+* ( --- )\r
+* Compile an in-line literal value from the instruction stream.\r
+       EVEN\r
+       DC.B    $87\r
+       DC.B    'COMPIL'        ; 'COMPILE'\r
+       DC.B    'E'|$80\r
+       DC.L    QLOAD-9-NATWID\r
+* COMPIL       DC.L    DOCOL,QCOMP,FROMR,TWOP,DUP,TOR,AT,COMMA\r
+* COMPIL       DC.L    DOCOL,QCOMP,FROMR,NATP,DUP,TOR,AT,COMMA\r
+COMPIL DC.L    DOCOL,QCOMP,FROMR,DUP,NATP,TOR,AT,COMMA\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  112  <<\r
+* ( --- )                                                 P\r
+* Clear the compile state bit(s) (shift to interpret).\r
+       EVEN\r
+       DC.B    $C1     ; [     immediate\r
+       DC.B    '['|$80\r
+       DC.L    COMPIL-8-NATWID\r
+LBRAK  DC.L    DOCOL,ZERO,STATE,STORE\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  113  <<\r
+* \r
+STCOMP EQU     $C0\r
+* ( --- )\r
+* Set the compile state bit(s) (shift to compile).\r
+       EVEN\r
+       DC.B    $81     ; ]\r
+       DC.B    ']'|$80\r
+       DC.L    LBRAK-2-NATWID\r
+RBRAK  DC.L    DOCOL,LIT16\r
+       DC.W    STCOMP\r
+       DC.L    STATE,STORE\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  114  <<\r
+* ( --- )\r
+* Toggle SMUDGE bit of LATEST definition header,\r
+* to hide it until defined or reveal it after definition.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $86\r
+       DC.B    'SMUDG' ; 'SMUDGE'\r
+       DC.B    'E'|$80\r
+       DC.L    RBRAK-2-NATWID\r
+SMUDGE DC.L    DOCOL,LATEST,LIT16\r
+       DC.W    FSMUDG\r
+       DC.L    TOGGLE\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  115  <<\r
+* ( --- )\r
+* Set the conversion base to sixteen (b00010000).\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'HE'    ; 'HEX'\r
+       DC.B    'X'|$80\r
+       DC.L    SMUDGE-7-NATWID\r
+HEX    DC.L    DOCOL\r
+       DC.L    LIT16\r
+       DC.W    16      ; decimal sixteen\r
+       DC.L    BASE,STORE\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  116  <<\r
+* ( --- )\r
+* Set the conversion base to ten (b00001010).\r
+       EVEN\r
+       DC.B    $87\r
+       DC.B    'DECIMA'        ; 'DECIMAL'\r
+       DC.B    'L'|$80\r
+       DC.L    HEX-4-NATWID\r
+DEC    DC.L    DOCOL\r
+       DC.L    LIT16\r
+       DC.W    10      ; decimal ten\r
+       DC.L    BASE,STORE\r
+       DC.L    SEMIS\r
+*\r
+* ######>> screen 42 <<\r
+* ======>>  117  <<\r
+* ( --- )         ( IP *** ) \r
+* Pop the saved IP and use it to \r
+* compile the latest symbol as a reference to a ;CODE definition;\r
+* overwrite the code field of the symbol found by LATEST\r
+* with the address of the low-level characteristic code\r
+* provided in the defining definition.\r
+* Look closely at where things return, consider the operation of R> and >R .\r
+*\r
+* The machine-level code which follows (;CODE) in the instruction stream\r
+* is not executed by the defining symbol,\r
+* but becomes the characteristic of the defined symbol. \r
+* This is the usual way to generate the characteristics of VARIABLEs,\r
+* CONSTANTs, COLON definitions, etc., when FORTH compiles itself. \r
+*\r
+* Finally, note that, if code shifts from low level back to high \r
+* (native CPU machine code calling into a list of FORTH codes),\r
+* the low level code can't just call a high-level definition. \r
+* Leaf definitions can directly call other leaf definitions, \r
+* but not non-leafs.\r
+* It will need an anonymous list, probably embedded in the low-level code,\r
+* and Y and X will have to be set appropriately before entering the list.\r
+\r
+*********\r
+********* This will have to fix up the initial branch according to the offset to the characteristic:\r
+* BSR.S (2 bytes)\r
+* BSR.W (4 bytes)\r
+* MOVE.L #difference,IX; JMP (PC,IX.L) or something (6 bytes, for those that don't have BSR.L)\r
+*********\r
+*\r
+* BSR.S offset and BSR.W offsets are both from the address of the word following the op-code lead word, \r
+* which is kind of awkward. \r
+* Use TARGL as dummy target, to avoid semantics of 0 offset.\r
+* Since the 68000 does not have BSR.L (not until the 68020), long offset branches will have to be synthesized:\r
+DOASML MOVE.L  #TARGL-*,A0     ; 6 bytes, overwrite offset in long word following opcode\r
+       JSR     TARGL(PC,A0.L)  ; 4 bytes, offset should be forced to 0\r
+* I do not like the way it's handling the offset for PC relative, indexed.\r
+TARGL:\r
+* 3206 T  00003952 207C0000000A         DOASML  MOVE.L  #TARGL-*,A0     ; 6 bytes, overwrite offset in long word following opcode\r
+* 3207 T  00003958 4EBB8802                     JSR     TARGL(PC,A0.L)  ; 4 bytes, offset should be forced to 0\r
+* 3209 T  0000395C                      TARGL:\r
+DOASMW BSR.W   TARGL           ; overwrite offset following 16-bit op-code.\r
+* 3213 T  0000395C 6100FFFE             DOASMW  BSR.W   TARGL           ; overwrite offset following 16-bit op-code.\r
+DOASMS BSR.S   TARGL           ; overwrite offset in 2nd byte of op-code.\r
+* 3215 T  00003960 61FA                 DOASMS  BSR.S   TARGL           ; overwrite offset in 2nd byte of op-code.\r
+\r
+       EVEN\r
+       DC.B    $87\r
+       DC.B    '(;CODE'        ; '(;CODE)'\r
+       DC.B    ')'|$80\r
+       DC.L    DEC-8-NATWID\r
+* PSCODE       DC.L    DOCOL,FROMR,TWOP,LATEST,PFA,CFA,STORE\r
+PSCODE DC.L    DOCOL,FROMR     ; A5/IP is post-inc, needs no adjustment.\r
+       DC.L    LATEST,PFA,CFA,STORE\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  118  <<\r
+* ( --- )                                                 P\r
+* ?CSP to see if there are loose ends in the defining definition\r
+* before shifting to the assembler,\r
+* compile (;CODE) in the defining definition's instruction stream,\r
+* shift to interpreting,\r
+* make the ASSEMBLER vocabulary current,\r
+* and !CSP to mark the stack\r
+* in preparation for assembling low-level code.\r
+* Note that ;CODE, unlike DOES>, is IMMEDIATE,\r
+* and compiles (;CODE),\r
+* which will do the actual work of changing\r
+* the LATEST definition's characteristic when the defining word runs.\r
+* Assembly is done by the interpreter, rather than the compiler.\r
+* I could have avoided the anomalous three-byte code fields by\r
+*\r
+* Note that the ASSEMBLER is not part of the model (at this time).\r
+* That means that, until the assembler is ready, \r
+* if you want to define low-level words,\r
+* you have to poke (comma) in hand-assembled stuff.\r
+*\r
+       EVEN\r
+       DC.B    $C5     immediate\r
+       DC.B    ';COD'  ; ';CODE'\r
+       DC.B    'E'|$80\r
+       DC.L    PSCODE-8-NATWID\r
+SEMIC  DC.L    DOCOL,QCSP,COMPIL,PSCODE,SMUDGE,LBRAK,QSTACK\r
+       DC.L    NOOP    ; note: will be replaced by "ASSEMBLER" later\r
+       DC.L    SEMIS\r
+* note: I think I'd rather keep ?STACK here, so I'm adding a NOOP to be patched later. \r
+*\r
+* ######>> screen 43 <<\r
+* ======>>  119  <<\r
+* ( --- )                                                 C\r
+* Make the word currently being defined\r
+* build a header for DOES> definitions. \r
+* Actually just compiles a CONSTANT zero\r
+* which can be overwritten later by DOES>.\r
+* Since the fig models were established, this technique has been deprecated.\r
+*\r
+* Note that <BUILDS is not IMMEDIATE,\r
+* and therefore executes during a definition's run-time,\r
+* rather than its compile-time. \r
+* It is not intended to be used directly,\r
+* but rather so that one definition word can build another. \r
+* Also, note that nothing particularly special happens\r
+* in the defining definition until DOES> executes. \r
+* The name <BUILDS is intended to be a reminder of what is about to occur.\r
+*\r
+* <BUILDS probably should have compiled an ERROR instead of a ZERO CONSTANT.\r
+       EVEN\r
+       DC.B    $87\r
+       DC.B    '<BUILD'        ; '<BUILDS'\r
+       DC.B    'S'|$80\r
+       DC.L    SEMIC-6-NATWID\r
+BUILDS DC.L    DOCOL,ZERO,CON\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  120  <<\r
+* ( --- )         ( IP *** )                              C\r
+* Define run-time behavior of definitions compiled/defined\r
+* by a high-level defining definition --\r
+* the FORTH equivalent of a compiler-compiler. \r
+* DOES> assumes that the LATEST symbol table entry\r
+* has at least one word of parameter field,\r
+* which <BUILDS provides. \r
+* Note that DOES> is also not IMMEDIATE. \r
+*\r
+* When the defining word containing DOES> executes the DOES> icode,\r
+* it overwrites the LATEST symbol's CFA with jsr <XDOES,\r
+* overwrites the first word of that symbol's parameter field with its own IP,\r
+* and pops the previous IP from the return stack.\r
+* The icodes which follow DOES> in the stream\r
+* do not execute at the defining word's run-time.\r
+*\r
+* Examining XDOES in the virtual machine shows\r
+* that the defined word will execute those icodes\r
+* which follow DOES> at its own run-time. \r
+*\r
+* The advantage of this kind of behaviour,\r
+* which you will also note in ;CODE,\r
+* is that the defined word can contain\r
+* both operations and data to be operated on. \r
+* This is how FORTH data objects define their own behavior. \r
+*\r
+* Finally, note that the effective parameter field for DOES> definitions\r
+* starts two NATWID words after the CFA, instead of just one\r
+* (eight bytes instead of four in a thirty-two-bit addressing Forth).\r
+*\r
+* VOCABULARYs will use this. See definition of word FORTH.\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    'DOES'  ; 'DOES>'\r
+       DC.B    '>'|$80\r
+       DC.L    BUILDS-8-NATWID\r
+* DOES DC.L    DOCOL,FROMR,TWOP,LATEST,PFA,STORE\r
+DOES   DC.L    DOCOL,FROMR     ; A5/IP is post-inc, needs no adjustment.\r
+       DC.L    LATEST,PFA,STORE\r
+       DC.L    PSCODE\r
+*\r
+* ( --- PFA+NATWID )     ( *** IP )\r
+* Characteristic of a DOES> defined word. \r
+* The characteristics of DOES> definitions are written in high-level\r
+* Forth codes rather than native CPU machine level code.\r
+* The first parameter word points to the high-level characteristic. \r
+* This routine's job is to push the IP,\r
+* load the high level characteristic pointer in IP,\r
+* and leave the address following the characteristic pointer on the stack\r
+* so the parameter field can be accessed.\r
+DODOES MOVE.L  (RP),A0\r
+       MOVE.L  IP,(RP) ; Save/nest the current IP on the return stack.\r
+       MOVE.L  (W),IP  ; First parameter is new IP.\r
+       LEA     NATWID(W),A1    ; Address of second parameter.\r
+       MOVE.L  A1,-(PSP)       ; Note that PEA would push on Forth RP\r
+       JMP     (A0)    ; return to NEXT.\r
+*\r
+* ######>> screen 44 <<\r
+* ======>>  121  <<\r
+* ( strptr --- strptr+1 count )\r
+* Convert counted string to string and count. \r
+* (Fetch the byte at strptr, post-increment.)\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    'COUN'  ; 'COUNT'\r
+       DC.B    'T'|$80\r
+       DC.L    DOES-6-NATWID\r
+COUNT  DC.L    DOCOL,DUP,ONEP,SWAP,CAT\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  122  <<\r
+* ( strptr count --- )\r
+* EMIT count characters at strptr.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $84\r
+       DC.B    'TYP'   ; 'TYPE'\r
+       DC.B    'E'|$80\r
+       DC.L    COUNT-6-NATWID\r
+TYPE   DC.L    DOCOL,DDUP,ZBRAN\r
+       DC.L    TYPE3-*-NATWID\r
+       DC.L    OVER,PLUS,SWAP,XDO\r
+TYPE2  DC.L    I,CAT,EMIT,XLOOP\r
+       DC.L    TYPE2-*-NATWID\r
+       DC.L    BRAN\r
+       DC.L    TYPE4-*-NATWID\r
+TYPE3  DC.L    DROP\r
+TYPE4  DC.L    SEMIS\r
+*\r
+* ======>>  123  <<\r
+* ( strptr count1 --- strptr count2 )\r
+* Supress trailing blanks (subtract count of trailing blanks from strptr).\r
+       EVEN\r
+       DC.B    $89\r
+       DC.B    '-TRAILIN'      ; '-TRAILING'\r
+       DC.B    'G'|$80\r
+       DC.L    TYPE-5-NATWID\r
+DTRAIL DC.L    DOCOL,DUP,ZERO,XDO\r
+DTRAL2 DC.L    OVER,OVER,PLUS,ONE,SUB,CAT,BL\r
+       DC.L    SUB,ZBRAN\r
+       DC.L    DTRAL3-*-NATWID\r
+       DC.L    LEAVE,BRAN\r
+       DC.L    DTRAL4-*-NATWID\r
+DTRAL3 DC.L    ONE,SUB\r
+DTRAL4 DC.L    XLOOP\r
+       DC.L    DTRAL2-*-NATWID\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  124  <<\r
+* ( --- ) \r
+* TYPE counted string out of instruction stream (updating IP).\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $84\r
+       DC.B    '(."'   ; '(.")'\r
+       DC.B    ')'|$80\r
+       DC.L    DTRAIL-10-NATWID\r
+* PDOTQ        DC.L    DOCOL,R,TWOP,COUNT,DUP,ONEP\r
+* PDOTQ        DC.L    DOCOL,R,NATP,COUNT,DUP,ONEP\r
+PDOTQ  DC.L    DOCOL,R         ; A5/IP is post-inc.\r
+       DC.L    COUNT,DUP,ONEP  ; There's a count byte, too.\r
+       DC.L    ZERO,ALGNB,PLUS ; Align the count.\r
+       DC.L    FROMR,PLUS,TOR  ; IP ready to continue after the string.\r
+       DC.L    TYPE\r
+       DC.L    BREAK   ; DBG *****\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  125  <<\r
+* ( --- )                                                 P\r
+* { ." something-to-be-printed " } typical input\r
+* Use WORD to parse to trailing quote;\r
+* if compiling, compile XDOTQ and string parsed,\r
+* otherwise, TYPE string.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $C2     immediate\r
+       DC.B    '.'     ; '."'\r
+       DC.B    '"'|$80\r
+       DC.L    PDOTQ-5-NATWID\r
+DOTQ   DC.L    DOCOL\r
+       DC.L    LIT16\r
+       DC.W    $22     ascii quote\r
+       DC.L    STATE,AT,ZBRAN\r
+       DC.L    DOTQ1-*-NATWID\r
+       DC.L    COMPIL,PDOTQ,WORD\r
+       DC.L    HERE,CAT,ONEP,DUP,ALLOT\r
+       DC.L    ALGNB,ZBRAN     ; Rely on PDOTQ to adjust the IP for the odd length.\r
+       DC.L    DOTQ0-*-NATWID\r
+       DC.L    ZERO,CCOMM      ; Align and fill with NUL\r
+DOTQ0  DC.L    BRAN\r
+       DC.L    DOTQ2-*-NATWID\r
+DOTQ1  DC.L    WORD,HERE,COUNT,TYPE\r
+DOTQ2  DC.L    SEMIS\r
+*\r
+* ######>> screen 45 <<\r
+* ======>>  126  <<== MACHINE DEPENDENT\r
+* ( --- )                 ( *** )\r
+* ( --- IN BLK )          ( anything *** nothing )\r
+* ERROR if parameter stack out of bounds.\r
+* \r
+* But checking whether the stack is in bounds or not\r
+* really should not use the stack.\r
+* And there really should be a ?RSTACK, as well.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $86\r
+       DC.B    '?STAC' ; '?STACK'\r
+       DC.B    'K'|$80\r
+       DC.L    DOTQ-3-NATWID\r
+QSTACK DC.L    DOCOL,LIT16\r
+*      DC.W    $12\r
+       DC.W    SINIT-ORIG\r
+* But why use that instead of XSPZER (S0)?\r
+* Multi-user or multi-tasking would not want that.\r
+*      CMP.L   XSPZER-UORIG(UP),PSP    ; something like this   \r
+*      DC.L    PORIG,AT,TWO,SUB,SPAT,LESS,ONE\r
+       DC.L    PORIG,AT,SPAT,LESS,ONE  ; Not post-decrement push.\r
+       DC.L    QERR\r
+* prints 'empty stack'\r
+*\r
+QSTAC2 DC.L    SPAT\r
+* Here, we compare with a value at least 128\r
+* higher than dict. ptr. (DICTPT)\r
+*      DC.L    HERE,LIT16\r
+*      DC.W    $80     ; This is a rough check anyway, leave it as is. \r
+* But shouldn't it be the terminal width?\r
+       DC.L    HERE,COLUMS,AT\r
+       DC.L    PLUS,LESS,ZBRAN\r
+       DC.L    QSTAC3-*-NATWID\r
+       DC.L    TWO     ; NOT the NATWID constant!\r
+       DC.L    QERR\r
+* prints 'full stack'\r
+*\r
+QSTAC3 DC.L    SEMIS\r
+*\r
+* ======>>  127  <<    this word's function\r
+*          is done by ?STACK in this version\r
+*      EVEN\r
+*      DC.B    $85\r
+*      DC.B    4,?FREE\r
+*      DC.B    'E'|$80\r
+*      DC.L    QSTACK-7-NATWID\r
+*QFREE DC.L    DOCOL,SPAT,HERE,LIT16\r
+*      DC.W    $80\r
+*      DC.L    PLUS,LESS,TWO,QERR,SEMIS        ; This TWO is not NATWID!\r
+*\r
+       PAGE\r
+*\r
+* ######>> screen 46 <<\r
+* ======>>  128  <<\r
+* ( buffer n --- )\r
+* ***** Check that this is how it works here:\r
+* Get up to n-1 characters from the keyboard,\r
+* storing at buffer and echoing, with backspace editing,\r
+* quitting when a CR is read.\r
+* Terminate it with a NUL.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $86\r
+       DC.B    'EXPEC' ; 'EXPECT'\r
+       DC.B    'T'|$80\r
+       DC.L    QSTACK-7-NATWID\r
+EXPECT DC.L    DOCOL,OVER,PLUS,OVER,XDO        ; brace the buffer area\r
+* EXPEC2       DC.L    KEY,DUP,LIT16\r
+EXPEC2 DC.L    KEY\r
+       DC.L    DUP,LIT16\r
+       DC.W    BACKSP-ORIG     ; again, this should be in the per-task table\r
+       DC.L    PORIG,AT,EQUAL,ZBRAN    ; check for backspacing \r
+       DC.L    EXPEC3-*-NATWID\r
+       DC.L    DROP,LIT16\r
+       DC.W    8       ; ( backspace character to emit )\r
+       DC.L    OVER,I,EQUAL,DUP,FROMR,TWO,SUB,PLUS     ; back I up TWO characters \r
+       DC.L    TOR,SUB,BRAN\r
+       DC.L    EXPEC6-*-NATWID\r
+EXPEC3 DC.L    DUP,LIT16\r
+       DC.W    $D      ; ( carriage return )\r
+       DC.L    EQUAL,ZBRAN\r
+       DC.L    EXPEC4-*-NATWID\r
+* DC.L BREAK   ; dbg\r
+       DC.L    LEAVE,DROP,BL,ZERO,BRAN ; I think this is the NUL terminator.\r
+       DC.L    EXPEC5-*-NATWID\r
+EXPEC4 DC.L    DUP\r
+* DC.L BREAK   ; dbg\r
+EXPEC5 DC.L    I,CSTORE,ZERO,I,ONEP,CSTORE,ZERO,I,TWOP,CSTORE  ; save two NULs to make sure address is even\r
+EXPEC6 DC.L    EMIT,XLOOP\r
+       DC.L    EXPEC2-*-NATWID\r
+       DC.L    DROP\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  129  <<\r
+* ( --- )\r
+* EXPECT terminal width characters to TIB.\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    'QUER'  ; 'QUERY'\r
+       DC.B    'Y'|$80\r
+       DC.L    EXPECT-7-NATWID\r
+QUERY  DC.L    DOCOL,TIB,AT,COLUMS,AT\r
+*      DC.L    TRON    ; dbg *****\r
+       DC.L    EXPECT,ZERO,IN,STORE\r
+*      DC.L    TROFF   ; dbg *****\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  130  <<\r
+* ( --- )                                                 P\r
+* End interpretation of a line or screen, and/or prepare for a new block. \r
+* Note that the name of this definition is an empty string,\r
+* so it matches on the terminating NUL in the terminal or block buffer.\r
+       EVEN\r
+       DC.B    $C1     ; immediate     < carriage return >\r
+       DC.B    $00|$80 ; NUL character (end of buffered text)\r
+       DC.L    QUERY-6-NATWID\r
+NULL   DC.L    DOCOL,BLK,AT,ZBRAN\r
+       DC.L    NULL2-*-NATWID\r
+       DC.L    ONE,BLK,PSTORE\r
+       DC.L    ZERO,IN,STORE,BLK,AT,BSCR,MOD\r
+       DC.L    ZEQU\r
+*     check for end of screen\r
+       DC.L    ZBRAN\r
+       DC.L    NULL1-*-NATWID\r
+       DC.L    QEXEC,FROMR,DROP\r
+NULL1  DC.L    BRAN\r
+       DC.L    NULL3-*-NATWID\r
+NULL2  DC.L    FROMR,DROP\r
+NULL3  DC.L    SEMIS\r
+*\r
+       PAGE\r
+*\r
+* ######>> screen 47 <<\r
+* ======>>  133  <<\r
+* ( adr n b --- )\r
+* Fill n bytes at adr with b.\r
+* This relies on CMOVE having a certain lack of parameter checking,\r
+* where overlapping regions are not properly inverted in copy.\r
+* And this really should be done in low-level.\r
+* None of the advantages of doing things in high-level apply to fill.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $84\r
+       DC.B    'FIL'   ; 'FILL'\r
+       DC.B    'L'|$80\r
+       DC.L    NULL-2-NATWID\r
+FILL   DC.L    DOCOL\r
+*      DC.L    BREAK   ; DBG\r
+       DC.L    SWAP,TOR,OVER,CSTORE,DUP,ONEP\r
+       DC.L    FROMR,ONE,SUB,CMOVE\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  134  <<\r
+* ( adr n --- )\r
+* Fill n bytes with 0.\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    'ERAS'  ; 'ERASE'\r
+       DC.B    'E'|$80\r
+       DC.L    FILL-5-NATWID\r
+ERASE  DC.L    DOCOL,ZERO,FILL\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  135  <<\r
+* ( adr n --- )\r
+* Fill n bytes with ASCII SPACE.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $86\r
+       DC.B    'BLANK' ; 'BLANKS'\r
+       DC.B    'S'|$80\r
+       DC.L    ERASE-6-NATWID\r
+BLANKS DC.L    DOCOL,BL,FILL\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  136  <<\r
+* ( c --- )\r
+* Format a character at the left of the HLD output buffer.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $84\r
+       DC.B    'HOL'   ; 'HOLD'\r
+       DC.B    'D'|$80\r
+       DC.L    BLANKS-7-NATWID\r
+HOLD   DC.L    DOCOL,LIT\r
+       DC.L    -1      ; $FFFF in 16-bit model, but -1 is -1. DPL flag.\r
+       DC.L    HLD,PSTORE,HLD,AT,CSTORE\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  137  <<\r
+* ( --- adr )\r
+* Give the address of the output PAD buffer. \r
+* PAD points to the end of a 68 byte buffer for numeric conversion.\r
+* 68 bytes is enough to convert a 64-bit integer to binary.\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'PA'    ; 'PAD'\r
+       DC.B    'D'|$80\r
+       DC.L    HOLD-5-NATWID\r
+PAD    DC.L    DOCOL,HERE,LIT16\r
+       DC.W    $44\r
+       DC.L    PLUS\r
+       DC.L    SEMIS\r
+*\r
+* ######>> screen 48 <<\r
+* ======>>  138  <<\r
+* ( c --- )\r
+* Scan a string terminated by the character c or ASCII NUL out of input;\r
+* store symbol at WORDPAD with leading count byte and trailing ASCII NUL. \r
+* Leading c are passed over, per ENCLOSE.\r
+* Scans from BLK, or from TIB if BLK is zero. \r
+* May overwrite the numeric conversion pad,\r
+* if really long (length > 31) symbols are scanned.\r
+* Does not ALLOCate the symbol.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $84\r
+       DC.B    'WOR'   ; 'WORD'\r
+       DC.B    'D'|$80\r
+       DC.L    PAD-4-NATWID\r
+WORD   DC.L    DOCOL,BLK,AT,ZBRAN\r
+       DC.L    WORD2-*-NATWID\r
+       DC.L    BLK,AT,BLOCK,BRAN\r
+       DC.L    WORD3-*-NATWID\r
+WORD2  DC.L    TIB,AT\r
+WORD3  DC.L    IN,AT,PLUS,SWAP,ENCLOS,HERE,LIT16\r
+       DC.W    MAXNML+2\r
+       DC.L    BLANKS,IN,PSTORE,OVER,SUB,TOR,R,HERE\r
+       DC.L    CSTORE,PLUS,HERE,ONEP,FROMR,CMOVE\r
+       DC.L    SEMIS\r
+*\r
+* ######>> screen 49 <<\r
+* ======>>  139  <<\r
+* ( d1 string --- d2 adr )\r
+* Convert the text at string into a number, accumulating the result into d1,\r
+* leaving adr pointing to the first character not converted. \r
+* If DPL is non-negative at entry,\r
+* accumulates the number of characters converted into DPL.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $88\r
+       DC.B    '(NUMBER'       ; '(NUMBER)'\r
+       DC.B    ')'|$80\r
+       DC.L    WORD-5-NATWID\r
+PNUMB  DC.L    DOCOL\r
+*      DC.L    BREAK   ; DBG *****\r
+PNUMB2 DC.L    ONEP,DUP,TOR,CAT,BASE,AT,DIGIT,ZBRAN\r
+       DC.L    PNUMB4-*-NATWID\r
+       DC.L    SWAP,BASE,AT,USTAR,DROP,ROT,BASE\r
+       DC.L    AT,USTAR,DPLUS,DPL,AT,ONEP,ZBRAN\r
+       DC.L    PNUMB3-*-NATWID\r
+       DC.L    ONE,DPL,PSTORE\r
+PNUMB3 DC.L    FROMR,BRAN\r
+       DC.L    PNUMB2-*-NATWID\r
+PNUMB4 DC.L    FROMR\r
+*      DC.L    BREAK   ; DBG *****\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  140  <<\r
+* ( ctstr --- d )\r
+* Convert text at ctstr to a double integer,\r
+* taking the 0 ERROR if the conversion is not valid. \r
+* If a decimal point is present,\r
+* accumulate the count of digits to the decimal point's right into DPL\r
+* (negative DPL at exit indicates single precision). \r
+* ctstr is a counted string\r
+* -- the first byte at ctstr is the length of the string,\r
+* but NUMBER ignores the count and expects a NUL terminator instead.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $86\r
+       DC.B    'NUMBE' ; 'NUMBER'\r
+       DC.B    'R'|$80\r
+       DC.L    PNUMB-9-NATWID\r
+NUMB   DC.L    DOCOL,ZERO,ZERO,ROT,DUP,ONEP,CAT,LIT16\r
+       DC.W    "-"     minus sign\r
+       DC.L    EQUAL,DUP,TOR,PLUS,LIT\r
+       DC.L    -1      ; $FFFF in 16-bit model, but -1 is -1. DPL flag.\r
+NUMB1  DC.L    DPL,STORE,PNUMB,DUP,CAT,BL,SUB\r
+       DC.L    ZBRAN\r
+       DC.L    NUMB2-*-NATWID\r
+       DC.L    DUP,CAT,LIT16\r
+       DC.W    "."\r
+       DC.L    SUB,ZERO,QERR,ZERO,BRAN\r
+       DC.L    NUMB1-*-NATWID\r
+NUMB2  DC.L    DROP,FROMR,ZBRAN\r
+       DC.L    NUMB3-*-NATWID\r
+       DC.L    DMINUS\r
+NUMB3  DC.L    SEMIS\r
+*\r
+* ======>>  141  <<\r
+* ( --- locptr length true )      { -FIND name } typical input\r
+* ( --- false )\r
+* Parse a word, then FIND,\r
+* first in the definition vocabulary,\r
+* then in the CONTEXT (interpretation) vocabulary, if necessary.\r
+* Returns what (FIND) returns, flag and optional location and length.\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    '-FIN'  ; '-FIND'\r
+       DC.B    'D'|$80\r
+       DC.L    NUMB-7-NATWID\r
+DFIND  DC.L    DOCOL,BL,WORD,HERE,CONTXT,AT,AT\r
+       DC.L    PFIND,DUP,ZEQU,ZBRAN\r
+       DC.L    DFIND2-*-NATWID\r
+       DC.L    DROP,HERE,LATEST,PFIND\r
+DFIND2 DC.L    SEMIS\r
+*\r
+       PAGE\r
+* ######>> screen 50 <<\r
+* ======>>  142  <<\r
+* ( anything --- nothing )        ( anything *** nothing )\r
+* An indirection for ABORT, for ERROR,\r
+* which may be modified carefully.\r
+       EVEN\r
+       DC.B    $87\r
+       DC.B    '(ABORT'        ; '(ABORT)'\r
+       DC.B    ')'|$80\r
+       DC.L    DFIND-6-NATWID\r
+PABORT DC.L    DOCOL,ABORT\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  143  <<\r
+* ERROR        ( anything line --- IN BLK )    ( anything *** nothing )\r
+* ( anything --- nothing )\r
+* ( anything *** nothing ) WARNING < 0\r
+* Prints out the last symbol scanned and MESSAGE number line.  If\r
+* WARNING is less than zero, ABORTs through (ABORT), otherwise,\r
+* clears the parameter stack, pushes the INput cursor and\r
+* interpretaion BLK, and QUITs.\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    'ERRO'  ; 'ERROR'\r
+       DC.B    'R'|$80\r
+       DC.L    PABORT-8-NATWID\r
+* This really should not be high level, according to best practices.\r
+* But fixing that cascades through MESSAGE,\r
+* requiring re-architecting the disk block system.\r
+* First, we need to get this transliteration running.\r
+ERROR  DC.L    DOCOL,WARN,AT,ZLESS\r
+       DC.L    ZBRAN\r
+       DC.L    ERROR2-*-NATWID\r
+* note: WARNING is\r
+* -1 to abort,\r
+* 0 to print error #\r
+* and 1 to print error message from disc\r
+       DC.L    PABORT\r
+ERROR2 DC.L    HERE,COUNT,TYPE,PDOTQ\r
+       DC.B    4,7     ; ( bell )\r
+       DC.B    " ? "\r
+       DC.B    0       ; hand-align\r
+       DC.L    MESS,SPSTOR,IN,AT,BLK,AT,QUIT\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  144  <<\r
+* ( n adr --- )\r
+* Mask byte at adr with n.\r
+* Not in FIG, don't need it for 8 bit characters after all.\r
+*      EVEN\r
+*      DC.B    $85\r
+*      DC.B    'CMAS'  ; 'CMASK'\r
+*      DC.B    'K'|$80\r
+*      DC.L    ERROR-6-NATWID\r
+* CMASK        DC.L    *+NATWID\r
+*      MOVE.L  (PSP)+,A0       ; adr\r
+*      MOVE.L  (PSP)+,D0       ; prepare for mask\r
+*      AND.B   D0,(A0)\r
+*      RTS\r
+*\r
+* ( adr --- adr )\r
+* Mask high bit of tail of name in PAD buffer.\r
+* Not in FIG, need it for characters with high bit set.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $86\r
+       DC.B    'IDFLA' ; 'IDFLAT'\r
+       DC.B    'T'|$80\r
+       DC.L    ERROR-6-NATWID\r
+IDFLAT DC.L    *+NATWID\r
+       MOVE.L  (PSP),A0\r
+       MOVE.B  (A0),D1 ; get the count\r
+       AND.W   #CTMASK,D1\r
+       AND.B   #$7F,(A0,D1.W)  ; point to the tail and clear the EndOfName flag bit.\r
+       RTS\r
+*\r
+* ( symptr --- )\r
+* Print definition's name from its NFA.\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'ID'    ; 'ID.'\r
+       DC.B    '.'|$80\r
+       DC.L    IDFLAT-7-NATWID\r
+IDDOT  DC.L    DOCOL,PAD\r
+*      DC.L    BREAK   ; DBG *****\r
+       DC.L    LIT16\r
+       DC.W    MAXNML  ; Why did I hard code this?\r
+*      DC.L    WIDTH,ONEP      ; Because WIDTH is a (USER) variable.\r
+       DC.L    LIT16\r
+       DC.W    '_'     ( underline )\r
+       DC.L    FILL,DUP,PFA,LFA,OVER,SUB,PAD\r
+*      DC.L    SWAP,CMOVE,PAD,COUNT,LIT16\r
+*      DC.W    NMLMSK\r
+       DC.L    SWAP,CMOVE,PAD\r
+       DC.L    IDFLAT\r
+       DC.L    COUNT,LIT16\r
+       DC.W    NMLMSK\r
+       DC.L    AND,TYPE,SPACE\r
+       DC.L    SEMIS\r
+*\r
+* ######>> screen 51 <<\r
+* ======>>  145  <<\r
+* ( --- )         { CREATE name } input\r
+* Parse a name (length < MAXNML characters) and create a header,\r
+* reporting first duplicate found in either the defining vocabulary\r
+* or the context (interpreting) vocabulary. \r
+* Install the header in the defining vocabulary\r
+* with CFA dangerously pointing to the parameter field.\r
+* Leave the name SMUDGEd.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $86\r
+       DC.B    'CREAT' ; 'CREATE'\r
+       DC.B    'E'|$80\r
+       DC.L    IDDOT-4-NATWID\r
+CREATE DC.L    DOCOL,DFIND,ZBRAN\r
+       DC.L    CREAT2-*-NATWID\r
+       DC.L    DROP,PDOTQ\r
+       DC.B    8\r
+       DC.B    7       ; ( bel )\r
+       DC.B    "redef: "\r
+       DC.B    0       ; hand align\r
+       DC.L    NFA,IDDOT,LIT16\r
+       DC.W    4\r
+       DC.L    MESS,SPACE\r
+*CREAT2        DC.L    HERE,DUP,CAT,WIDTH,AT,MIN       ; clip to WIDTH\r
+CREAT2 DC.L    BREAK,HERE,CAT,WIDTH,AT,MIN     ; clip to WIDTH, hold off copying HERE ; DBG *****\r
+* Make sure it ends up aligned by moving the name.\r
+* Note that we don't need to copy beyond WIDTH.\r
+       DC.L    DUP,HERE,PLUS,ONEP      ; tentative LFA\r
+       DC.L    ONE,AND,ZBRAN           ; Will LFA, as is, be even?\r
+       DC.L    CREATN-*-NATWID         ; will be even\r
+\r
+       DC.L    HERE,OVER,HERE,ONEP,SWAP,ONEP   ; source, destination, length including count\r
+       DC.L    CMOVD                   ; Use descending copy so it doesn't just fill.\r
+\r
+       DC.L    ZERO,CCOMM              ; insert a NUL byte, update HERE.\r
+\r
+* Now build header.\r
+CREATN DC.L    HERE,SWAP,ONEP,ALLOT,DUP,LIT16\r
+       DC.W    ($80|FSMUDG)            ; Bracket the name.\r
+       DC.L    TOGGLE\r
+       DC.L    HERE,ONE,SUB,LIT16\r
+       DC.W    $80\r
+       DC.L    TOGGLE\r
+       DC.L    LATEST,COMMA,CURENT,AT,STORE\r
+*      DC.L    HERE,TWOP,COMMA\r
+       DC.L    HERE,NATP,COMMA\r
+       DC.L    SEMIS\r
+*\r
+* ######>> screen 52 <<\r
+* ======>>  146  <<\r
+* ( --- )                                         P\r
+*                      { [COMPILE] name } typical use\r
+* -DFIND next WORD and COMPILE it, literally;\r
+* used to compile immediate definitions into words.\r
+       EVEN\r
+       DC.B    $C9     immediate\r
+       DC.B    '[COMPILE'      ; '[COMPILE]'\r
+       DC.B    ']'|$80\r
+       DC.L    CREATE-7-NATWID\r
+BCOMP  DC.L    DOCOL,DFIND,ZEQU,ZERO,QERR,DROP,CFA,COMMA\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  147  <<\r
+* ( n --- ) if compiling.                          P\r
+* ( n --- n ) if interpreting.\r
+* Compile n as a literal, if compiling.\r
+       EVEN\r
+       DC.B    $C7     immediate\r
+       DC.B    'LITERA'        ; 'LITERAL'\r
+       DC.B    'L'|$80\r
+       DC.L    BCOMP-10-NATWID\r
+LITER  DC.L    DOCOL,STATE,AT,ZBRAN\r
+       DC.L    LITER2-*-NATWID\r
+       DC.L    COMPIL,LIT,COMMA\r
+LITER2 DC.L    SEMIS\r
+*\r
+* ======>>  148  <<\r
+* ( d --- )  if compiling.                        P\r
+* ( d --- d ) if interpreting.\r
+* Compile d as a double literal, if compiling.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $C8     immediate\r
+       DC.B    'DLITERA'       ; 'DLITERAL'\r
+       DC.B    'L'|$80\r
+       DC.L    LITER-8-NATWID\r
+DLITER DC.L    DOCOL,STATE,AT,ZBRAN\r
+       DC.L    DLITE2-*-NATWID\r
+       DC.L    SWAP,LITER,LITER        ; Just two literals in the right order.\r
+DLITE2 DC.L    SEMIS\r
+*\r
+* ######>> screen 53 <<\r
+* ======>>  149  <<\r
+* ( --- )\r
+* Interpret or compile, according to STATE. \r
+* Searches words parsed in dictionary first, via -FIND,\r
+* then checks for valid NUMBER.\r
+* Pushes or COMPILEs double literal if NUMBER leaves DPL non-negative. \r
+* ERROR checks the stack via ?STACK before returning to its caller. \r
+       EVEN\r
+       DC.B    $89\r
+       DC.B    'INTERPRE'      ; 'INTERPRET'\r
+       DC.B    'T'|$80\r
+*      DC.L    LITER-8-NATWID\r
+       DC.L    DLITER-9-NATWID\r
+INTERP DC.L    DOCOL\r
+INTER2 DC.L    DFIND,ZBRAN\r
+       DC.L    INTER5-*-NATWID\r
+       DC.L    STATE,AT,LESS\r
+       DC.L    ZBRAN\r
+       DC.L    INTER3-*-NATWID\r
+       DC.L    CFA,COMMA,BRAN\r
+       DC.L    INTER4-*-NATWID\r
+INTER3 DC.L    CFA,EXEC\r
+INTER4 DC.L    BRAN\r
+       DC.L    INTER7-*-NATWID\r
+INTER5 DC.L    HERE,NUMB,DPL,AT,ONEP,ZBRAN\r
+       DC.L    INTER6-*-NATWID\r
+       DC.L    DLITER,BRAN\r
+       DC.L    INTER7-*-NATWID\r
+INTER6 DC.L    DROP,LITER\r
+INTER7 DC.L    QSTACK,BRAN\r
+*INTER7        DC.L    BREAK,QSTACK,BRAN       ; DBG\r
+       DC.L    INTER2-*-NATWID\r
+*      DC.L    SEMIS   never executed\r
+\r
+*\r
+* ######>> screen 54 <<\r
+* ======>>  150  <<\r
+* ( --- )\r
+* Toggle precedence bit of LATEST definition header. \r
+* During compiling, most symbols scanned are compiled. \r
+* IMMEDIATE definitions execute whenever the outer INTERPRETer scans them,\r
+* but may be compiled via ' (TICK).\r
+       EVEN\r
+       DC.B    $89\r
+       DC.B    'IMMEDIAT'      ; 'IMMEDIATE'\r
+       DC.B    'E'|$80\r
+       DC.L    INTERP-10-NATWID\r
+IMMED  DC.L    DOCOL,LATEST,LIT16\r
+       DC.W    FIMMED\r
+       DC.L    TOGGLE\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  151  <<\r
+* ( --- )         { VOCABULARY name } input\r
+* Create a vocabulary entry with a flag for terminating vocabulary searches.\r
+* Store the current search context in it for linking.\r
+* At run-time, VOCABULARY makes itself the CONTEXT vocabulary.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $8A\r
+       DC.B    'VOCABULAR'     ; 'VOCABULARY'\r
+       DC.B    'Y'|$80\r
+       DC.L    IMMED-10-NATWID\r
+VOCAB  DC.L    DOCOL,BUILDS,LIT,VOCFLG,COMMA,CURENT,AT,CFA\r
+       DC.L    COMMA,HERE,VOCLIN,AT,COMMA,VOCLIN,STORE,DOES\r
+* DOVOC        DC.L    TWOP,CONTXT,STORE\r
+DOVOC  DC.L    NATP,CONTXT,STORE\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  152  <<\r
+*\r
+* Note: FORTH does not go here in the rom-able dictionary,\r
+*    since FORTH is a type of variable.\r
+*\r
+* (Should make a proper architecture for this at some point.)\r
+*\r
+*\r
+* ======>>  153  <<\r
+* ( --- )\r
+* Makes the current interpretation CONTEXT vocabulary\r
+* also the CURRENT defining vocabulary.\r
+       EVEN\r
+       DC.B    $8B\r
+       DC.B    'DEFINITION'    ; 'DEFINITIONS'\r
+       DC.B    'S'|$80\r
+       DC.L    VOCAB-11-NATWID\r
+DEFIN  DC.L    DOCOL,CONTXT,AT,CURENT,STORE\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  154  <<\r
+* ( --- )\r
+* Parse out a comment and toss it away. \r
+* Leaves the leading characters in WORDPAD, which may or may not be useful.\r
+       EVEN\r
+       DC.B    $C1     immediate       (\r
+       DC.B    '('|$80\r
+       DC.L    DEFIN-12-NATWID\r
+PAREN  DC.L    DOCOL,LIT16\r
+       DC.W    ")"\r
+       DC.L    WORD\r
+       DC.L    SEMIS\r
+*\r
+* ######>> screen 55 <<\r
+* ======>>  155  <<\r
+* ( anything *** nothing )\r
+* Clear return stack. \r
+* Then INTERPRET and, if not compiling, prompt with OK,\r
+* in infinite loop.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $84\r
+       DC.B    'QUI'   ; 'QUIT'\r
+       DC.B    'T'|$80\r
+       DC.L    PAREN-2-NATWID\r
+QUIT   DC.L    DOCOL,ZERO,BLK,STORE\r
+       DC.L    BREAK   ; DBG ****\r
+       DC.L    LBRAK\r
+*\r
+*  Here is the outer interpretter\r
+*  which gets a line of input, does it, prints " OK"\r
+*  then repeats :\r
+QUIT2  DC.L    RPSTOR,CR,QUERY\r
+       DC.L    BREAK   ; DBG *****\r
+       DC.L    INTERP,STATE,AT,ZEQU\r
+       DC.L    ZBRAN\r
+       DC.L    QUIT3-*-NATWID\r
+       DC.L    PDOTQ\r
+       DC.B    3\r
+       DC.B    ' OK'   ; ' OK'\r
+QUIT3  DC.L    BRAN\r
+       DC.L    QUIT2-*-NATWID\r
+*      DC.L    SEMIS   ( never executed )\r
+*\r
+* ======>>  156  <<\r
+* ( anything --- nothing )        ( anything *** nothing )\r
+* Clear parameter stack,\r
+* set STATE to interpret and BASE to DECIMAL,\r
+* return to input from terminal,\r
+* restore DRIVE OFFSET to 0,\r
+* print out "Forth-68",\r
+* set interpret and define vocabularies to FORTH,\r
+* and finally, QUIT. \r
+* Used to force the system to a known state\r
+* and return control to the initial INTERPRETer.\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    'ABOR'  ; 'ABORT'\r
+       DC.B    'T'|$80\r
+       DC.L    QUIT-5-NATWID\r
+*ABORT DC.L    DOCOL,SPSTOR,DEC,QSTACK,DRZERO,CR,PDOTQ\r
+ABORT  DC.L    DOCOL,SPSTOR,DEC,QSTACK,DRZERO,CR,BREAK,PDOTQ\r
+       DC.B    15\r
+       DC.B    "fig-Forth-68000"\r
+*      DC.B    0       ; hand align\r
+       DC.L    FORTH,DEFIN\r
+*      DC.L    CR,TROFF,VLIST  ; (whole line is) DBG ****\r
+       DC.L    QUIT\r
+*      DC.L    SEMIS   never executed\r
+       PAGE\r
+*\r
+* ######>> screen 56 <<\r
+* bootstrap code... moves rom contents to ram :\r
+* ======>>  157  <<\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $84\r
+       DC.B    'COL'   ; 'COLD'\r
+       DC.B    'D'|$80\r
+       DC.L    ABORT-6-NATWID\r
+COLD   DC.L    *+NATWID\r
+* Ultimately, we want position indepence,\r
+* so I'm using PCR where it seems reasonable.\r
+* Time for some testing.\r
+CENT   MOVE.L  RINIT(PC),RP    ; Get a useable initial return stack,\r
+       MOVE.L  SINIT(PC),PSP   ; a useable initial parameter stack,\r
+*      MOVE.L  #IUP,UP         ; and a useable initial task base (not in init table).\r
+       MOVE.L  #UORIG,UP               ; and a useable initial task base (not in init table).\r
+*\r
+       LEA     ERAM(PC),A2     ; end of stuff to move, A2 as loop terminator\r
+       MOVE.L  #RBEG,A1        ; bottom of (open-ended) destination\r
+       LEA     RAM(PC),A0      ; bottom of stuff to move\r
+COLD2  MOVE.B  (A0)+,(A1)+     ; move TASK & FORTH to ram\r
+       CMP.L   A2,A0\r
+       BNE.S   COLD2\r
+* The above leaves USE and PREV uninitialized.\r
+       MOVE.L  BUFINT(PC),A2\r
+       MOVE.L  A2,XUSE-UORIG(UP)\r
+       MOVE.L  A2,XPREV-UORIG(UP)\r
+* ... or we could go top to bottom.\r
+* Definitely no need to use the return stack pointer like in the 6800 model,\r
+* nor to fiddle with it, since it is already pointing to a place that should be safe.\r
+       MOVE.L  COLINT(PC),XCOLUM-UORIG(UP)\r
+       MOVE.L  DELINT(PC),XDELAY-UORIG(UP)\r
+       MOVE.L  VOCINT(PC),XVOCL-UORIG(UP)\r
+       MOVE.L  DPINIT(PC),XDICTP-UORIG(UP)\r
+       MOVE.L  FENCIN(PC),XFENCE-UORIG(UP)\r
+*\r
+WENT   MOVE.L  RINIT(PC),RP    ; Get a useable initial return stack,\r
+       MOVE.L  SINIT(PC),PSP   ; a useable initial parameter stack,\r
+*      MOVE.L  #IUP,UP         ; and a useable initial task base (not in init table).\r
+       MOVE.L  #UORIG,UP               ; and a useable initial task base (not in init table).\r
+*\r
+       LEA     SINIT(PC),A2            ; for loop termination\r
+       LEA     XFENCE-UORIG(UP),A1     ; top of destination\r
+       LEA     FENCIN(PC),A0           ; top of stuff to move\r
+WARM2  MOVE.L  -(A0),-(A1)             ; All entries are 32 bit.\r
+       CMP.L   A2,A0\r
+       BNE.S   WARM2\r
+*\r
+       LEA     ABORT+NATWID(PC),IP     ; IP never points to DOCOL!\r
+*\r
+       NOP             ; Here is a place to jump to special user\r
+       NOP             ; initializations such as I/0 interrups\r
+       NOP\r
+*\r
+\r
+\r
+* For systems with TRACE:\r
+       CLR.L   (RP)            ; The hole above the return stack\r
+       CLR.L   (PSP)           ; The hole above the parameter stack\r
+       LEA     N(PC),A0\r
+       CLR.W   TRLIM-N(A0)     ; clear trace limit (all bytes)\r
+       CLR.W   TRACEM-N(A0)    ; and mode (all bytes)\r
+* DBG:\r
+*      ADDQ.W  #1,TRACEM-N(A0) ; DBG *******************\r
+       CLR.L   BRKPT-N(A0)     ; clear breakpoint address\r
+       BRA.W   RPSTOR+NATWID   ; start the virtual machine running !\r
+*      RPSTOR's NEXT will pick up the IP set above, and start ABORT.\r
+*      RP! sets up the return stack pointer, then IP references abort.\r
+\r
+* Comment out the branch above and use something like this to jump direct to test code:\r
+*      LEA     TESTMIN(PC),IP\r
+*      RTS\r
+\r
+*\r
+* Here is the stuff that gets copied to ram :\r
+* (not * at address $140:)\r
+* at an appropriate address:\r
+*\r
+* RAM  DC.L    $3000,$3000,0,0\r
+* RAM  DC.L    BUFBAS,BUFBAS,0,0       ; ... except the direct page has moved.\r
+* These initialization values for USE and PREV were here to help pack the code.\r
+* They don't belong here unless we move the USER table\r
+* back below the writable dictionary, \r
+* *and* move these USER variables to the end of the direct page --\r
+* *or* let these definitions exist in the USER table.\r
+RAM    EQU     *       ; Does RAM need to have the BUFfer BASe address before RFORTH?\r
+\r
+* ======>>  (152)  <<\r
+* ( --- )                                                 P\r
+* Makes FORTH the current interpretation vocabulary.\r
+* In order to make this ROMmable,\r
+* this entry is set up as the tail-end of its VOCABULARY,\r
+* and copied to RAM in the start-up code.\r
+* We want a more elegant solution to this, too. Greedy, maybe.\r
+       EVEN\r
+       DC.B    $C5     immediate\r
+       DC.B    'FORT'  ; 'FORTH'\r
+       DC.B    'H'|$80\r
+       DC.L    NOOP-5-NATWID   ; Note that this does not link to COLD!\r
+RFORTH DC.L    DODOES,DOVOC,VOCFLG,TASK-5-NATWID\r
+       DC.L    0\r
+       DC.B    "Copyright 1979 Forth Interest Group, David Lion,"\r
+       DC.B    $0D\r
+       DC.B    "Parts Copyright 2019 Joel Matthew Rees"\r
+       DC.B    $0D\r
+*\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $84\r
+       DC.B    'TAS'   ; 'TASK'\r
+       DC.B    'K'|$80\r
+       DC.L    FORTH-6-NATWID\r
+RTASK  DC.L    DOCOL,SEMIS\r
+ERAM   EQU     *\r
+ERAMSZ EQU     *-RAM   ; So we can get a look at it.\r
+*\r
+       PAGE\r
+* ######>> screen 57 <<\r
+* ======>>  158  <<\r
+* ( n0 --- d0 )\r
+* Sign extend n0 to a double integer.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $84\r
+       DC.B    'S->'   ; 'S->D'\r
+       DC.B    'D'|$80\r
+       DC.L    COLD-5-NATWID   ; Note that this does not link to FORTH (RFORTH)!\r
+STOD   DC.L    DOCOL,DUP,ZLESS,MINUS\r
+       DC.L    SEMIS\r
+\r
+\r
+*\r
+* ======>>  159  <<\r
+* ( multiplier multiplicand --- product )\r
+* Signed word multiply.\r
+       EVEN\r
+       DC.B    $81     ; *\r
+       DC.B    '*'|$80\r
+       DC.L    STOD-5-NATWID\r
+STAR   DC.L    DOCOL\r
+       DC.L    USTAR,DROP,SEMIS        ; Drop high word.\r
+* STAR DC.L    *+NATWID\r
+*      BSR.W   USTAR+NATWID\r
+*      LEA     NATWID(PSP),PSP ; Drop high word. Seems like magic, doesn't it?\r
+*      RTS\r
+*\r
+* ======>>  160  <<\r
+* ( dividend divisor --- remainder quotient )\r
+* M/ in word-only form, i. e., signed division of 2nd word by top word,\r
+* yielding signed word quotient and remainder.\r
+* Except *BUG* it isn't signed.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $84\r
+       DC.B    '/MO'   ; '/MOD'\r
+       DC.B    'D'|$80\r
+       DC.L    STAR-2-NATWID\r
+SLMOD  DC.L    DOCOL,TOR,STOD,FROMR,USLASH\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  161  <<\r
+* ( dividend divisor --- quotient )\r
+* Signed word divide without remainder.\r
+* Except *BUG* it isn't signed.\r
+       EVEN\r
+       DC.B    $81     ; /\r
+       DC.B    '/'|$80\r
+       DC.L    SLMOD-5-NATWID\r
+SLASH  DC.L    DOCOL,SLMOD,SWAP,DROP\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  162  <<\r
+* ( dividend divisor --- remainder )\r
+* Remainder function, result takes sign of dividend.\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'MO'    ; 'MOD'\r
+       DC.B    'D'|$80\r
+       DC.L    SLASH-2-NATWID\r
+MOD    DC.L    DOCOL,SLMOD,DROP\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  163  <<\r
+* ( multiplier multiplicand divisor --- remainder quotient )\r
+* Signed precise division of product:\r
+* multiply 2nd and 3rd words on stack\r
+* and divide the 31-bit product by the top word,\r
+* leaving both quotient and remainder.\r
+* Remainder takes sign of product. \r
+* Guaranteed not to lose significant bits in 16 bit integer math.\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    '*/MO'  ; '*/MOD'\r
+       DC.B    'D'|$80\r
+       DC.L    MOD-4-NATWID\r
+SSMOD  DC.L    DOCOL,TOR,USTAR,FROMR,USLASH\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  164  <<\r
+* ( multiplier multiplicand divisor --- quotient )\r
+*   */MOD without remainder.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    '*'     ; '*/'\r
+       DC.B    '/'|$80\r
+       DC.L    SSMOD-6-NATWID\r
+SSLASH DC.L    DOCOL,SSMOD,SWAP,DROP\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  165  <<\r
+* ( ud1 u1 --- u2 ud2 )\r
+* U/ with an (unsigned) double quotient. \r
+* Guaranteed not to lose significant bits in 32 bit / 16 bit bit integer math,\r
+* if you are prepared to deal with the extra 16 bits of result.\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    'M/MO'  ; 'M/MOD'\r
+       DC.B    'D'|$80\r
+       DC.L    SSLASH-3-NATWID\r
+MSMOD  DC.L    DOCOL,TOR,ZERO,R,USLASH\r
+       DC.L    FROMR,SWAP,TOR,USLASH,FROMR\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  166  <<\r
+* ( n>=0 --- n )\r
+* ( n<0 --- -n )\r
+* Convert the top of stack to its absolute value.\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'AB'    ; 'ABS'\r
+       DC.B    'S'|$80\r
+       DC.L    MSMOD-6-NATWID\r
+ABS    DC.L    DOCOL,DUP,ZLESS,ZBRAN\r
+       DC.L    ABS2-*-NATWID\r
+       DC.L    MINUS\r
+ABS2   DC.L    SEMIS\r
+*\r
+* ======>>  167  <<\r
+* ( d>=0 --- d )\r
+* ( d<0 --- -d )\r
+* Convert the top double to its absolute value.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $84\r
+       DC.B    'DAB'   ; 'DABS'\r
+       DC.B    'S'|$80\r
+       DC.L    ABS-4-NATWID\r
+DABS   DC.L    DOCOL,DUP,ZLESS,ZBRAN\r
+       DC.L    DABS2-*-NATWID\r
+       DC.L    DMINUS\r
+DABS2  DC.L    SEMIS\r
+*\r
+       PAGE\r
+* ######>> screen 58 <<\r
+* Disc primitives :\r
+* ======>>  168  <<\r
+* ( --- vadr )   \r
+* Least Recently Used buffer.\r
+* Really should be with FIRST and LIMIT in the per-task table.\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'US'    ; 'USE'\r
+       DC.B    'E'|$80\r
+       DC.L    DABS-5-NATWID\r
+USE    DC.L    DOCON\r
+       DC.L    XUSE    ; The address of XUSE is the constant.\r
+* ======>>  169  <<\r
+* ( --- vadr )   \r
+* Most Recently Used buffer.\r
+* Really should be with FIRST and LIMIT in the per-task table.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $84\r
+       DC.B    'PRE'   ; 'PREV'\r
+       DC.B    'V'|$80\r
+       DC.L    USE-4-NATWID\r
+PREV   DC.L    DOCON\r
+       DC.L    XPREV   ; The address of XPREV is the constant.\r
+* ======>>  170  <<\r
+* ( buffer1 --- buffer2 f )\r
+* Bump to next buffer,\r
+* flag false if result is PREVious buffer,\r
+* otherwise flag true. \r
+* Used in the LRU allocation routines.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $84\r
+       DC.B    '+BU'   ; '+BUF'\r
+       DC.B    'F'|$80\r
+       DC.L    PREV-5-NATWID\r
+* PBUF DC.L    DOCOL,LIT16\r
+*      DC.W    $84     ; This was a hard-wiring bug.\r
+PBUF   DC.L    DOCOL,BBUF,BCTL,PLUS    ; Size of the buffer record.\r
+*      DC.L    PLUS,DUP,LIMIT,EQUAL,ZBRAN\r
+       DC.L    PLUS,DUP,LIMIT,LESS,ZEQU,OVER,FIRST,LESS,OR,ZBRAN\r
+       DC.L    PBUF2-*-NATWID  ; Use defensive programming.\r
+       DC.L    DROP,FIRST\r
+PBUF2  DC.L    DUP,PREV,AT,SUB\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  171  <<\r
+*\r
+UPDATB EQU     $80000000       ; $8000 in the 6800 model -- puts limits on sector count.\r
+*\r
+* ( --- f )\r
+* Flag to mark a buffer dirty, in need of being written out.\r
+* This flag limits the max number of sectors in a disk to ((256^NATWID)/2)-1.\r
+* It also hard-codes an implicit test which is used elsewhere.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $8A\r
+       DC.B    'UPDATE-BI'     ; 'UPDATE-BIT'\r
+       DC.B    'T'|$80\r
+       DC.L    PBUF-5-NATWID\r
+UPDBIT DC.L    DOCON\r
+       DC.L    UPDATB\r
+*\r
+* ( --- )\r
+* Mark PREVious buffer dirty, in need of being written out.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $86\r
+       DC.B    'UPDAT' ; 'UPDATE'\r
+       DC.B    'E'|$80\r
+       DC.L    UPDBIT-11-NATWID\r
+* UPDATE       DC.L    DOCOL,PREV,AT,AT,LIT,UPDATB,OR,PREV,AT,STORE\r
+UPDATE DC.L    DOCOL,PREV,AT,AT,UPDBIT,OR,PREV,AT,STORE\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  172  <<\r
+*\r
+* Going to leave the 0 sector bug in place, I guess. Maybe.\r
+* ( adr --- )\r
+** Mark the buffer addressed as empty.\r
+** Have to add code to avoid block 0 appearing to be in a buffer from COLD.\r
+** Usually, there is no sector 0 (?), but the RAM buffers are too simple.\r
+** Note that without this block number being made illegal, \r
+** about 8 binaryMegabytes (256 bytes/block) of disk can be addressed total.\r
+** With this block number made illegal, the max is 1 block less,\r
+** still about 8 biMeg.\r
+*      EVEN\r
+*      DC.B    $8B\r
+*      DC.B    'KILL-BUFFE'    ; 'KILL-BUFFER'\r
+*      DC.B    'R'|$80\r
+*      DC.L    UPDATE-7-NATWID\r
+*KILBUF        DC.L    *+NATWID        ; DOCOL,UPDBIT,ONE,SUB,SWAP,STORE\r
+*      MOVE.L  (PSP)+,A0       \r
+*      MOVE.L  UPDBIT+NATWID(PC),D0\r
+*      SUBQ.L  #1,D0\r
+*      MOVE.L  D0,(A0)\r
+*      RTS\r
+*\r
+* ( --- )\r
+* Mark all buffers empty. \r
+*      EVEN\r
+*      DC.B    0\r
+*      DC.B    $8C\r
+*      DC.B    'KILL-BUFFER'   ; 'KILL-BUFFERS'\r
+*      DC.B    'S'|$80\r
+*      DC.L    KILBUF-12-NATWID\r
+*KLBFS DC.L    DOCOL,FIRST,LIT16\r
+*      DC.W    4       ; Want to make sure it's only four.\r
+*      DC.L    ZERO,XDO        ; It would be "cleaner" to let +BUF control the loop.\r
+*      DC.L    DUP,KILBUF,PBUF,DROP,XLOOP\r
+*      DC.L    DROP,SEMIS\r
+** KLBFS       DC.L    *+NATWID\r
+**     LDD     #4\r
+**     PSHU    D\r
+**     LDD     FIRST+NATWID,PCR\r
+**     INC     <TRACEM\r
+**     LBSR    DBGREG\r
+**     PSHU    D       ; DUP\r
+** KLBFSL      PSHU    D\r
+**     BSR     KILBUF+NATWID\r
+**     LDD     ,U      \r
+**     LBSR    DBGREG\r
+**     ADDD    BBUF+NATWID,PCR\r
+**     ADDD    BCTL+NATWID,PCR\r
+**     STD     ,U\r
+**     LBSR    DBGREG\r
+**     DEC     NATWID+1,U\r
+**     BNE     KLBFSL\r
+**     LBSR    DBGREG\r
+**     LEAU    NATWID*2,U\r
+**     DEC     <TRACEM\r
+**     LBRA    NEXT\r
+*\r
+* ( --- )\r
+* Erase and mark all buffers empty. \r
+* Standard method of discarding changes.\r
+       EVEN\r
+       DC.B    $8D\r
+       DC.B    'EMPTY-BUFFER'  ; 'EMPTY-BUFFERS'\r
+       DC.B    'S'|$80\r
+*      DC.L    KLBFS-13-NATWID\r
+       DC.L    UPDATE-7-NATWID\r
+MTBUF  DC.L    DOCOL,FIRST,LIMIT,OVER,SUB,ERASE\r
+*      DC.L    FIRST,DUP,KILBUF,PBUF,DROP,DUP,KILBUF\r
+*      DC.L    PBUF,DROP,DUP,KILBUF,PBUF,DROP,KILBUF\r
+*      DC.L    KLBFS\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  173  <<\r
+* ( --- )\r
+* Clear the current offset to the block numbers in the drive interface.\r
+* The drives need to be re-architected.\r
+* Would be cool to have RAM and ROM drives supported\r
+* in addition to regular physical persistent store.\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'DR'    ; 'DR0'\r
+       DC.B    '0'|$80\r
+       DC.L    MTBUF-14-NATWID\r
+DRZERO DC.L    DOCOL,ZERO,OFSET,STORE\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  174  <<== system dependant word\r
+* ( --- )\r
+* Set the current offset in the drive interface to reference the second drive.\r
+* The hard-coded number in there needs to be in a table.\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'DR'    ; 'DR1'\r
+       DC.B    '1'|$80\r
+       DC.L    DRZERO-4-NATWID\r
+*DRONE DC.L    DOCOL,LIT,$07D0,OFSET,STORE     \r
+; **** hard-codes the size of the disc !!!!\r
+DRONE  DC.L    DOCOL,LIT,RAMDSZ,OFSET,STORE\r
+       DC.L    SEMIS\r
+*\r
+* ######>> screen 59 <<\r
+* ======>>  175  <<\r
+* ( n --- buffer )\r
+* Get a free buffer,\r
+* assign it to block n,\r
+* return buffer address.\r
+* Will free a buffer by writing it, if necessary. \r
+* Does not actually read the block. \r
+* A bug in the fig LRU algorithm, which I have not fixed,\r
+* gives the PREVious buffer if USE gets set to PREVious.\r
+* (The bug is that USE sometimes gets set to PREVious.) \r
+* This bug sometimes causes sector moves to become sector fills.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $86\r
+       DC.B    'BUFFE' ; 'BUFFER'\r
+       DC.B    'R'|$80\r
+       DC.L    DRONE-4-NATWID\r
+BUFFER DC.L    DOCOL,USE,AT,DUP,TOR\r
+BUFFR2 DC.L    PBUF,ZBRAN\r
+       DC.L    BUFFR2-*-NATWID\r
+       DC.L    USE,STORE,R,AT,ZLESS\r
+       DC.L    ZBRAN\r
+       DC.L    BUFFR3-*-NATWID\r
+*      DC.L    R,TWOP,R,AT,LIT,$7FFF,AND,ZERO,RW\r
+       DC.L    R,NATP,R,AT,UPDBIT,LNOT,AND,ZERO,RW\r
+* BUFFR3       DC.L    R,STORE,R,PREV,STORE,FROMR,TWOP\r
+BUFFR3 DC.L    R,STORE,R,PREV,STORE,FROMR,NATP\r
+       DC.L    SEMIS\r
+*\r
+* ######>> screen 60 <<\r
+* ======>>  176  <<\r
+* ( n --- buffer )\r
+* Get BUFFER containing block n, relative to OFFSET. \r
+* If block n is not in a buffer, bring it in. \r
+* Returns buffer address.\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    'BLOC'  ; 'BLOCK'\r
+       DC.B    'K'|$80\r
+       DC.L    BUFFER-7-NATWID\r
+BLOCK  DC.L    DOCOL,OFSET,AT,PLUS,TOR\r
+       DC.L    PREV,AT,DUP,AT,R,SUB,DUP,PLUS,ZBRAN\r
+       DC.L    BLOCK5-*-NATWID\r
+BLOCK3 DC.L    PBUF,ZEQU,ZBRAN\r
+       DC.L    BLOCK4-*-NATWID\r
+*      DC.L    DROP,R,BUFFER,DUP,R,ONE,RW,TWO,SUB\r
+       DC.L    DROP,R,BUFFER,DUP,R,ONE,RW,NATWC,SUB\r
+BLOCK4 DC.L    DUP,AT,R,SUB,DUP,PLUS,ZEQU,ZBRAN\r
+       DC.L    BLOCK3-*-NATWID\r
+       DC.L    DUP,PREV,STORE\r
+* BLOCK5       DC.L    FROMR,DROP,TWOP\r
+BLOCK5 DC.L    FROMR,DROP,NATP\r
+       DC.L    SEMIS\r
+*\r
+* ######>> screen 61 <<\r
+* ======>>  177  <<\r
+* ( line screen --- buffer C/L)\r
+* Bring in the sector containing the specified line of the specified screen. \r
+* Returns the buffer address and the width of the screen. \r
+* Screen number is relative to OFFSET. \r
+* The line number may be beyond screen 4,\r
+* (LINE) will get the appropriate screen.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $86\r
+       DC.B    '(LINE' ; '(LINE)'\r
+       DC.B    ')'|$80\r
+       DC.L    BLOCK-6-NATWID\r
+PLINE  DC.L    DOCOL,TOR,LIT16\r
+       DC.W    $40\r
+       DC.L    BBUF,SSMOD,FROMR,BSCR,STAR,PLUS,BLOCK,PLUS,LIT16\r
+       DC.W    $40\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  178  <<\r
+* ( line screen --- )\r
+* Print the line of the screen as found by (LINE), suppress trailing BLANKS.\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    '.LIN'  ; '.LINE'\r
+       DC.B    'E'|$80\r
+       DC.L    PLINE-7-NATWID\r
+DLINE  DC.L    DOCOL,PLINE,DTRAIL,TYPE\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  179  <<\r
+* ( n --- )\r
+* If WARNING is 0, print "MESSAGE #n";\r
+* otherwise, print line n relative to screen 4,\r
+* the line number may be negative. \r
+* Uses .LINE, but counter-adjusts to be relative to the real drive 0.\r
+* BUG: -DUP will cause this to reach farther into the stack than the error number \r
+* when WARNING is set and err# is zero (can't find entry in dictionary).\r
+       EVEN\r
+       DC.B    $87\r
+       DC.B    'MESSAG'        ; 'MESSAGE'\r
+       DC.B    'E'|$80\r
+       DC.L    DLINE-6-NATWID\r
+MESS   DC.L    DOCOL,WARN,AT,ZBRAN\r
+       DC.L    MESS3-*-NATWID\r
+       DC.L    DDUP,ZBRAN      ; -DUP here is a bug from the original 6800 model, at least.\r
+       DC.L    MESS3-*-NATWID\r
+       DC.L    LIT16\r
+       DC.W    4\r
+       DC.L    OFSET,AT,BSCR,SLASH,SUB,DLINE,BRAN\r
+       DC.L    MESS4-*-NATWID\r
+MESS3  DC.L    PDOTQ\r
+       DC.B    6\r
+       DC.B    'err # '        ; 'err # '\r
+       DC.B    0       ; hand align\r
+       DC.L    DOT\r
+MESS4  DC.L    SEMIS\r
+*\r
+* ======>>  180  <<\r
+* ( n --- )\r
+* Begin interpretation of screen (block) n. \r
+* See also ARROW, SEMIS, and NULL.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $84\r
+       DC.B    'LOA'   ; 'LOAD' :      input:scr #\r
+       DC.B    'D'|$80\r
+       DC.L    MESS-8-NATWID\r
+LOAD   DC.L    DOCOL,BLK,AT,TOR,IN,AT,TOR,ZERO,IN,STORE\r
+       DC.L    BSCR,STAR,BLK,STORE\r
+       DC.L    INTERP,FROMR,IN,STORE,FROMR,BLK,STORE\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  181  <<\r
+* ( --- )                                                 P\r
+* Continue interpreting source code on the next screen.\r
+       EVEN\r
+       DC.B    $C3\r
+       DC.B    '--'    ; '-->'\r
+       DC.B    '>'|$80\r
+       DC.L    LOAD-5-NATWID\r
+ARROW  DC.L    DOCOL,QLOAD,ZERO,IN,STORE,BSCR\r
+       DC.L    BLK,AT,OVER,MOD,SUB,BLK,PSTORE\r
+       DC.L    SEMIS\r
+*\r
+       PAGE\r
+*\r
+* ######>> screen 63 <<\r
+*    The next clot of subroutines are machine dependent.\r
+*    PEMIT, PKEY, PQTER, and PCR (_P_arenthetic versions) are called by\r
+*    EMIT, KEY, QTERM, and CR, words 13 through 16 in the dictionary.\r
+*    This is all native CPU code.\r
+*\r
+* ATARI BIOS call parameters on _A7_ == SP. (Not PSP!)\r
+* Defining for Atari ST BIOS:\r
+* Atari BIOS messes with D0-D2/A0-A2.\r
+* We do not know D0/D1/A0/A1 are safe to overwrite in our runtime.\r
+*\r
+* ======>>  185  << code for CR\r
+* ( --- ) No stack effect.\r
+* Output a CR/LF combo to the CONSOLE device \r
+* using the Atari ST BIOS.\r
+* Move this here to keep it in reach of short branch.\r
+PCR    MOVEM.L D1,-(SP)        Don't destroy D1.\r
+       MOVE.W  #$0D,D1\r
+       BSR.S   PEMIT\r
+       MOVE.W  #$0A,D1\r
+       BSR.S   PEMIT   ; Don't rob PEMIT's return.\r
+       MOVEM.L (SP)+,D1        ; Restore D1\r
+       RTS\r
+*\r
+* ( --- ) No parameter stack effect.\r
+* Assume volatile registers saved,\r
+* Use Atari terminal emulation to turn the text cursor on.\r
+PCURON MOVEM.L D1,-(SP)        Don't destroy D1.\r
+       MOVE.W  #$1B,D1\r
+       BSR.S   PEMIT\r
+       MOVE.W  #'e',D1\r
+       BSR.S   PEMIT   ; Don't rob PEMIT's return.\r
+       MOVEM.L (SP)+,D1        ; Restore D1\r
+       RTS     \r
+*\r
+* ( --- ) No parameter stack effect.\r
+* Assume volatile registers saved,\r
+* Use Atari terminal emulation to turn the text cursor off.\r
+PCROFF MOVEM.L D1,-(SP)        Don't destroy D1.\r
+       MOVE.W  #$1B,D1\r
+       BSR.S   PEMIT\r
+       MOVE.W  #'f',D1\r
+       BSR.S   PEMIT   ; Don't rob PEMIT's return.\r
+       MOVEM.L (SP)+,D1        ; Restore D1\r
+       RTS     \r
+*\r
+* ======>>  182  << code for EMIT\r
+* ( --- ) No parameter stack effect.\r
+* Put one byte from D1 out on the CONSOLE device\r
+* using Atari ST BIOS.\r
+PEMIT  MOVEM.L D0/D1/D2/A0/A1/A2,-(PSP)        ; Save volatile registers, D0 lowest.\r
+       LEA     -6(SP),SP       ; allocate BIOS parameter space\r
+PEMITW MOVE.W  #2,2(SP)        ; console device\r
+       MOVE.W  #8,(SP)         ; bcostat\r
+       TRAP    #13             ; BIOS call\r
+       TST.L   D0              ; not really necessary?\r
+       BEQ.S   PEMITW          ; wait for CONSOLE out ready\r
+       MOVE.W  NATWID+NATWID/2(PSP),4(SP)      ; low word of PSP top is character to output\r
+       MOVE.W  #2,2(SP)        ; console device\r
+       MOVE.W  #3,(SP)         ; bconout\r
+       TRAP    #13             ; BIOS call\r
+       LEA     6(SP),SP        ; deallocate BIOS workspace\r
+       MOVEM.L (PSP)+,D0/D1/D2/A0/A1/A2        ; Restore volatile registers and parameter stack.\r
+       RTS\r
+*\r
+* ======>>  183  << code for KEY\r
+* ( --- ) No parameter stack effect.\r
+* Wait for one keypress from the CONSOLE device\r
+* and return the character code for the key pressed in D1\r
+* using Atari ST BIOS.\r
+PKEY   MOVEM.L D0/D2/A0/A1/A2,-(PSP)   ; Save volatile registers.\r
+       BSR.S   PCURON          ; Show the cursor\r
+PKEYG  MOVE.W  #2,-(SP)        ; console device\r
+       MOVE.W  #2,-(SP)        ; bconin\r
+       TRAP    #13             ; BIOS call\r
+       LEA     4(SP),SP        ; clean up stack\r
+PKEYT  BSR.S   PCROFF\r
+       CMP.B   #3,D0           ; CTL-C? (Atari BIOS emulates a nice terminal.)\r
+       BNE.S   PKEYX\r
+       OR.L    #$FFFFFF00,D0   ; set the N flag\r
+PKEYX  MOVE.L  D0,D1           ; KEY and QTERM expect it in D1.\r
+       MOVEM.L (PSP)+,D0/D2/A0/A1/A2   ; Restore registers without touching flags.\r
+       RTS\r
+*\r
+* ######>> screen 64 <<\r
+* ======>>  184  << code for ?TERMINAL\r
+* ( --- ) No stack effect.\r
+* Check for break key on the CONSOLE device without waiting\r
+* using Atari ST BIOS.\r
+PQTER  MOVEM.L D0/D2/A0/A1/A2,-(PSP)   ; Save D2.\r
+       MOVE.W  #2,-(SP)        ; console device\r
+       MOVE.W  #1,-(SP)        ; bconstat\r
+       TRAP    #13             ; BIOS call\r
+       LEA     4(SP),SP        ; clean up stack, don't wait\r
+       TST.L   D0              ; Got a key?\r
+       BMI.S   PKEYG           ; Get the key, but D2 already saved.\r
+       BRA.S   PKEYX           ; Rob PKEY's tail and restore.\r
+*\r
+* ######>> screen 66 <<\r
+* ======>>  187  <<\r
+* ( ??? )\r
+* Query the disk, I suppose.\r
+* Not sure what the model had in mind for this stub.\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    '?DIS'  ; '?DISC'\r
+       DC.B    'C'|$80\r
+       DC.L    ARROW-4-NATWID\r
+QDISC  DC.L    *+NATWID\r
+       JMP     NEXT\r
+*\r
+* ######>> screen 67 <<\r
+* ======>>  189  <<\r
+* ( ??? )\r
+* Write one block of data to disk.\r
+* Parameters unspecified in model. Stub in model.\r
+       EVEN\r
+       DC.B    $8B\r
+       DC.B    'BLOCK-WRIT'    ; 'BLOCK-WRITE'\r
+       DC.B    'E'|$80\r
+       DC.L    QDISC-6-NATWID\r
+BWRITE DC.L    *+NATWID\r
+       JMP     NEXT\r
+*\r
+* ######>> screen 68 <<\r
+* ======>>  190  <<\r
+* ( ??? )\r
+* Read one block of data from disk.\r
+* Parameters unspecified in model. Stub in model.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $8A\r
+       DC.B    'BLOCK-REA'     ; 'BLOCK-READ'\r
+       DC.B    'D'|$80\r
+       DC.L    BWRITE-12-NATWID\r
+BREAD  DC.L    *+NATWID\r
+       JMP     NEXT\r
+*\r
+*The next 3 words are written to create a substitute for disc\r
+* mass memory,located between MASSLO & MASSHI in ram --\r
+* ($3210 and $3fff in the 6800 model).\r
+* ======>>  190.1  <<\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    'L'     ; 'LO'\r
+       DC.B    'O'|$80\r
+       DC.L    BREAD-11-NATWID\r
+LO     DC.L    DOCON\r
+       DC.L    MEMEND  a system dependent equate at front\r
+*\r
+* ======>>  190.2  <<\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    'H'     ; 'HI'\r
+       DC.B    'I'|$80\r
+       DC.L    LO-3-NATWID\r
+HI     DC.L    DOCON\r
+       DC.L    MEMTOP  ( $3FFF or $7FFF in this version )\r
+*\r
+* ######>> screen 69 <<\r
+* ======>>  191  <<\r
+* ( buffer sector f --- )\r
+* Read or Write the specified (absolute -- ignores OFFSET) sector\r
+* from or to the specified buffer. \r
+* A zero flag specifies write,\r
+* non-zero specifies read. \r
+* Sector is an unsigned integer,\r
+* buffer is the buffer's address. \r
+* Will need to use the CoCo ROM disk routines. \r
+* For now, provides a virtual disk in RAM.\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'R/'    ; 'R/W'\r
+       DC.B    'W'|$80\r
+       DC.L    HI-3-NATWID\r
+RW     DC.L    DOCOL,TOR,BBUF,STAR,LO,PLUS,DUP,HI,GREAT,ZBRAN\r
+       DC.L    RW2-*-NATWID\r
+       DC.L    PDOTQ\r
+       DC.B    8\r
+       DC.B    ' Range ?'      ; ' Range ?'\r
+       DC.B    0       ; hand align\r
+       DC.L    QUIT\r
+RW2    DC.L    FROMR,ZBRAN\r
+       DC.L    RW3-*-NATWID\r
+       DC.L    SWAP\r
+RW3    DC.L    BBUF,CMOVE\r
+       DC.L    SEMIS\r
+*\r
+* From BIF-6809:\r
+* RW   PSHS Y,U,DP\r
+*      LDY $C006 control table\r
+*      LDX #DROFFS+7   ; This is BIF's table of drive sizes.\r
+*      LDD 2,U\r
+* RWD  SUBD ,X++ sectors\r
+*      BHS RWD\r
+*      BVC RWR table end?\r
+*      LDD #6\r
+*      PSHU D\r
+*      JMP ERROR\r
+* RWR  ADDD ,--X back one\r
+*      PSHS X\r
+*      PSHU D\r
+*      LDD #18 sectors/track\r
+*      PSHU D\r
+*      DOCOL\r
+*      FDB SLAMOD\r
+*      FDB XMACH\r
+*      PULU D\r
+*      STB 2,Y track\r
+*      PULU D\r
+*      INCB\r
+*      STB 3,Y sector\r
+*      PULS D table entry\r
+*      SUBD #DROFFS+7\r
+*      ASRB drive #\r
+*      STB 1,Y\r
+*      LDD 4,U buffer\r
+*      STD 4,Y\r
+*      LDB #2 coco READ\r
+*      LDX ,U 0?\r
+*      BNE *+3\r
+*      INCB coco WRITE\r
+*      STB ,Y op code\r
+*      CLRA\r
+*      TFR A,DP\r
+*      JSR [$C004]     ROM handles timeout\r
+*      PULS Y,U,DP     if IRQ enabled\r
+*      LEAU 6,U\r
+*      LDX $C006\r
+*      LDB 6,X coco status\r
+*      BEQ RWE\r
+*      LDX <UP\r
+*      LDD #0 no disc\r
+*      STD UWARN,X\r
+*      LDD #8\r
+*      PSHU D\r
+*      JMP ERROR\r
+* RWE  NEXT\r
+*\r
+       PAGE\r
+*\r
+* ######>> screen 72 <<\r
+* ======>>  192  <<\r
+* ( --- ) compiling                                       P\r
+* ( --- adr ) interpreting\r
+* { ' name } input\r
+* Parse a symbol name from input and search the dictionary for it, per -FIND;\r
+* compile the address as a literal if compiling,\r
+* otherwise just push it. \r
+       EVEN\r
+       DC.B    $C1     ; immediate\r
+       DC.B    "'"|$80 ; '     ( tick )\r
+       DC.L    RW-4-NATWID\r
+TICK   DC.L    DOCOL,DFIND,ZEQU,ZERO,QERR,DROP,LITER\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  193  <<\r
+* ( --- ) { FORGET name } input\r
+* Parse out name of definition to FORGET to, -DFIND it,\r
+* then lop it and everything that follows out of the dictionary. \r
+* In fig Forth, CURRENT and CONTEXT have to be the same to FORGET.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $86\r
+       DC.B    'FORGE' ; 'FORGET'\r
+       DC.B    'T'|$80\r
+       DC.L    TICK-2-NATWID\r
+FORGET DC.L    DOCOL,CURENT,AT,CONTXT,AT,SUB,LIT16\r
+       DC.W    $18\r
+       DC.L    QERR,TICK,DUP,FENCE,AT,LESS,LIT16\r
+       DC.W    $15\r
+       DC.L    QERR,DUP,ZERO,PORIG,GREAT,LIT16\r
+       DC.W    $15\r
+       DC.L    QERR,DUP,NFA,DICTPT,STORE,LFA,AT,CONTXT,AT,STORE\r
+       DC.L    SEMIS\r
+*\r
+* ######>> screen 73 <<\r
+* ======>>  194  <<\r
+*  ( adr --- )                                             C\r
+* Calculate a back reference from HERE and compile it. \r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $84\r
+       DC.B    'BAC'   ; 'BACK'\r
+       DC.B    'K'|$80\r
+       DC.L    FORGET-7-NATWID\r
+* BACK DC.L    DOCOL,HERE,SUB,COMMA\r
+BACK   DC.L    DOCOL,HERE,NATP,SUB,COMMA\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  195  <<\r
+* ( --- )   runtime\r
+* typical use: BEGIN code-loop test UNTIL  \r
+* typical use: BEGIN code-loop AGAIN  \r
+* typical use: BEGIN code-loop test WHILE code-true REPEAT  \r
+* ( --- adr n )  compile time                       P,C\r
+* Push HERE for BACK reference for general (non-counting) loops,\r
+* with BEGIN construct flag.\r
+* A better flag: $4245 (ASCII for 'BE').\r
+       EVEN\r
+       DC.B    $C5\r
+       DC.B    'BEGI'  ; 'BEGIN'\r
+       DC.B    'N'|$80\r
+       DC.L    BACK-5-NATWID\r
+BEGIN  DC.L    DOCOL,QCOMP,HERE,ONE    ; ONE is a flag for BEGIN loops.\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  196  <<\r
+* ( --- )   runtime\r
+* typical use: test IF code-true ELSE code-false ENDIF \r
+* ENDIF is just a sort of intersection piece, \r
+* marking where execution resumes after both branches.\r
+* ( adr n --- ) compile time\r
+* Check the mark and resolve the IF.\r
+* A better flag: $4846 (ASCII for 'IF').\r
+       EVEN\r
+       DC.B    $C5\r
+       DC.B    'ENDI'  ; 'ENDIF'\r
+       DC.B    'F'|$80\r
+       DC.L    BEGIN-6-NATWID\r
+ENDIF  DC.L    DOCOL,QCOMP,TWO,QPAIRS,HERE     ; This TWO is a flag for IF.\r
+*      DC.L    OVER,SUB,SWAP,STORE\r
+       DC.L    OVER,NATP,SUB,SWAP,STORE\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  197  <<\r
+* ( --- )   runtime\r
+* typical use: test IF code-true ELSE code-false ENDIF \r
+* ( adr n --- ) \r
+* Alias for ENDIF .\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $C4\r
+       DC.B    'THE'   ; 'THEN'\r
+       DC.B    'N'|$80\r
+       DC.L    ENDIF-6-NATWID\r
+THEN   DC.L    DOCOL,ENDIF\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  198  <<\r
+* ( limit index --- )   runtime\r
+* typical use: DO code-loop LOOP  \r
+* typical use: DO code-loop increment +LOOP\r
+* Counted loop, index is initial value of index.\r
+* Will loop until index equals (positive going)\r
+* or passes (negative going) limit.\r
+*  ( --- adr n )  compile time                        P,C\r
+* Compile (DO), push HERE for BACK reference,\r
+* and push DO control construct flag.\r
+* A better flag: $444F (ASCII for 'DO').\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $C2\r
+       DC.B    'D'     ; 'DO'\r
+       DC.B    'O'|$80\r
+       DC.L    THEN-5-NATWID\r
+DO     DC.L    DOCOL,COMPIL,XDO,HERE,THREE     ; THREE is a flag for DO loops.\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  199  <<\r
+* ( --- )   runtime\r
+* typical use: DO code-loop LOOP  \r
+* Increments the index by one and branches back to beginning of loop.\r
+* Will loop until index equals limit.\r
+* ( adr n --- )  compile time                        P,C\r
+* Check the mark and compile (LOOP), fill in BACK reference.\r
+* A better flag: $444F (ASCII for 'DO').\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $C4\r
+       DC.B    'LOO'   ; 'LOOP'\r
+       DC.B    'P'|$80\r
+       DC.L    DO-3-NATWID\r
+LOOP   DC.L    DOCOL,THREE,QPAIRS,COMPIL,XLOOP,BACK    ; THREE for DO loops.\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  200  <<\r
+* ( n --- )   runtime\r
+* typical use: DO code-loop increment +LOOP\r
+* Increments the index by n and branches back to beginning of loop.\r
+* Will loop until index equals (positive going)\r
+* or passes (negative going) limit.\r
+* ( adr n --- )  compile time                       P,C\r
+* Check the mark and compile (+LOOP), fill in BACK reference.\r
+* A better flag: $444F (ASCII for 'DO').\r
+       EVEN\r
+       DC.B    $C5\r
+       DC.B    '+LOO'  ; '+LOOP'\r
+       DC.B    'P'|$80\r
+       DC.L    LOOP-5-NATWID\r
+PLOOP  DC.L    DOCOL,THREE,QPAIRS,COMPIL,XPLOOP,BACK   ; THREE for DO loops.\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  201  <<\r
+* ( n --- )   runtime\r
+* typical use: BEGIN code-loop test UNTIL  \r
+* Will loop until UNTIL tests true.\r
+* ( adr n --- )  compile time                      P,C\r
+* Check the mark and compile (0BRANCH), fill in BACK reference.\r
+* A better flag: $4245 (ASCII for 'BE').\r
+       EVEN\r
+       DC.B    $C5\r
+       DC.B    'UNTI'  ; 'UNTIL' :     ( same as END )\r
+       DC.B    'L'|$80\r
+       DC.L    PLOOP-6-NATWID\r
+UNTIL  DC.L    DOCOL,ONE,QPAIRS,COMPIL,ZBRAN,BACK      ; ONE for BEGIN loops.\r
+       DC.L    SEMIS\r
+*\r
+* ######>> screen 74 <<\r
+* ======>>  202  <<\r
+* ( n --- )   runtime\r
+* typical use: BEGIN code-loop test END  \r
+* ( adr n --- ) \r
+* Alias for UNTIL .\r
+       EVEN\r
+       DC.B    $C3\r
+       DC.B    'EN'    ; 'END'\r
+       DC.B    'D'|$80\r
+       DC.L    UNTIL-6-NATWID\r
+END    DC.L    DOCOL,UNTIL\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  203  <<\r
+* ( --- )   runtime\r
+* typical use: BEGIN code-loop AGAIN  \r
+* Will loop forever \r
+* (or until something uses R> DROP to force the current definition to die,\r
+*  or perhaps ABORT or ERROR or some such other drastic means stops things).\r
+* ( adr n --- )  compile time                      P,C\r
+* Check the mark and compile (0BRANCH), fill in BACK reference.\r
+* A better flag: $4245 (ASCII for 'BE').\r
+       EVEN\r
+       DC.B    $C5\r
+       DC.B    'AGAI'  ; 'AGAIN'\r
+       DC.B    'N'|$80\r
+       DC.L    END-4-NATWID\r
+AGAIN  DC.L    DOCOL,ONE,QPAIRS,COMPIL,BRAN,BACK       ; ONE for BEGIN loops.\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  204  <<\r
+* ( --- )   runtime\r
+* typical use: BEGIN code-loop test WHILE code-true REPEAT  \r
+* Will loop until WHILE tests false, skipping code-true on end.\r
+* REPEAT marks where execution resumes after the WHILE find a false flag.\r
+* ( aadr1 n1 adr2 n2 --- )   compile time         P,C\r
+* Check the marks for WHILE and BEGIN,\r
+* compile BRANCH and BACK fill adr1 reference,\r
+* FILL-IN 0BRANCH reference at adr2.\r
+* Better flags: $4245 (ASCII for 'BE') and $5747 (ASCII for 'WH').\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $C6\r
+       DC.B    'REPEA' ; 'REPEAT'\r
+       DC.B    'T'|$80\r
+       DC.L    AGAIN-6-NATWID\r
+REPEAT DC.L    DOCOL,TOR,TOR,AGAIN,FROMR,FROMR ; ONE for BEGIN loops.\r
+       DC.L    TWO,SUB,ENDIF   ; TWO is for IF, 4 is for WHILE.\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  205  <<\r
+* ( n --- )   runtime\r
+* typical use: test IF code-true ELSE code-false ENDIF \r
+* Will pass execution to the true part on a true flag \r
+* and to the false part on a false flag.\r
+* ( --- adr n )  compile time                       P,C\r
+* Compile a 0BRANCH and dummy offset\r
+* and push IF reference to fill in and\r
+* IF control construct flag.\r
+* A better flag: $4946 (ASCII for 'IF').\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $C2\r
+       DC.B    'I'     ; 'IF'\r
+       DC.B    'F'|$80\r
+       DC.L    REPEAT-7-NATWID\r
+IF     DC.L    DOCOL,COMPIL,ZBRAN,HERE,ZERO,COMMA,TWO  ; TWO is a flag for IF.\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  206  <<\r
+* ( --- )   runtime\r
+* typical use: test IF code-true ELSE code-false ENDIF \r
+* ELSE is just a sort of intersection piece, \r
+* marking where execution resumes on a false branch.\r
+* ( adr1 n --- adr2 n )  compile time         P,C\r
+* Check the marks,\r
+* compile BRANCH with dummy offset,\r
+* resolve IF reference,\r
+* and leave reference to BRANCH for ELSE.\r
+* A better flag: $4946 (ASCII for 'IF').\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $C4\r
+       DC.B    'ELS'   ; 'ELSE'\r
+       DC.B    'E'|$80\r
+       DC.L    IF-3-NATWID\r
+ELSE   DC.L    DOCOL,TWO,QPAIRS,COMPIL,BRAN,HERE\r
+       DC.L    ZERO,COMMA,SWAP,TWO,ENDIF,TWO   ; TWO is a flag for IF.\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  207  <<\r
+* ( n --- )   runtime\r
+* typical use: BEGIN code-loop test WHILE code-true REPEAT  \r
+* Will loop until WHILE tests false, skipping code-true on end.\r
+* ( --- adr n ) compile time                        P,C\r
+* Compile 0BRANCH with dummy offset (using IF),\r
+* push WHILE reference.\r
+* BEGIN flag will sit underneath this.\r
+* Better flags: $4245 (ASCII for 'BE') and $5747 (ASCII for 'WH').\r
+       EVEN\r
+       DC.B    $C5\r
+       DC.B    'WHIL'  ; 'WHILE'\r
+       DC.B    'E'|$80\r
+       DC.L    ELSE-5-NATWID\r
+WHILE  DC.L    DOCOL,IF,TWOP   ; TWO is a flag for IF, 4 is for WHILE.\r
+       DC.L    SEMIS\r
+*\r
+       PAGE\r
+*\r
+* ######>> screen 75 <<\r
+* ======>>  208  <<\r
+* ( count --- )\r
+* EMIT count spaces, for non-zero, non-negative counts.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $86\r
+       DC.B    'SPACE' ; 'SPACES'\r
+       DC.B    'S'|$80\r
+       DC.L    WHILE-6-NATWID\r
+SPACES DC.L    DOCOL,ZERO,MAX,DDUP,ZBRAN\r
+       DC.L    SPACE3-*-NATWID\r
+       DC.L    ZERO,XDO\r
+SPACE2 DC.L    SPACE,XLOOP\r
+       DC.L    SPACE2-*-NATWID\r
+SPACE3 DC.L    SEMIS\r
+*\r
+* ======>>  209  <<\r
+* ( --- )\r
+* Initialize HLD for converting a double integer. \r
+* Stores the PAD address in HLD.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    '<'     ; '<#'\r
+       DC.B    '#'|$80\r
+       DC.L    SPACES-7-NATWID\r
+BDIGS  DC.L    DOCOL,PAD,HLD,STORE\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  210  <<\r
+* ( d --- string length )\r
+* Terminate numeric conversion,\r
+* drop the number being converted,\r
+* leave the address of the conversion string and the length, ready for TYPE.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    '#'     ; '#>'\r
+       DC.B    '>'|$80\r
+       DC.L    BDIGS-3-NATWID\r
+EDIGS  DC.L    DOCOL,DROP,DROP,HLD,AT,PAD,OVER,SUB\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  211  <<\r
+* ( n d --- d )\r
+* Put sign of n (as a flag) at the head of the conversion string.\r
+* Drop the sign flag.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $84\r
+       DC.B    'SIG'   ; 'SIGN'\r
+       DC.B    'N'|$80\r
+       DC.L    EDIGS-3-NATWID\r
+SIGN   DC.L    DOCOL,ROT,ZLESS,ZBRAN\r
+       DC.L    SIGN2-*-NATWID\r
+       DC.L    LIT16\r
+       DC.W    "-"     \r
+       DC.L    HOLD\r
+SIGN2  DC.L    SEMIS\r
+*\r
+* ======>>  212  <<\r
+* ( d --- d/base )\r
+* Generate next most significant digit in the conversion BASE,\r
+* putting the digit at the head of the conversion string.\r
+       EVEN\r
+       DC.B    $81     ; #\r
+       DC.B    '#'|$80\r
+       DC.L    SIGN-5-NATWID\r
+DIG    DC.L    DOCOL,BASE,AT,MSMOD,ROT,LIT16\r
+       DC.W    9\r
+       DC.L    OVER,LESS,ZBRAN\r
+       DC.L    DIG2-*-NATWID\r
+       DC.L    LIT16\r
+       DC.W    7\r
+       DC.L    PLUS\r
+DIG2   DC.L    LIT16\r
+       DC.W    "0"     ; ascii zero\r
+       DC.L    PLUS,HOLD\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  213  <<\r
+* ( d --- dzero )\r
+* Convert d to a numeric string using # until the result is zero.\r
+* Leave the double result on the stack for #> to drop.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    '#'     ; '#S'\r
+       DC.B    'S'|$80\r
+       DC.L    DIG-2-NATWID\r
+DIGS   DC.L    DOCOL\r
+DIGS2  DC.L    DIG,OVER,OVER,OR,ZEQU,ZBRAN\r
+       DC.L    DIGS2-*-NATWID\r
+       DC.L    SEMIS\r
+*\r
+* ######>> screen 76 <<\r
+* ======>>  214  <<\r
+* ( n width --- )\r
+* Print n on the output device in the current conversion base,\r
+* with sign,\r
+* right aligned in a field at least width wide.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    '.'     ; '.R'\r
+       DC.B    'R'|$80\r
+       DC.L    DIGS-3-NATWID\r
+DOTR   DC.L    DOCOL,TOR,STOD,FROMR,DDOTR\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  215  <<\r
+* ( d width --- )\r
+* Print d on the output device in the current conversion base,\r
+* with sign,\r
+* right aligned in a field at least width wide.\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'D.'    ; 'D.R'\r
+       DC.B    'R'|$80\r
+       DC.L    DOTR-3-NATWID\r
+DDOTR  DC.L    DOCOL,TOR,SWAP,OVER,DABS,BDIGS,DIGS,SIGN\r
+       DC.L    EDIGS,FROMR,OVER,SUB,SPACES,TYPE\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  216  <<\r
+* D.      ( d --- )\r
+* Print d on the output device in the current conversion base,\r
+* with sign,\r
+* in free format with trailing space.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $82\r
+       DC.B    'D'     ; 'D.'\r
+       DC.B    '.'|$80\r
+       DC.L    DDOTR-4-NATWID\r
+DDOT   DC.L    DOCOL,ZERO,DDOTR,SPACE\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  217  <<\r
+* ( n --- )\r
+* Print n on the output device in the current conversion base,\r
+* with sign,\r
+* in free format with trailing space.\r
+       EVEN\r
+       DC.B    $81     ; .\r
+       DC.B    '.'|$80\r
+       DC.L    DDOT-3-NATWID\r
+*DOT   DC.L    DOCOL,STOD,DDOT\r
+DOT    DC.L    DOCOL,BREAK,STOD,DDOT   ; DBG *****\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  218  <<\r
+* ( adr --- )\r
+* Print signed word at adr, per DOT.\r
+       EVEN\r
+       DC.B    $81     ; ?\r
+       DC.B    '?'|$80\r
+       DC.L    DOT-2-NATWID\r
+QUEST  DC.L    DOCOL,AT,DOT\r
+       DC.L    SEMIS\r
+*\r
+       PAGE\r
+*\r
+* ######>> screen 77 <<\r
+* ======>>  219  <<\r
+* ( n --- )\r
+* Print out screen n as a field of ASCII,\r
+* with line numbers in decimal.\r
+* Needs a console more than 70 characters wide.\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $84\r
+       DC.B    'LIS'   ; 'LIST'\r
+       DC.B    'T'|$80\r
+       DC.L    QUEST-2-NATWID\r
+LIST   DC.L    DOCOL,DEC,CR,DUP,SCR,STORE,PDOTQ\r
+       DC.B    6\r
+       DC.B    "SCR # "\r
+       DC.B    0       ; hand align\r
+       DC.L    DOT,LIT16\r
+       DC.W    $10\r
+       DC.L    ZERO,XDO\r
+LIST2  DC.L    CR,I,THREE\r
+       DC.L    DOTR,SPACE,I,SCR,AT,DLINE,XLOOP\r
+       DC.L    LIST2-*-NATWID\r
+       DC.L    CR\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  220  <<\r
+* ( start end --- )\r
+* Print comment lines (line 0, and line 1 if C/L < 41) of screens\r
+* from start to end.\r
+* Needs a console more than 70 characters wide.\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    'INDE'  ; 'INDEX'\r
+       DC.B    'X'|$80\r
+       DC.L    LIST-5-NATWID\r
+INDEX  DC.L    DOCOL,CR,ONEP,SWAP,XDO\r
+INDEX2 DC.L    CR,I,THREE\r
+       DC.L    DOTR,SPACE,ZERO,I,DLINE\r
+       DC.L    QTERM,ZBRAN\r
+       DC.L    INDEX3-*-NATWID\r
+       DC.L    LEAVE\r
+INDEX3 DC.L    XLOOP\r
+       DC.L    INDEX2-*-NATWID\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  221  <<\r
+* ( n --- )\r
+* List a printer page full of screens.\r
+* Line and screen number are in current base.\r
+* Needs a console more than 70 characters wide.\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    'TRIA'  ; 'TRIAD'\r
+       DC.B    'D'|$80\r
+       DC.L    INDEX-6-NATWID\r
+TRIAD  DC.L    DOCOL,THREE,SLASH,THREE,STAR\r
+       DC.L    THREE,OVER,PLUS,SWAP,XDO\r
+TRIAD2 DC.L    CR,I\r
+       DC.L    LIST,QTERM,ZBRAN\r
+       DC.L    TRIAD3-*-NATWID\r
+       DC.L    LEAVE\r
+TRIAD3 DC.L    XLOOP\r
+       DC.L    TRIAD2-*-NATWID\r
+       DC.L    CR,LIT16\r
+       DC.W    $0F\r
+       DC.L    MESS,CR\r
+       DC.L    SEMIS\r
+*\r
+* ######>> screen 78 <<\r
+* ======>>  222  <<\r
+* ( --- )\r
+* List the definitions in the current vocabulary.\r
+* Expects to output to full-width screen of printer, not a 32- or 40- column screen\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    'VLIS'  ; 'VLIST'\r
+       DC.B    'T'|$80\r
+       DC.L    TRIAD-6-NATWID\r
+VLIST  DC.L    DOCOL\r
+*      DC.L    TRON    ; DBG ******\r
+*      DC.L    LIT16   ; should not be hard coded.\r
+*      DC.W    $80\r
+       DC.L    COLUMS,AT\r
+       DC.L    OUT,STORE,CONTXT,AT,AT\r
+VLIST1 DC.L    OUT,AT,COLUMS,AT\r
+*      DC.L    LIT16   ; Should not be hard coded.\r
+*      DC.W    32\r
+       DC.L    WIDTH,AT\r
+       DC.L    SUB,GREAT,ZBRAN\r
+       DC.L    VLIST2-*-NATWID\r
+       DC.L    CR,ZERO,OUT,STORE\r
+VLIST2 DC.L    DUP,IDDOT\r
+*      DC.L    BREAK   ; dbg *****\r
+       DC.L    SPACE,SPACE,PFA,LFA,AT\r
+       DC.L    DUP,ZEQU,QTERM,OR,ZBRAN\r
+       DC.L    VLIST1-*-NATWID\r
+       DC.L    DROP\r
+*      DC.L    TROFF,BREAK     ; DBG ********\r
+       DC.L    SEMIS\r
+*\r
+* Need some utility stuff that isn't in the fig FORTH:\r
+* ( c --- )\r
+* Emit dot if c is less than blank, else emit c\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    'BEMI'  ; 'BEMIT'\r
+       DC.B    'T'|$80\r
+       DC.L    VLIST-6-NATWID\r
+BEMIT  DC.L    DOCOL\r
+       DC.L    DUP,BL,LESS,ZBRAN\r
+       DC.L    BEMITO-*-NATWID\r
+       DC.L    DROP,LIT16\r
+       DC.W    $2e     ; '.'\r
+BEMITO DC.L    EMIT\r
+       DC.L    SEMIS\r
+*\r
+* ( n width --- )\r
+* Output n in hexadecimal with field width.\r
+       EVEN\r
+       DC.B    $83\r
+       DC.B    'X.'    ; 'X.R'\r
+       DC.B    'R'|$80\r
+       DC.L    BEMIT-6-NATWID\r
+XDOTR  DC.L    DOCOL\r
+       DC.L    BASE,AT,TOR,HEX,DOTR,FROMR,BASE,STORE\r
+       DC.L    SEMIS\r
+*\r
+BYTPLN EQU     16      ; bytes to dump per line\r
+* ( adr --- )\r
+* Dump a line of 16 bytes in memory, in hex and as characters.\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    'BLIN'  ; 'BLINE'\r
+       DC.B    'E'|$80\r
+       DC.L    XDOTR-4-NATWID\r
+BLINE  DC.L    DOCOL\r
+       DC.L    DUP,LIT16\r
+       DC.W    BYTPLN\r
+       DC.L    PLUS,OVER,XDO\r
+BLINEX DC.L    I,CAT,THREE,XDOTR,XLOOP\r
+       DC.L    BLINEX-*-NATWID\r
+       DC.L    SPACE,SPACE\r
+       DC.L    DUP,LIT16\r
+       DC.W    BYTPLN\r
+       DC.L    PLUS,SWAP,XDO\r
+BLINEC DC.L    I,CAT,BEMIT,XLOOP\r
+       DC.L    BLINEC-*-NATWID\r
+       DC.L    SEMIS\r
+*\r
+* ( adr ct --- )\r
+* Dump memory via BLINE from adr to ct (ceiling BYTPLN) bytes.\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    'BDUM'  ; 'BDUMP'\r
+       DC.B    'P'|$80\r
+       DC.L    BLINE-6-NATWID\r
+BDUMP  DC.L    DOCOL\r
+       DC.L    CR,OVER,PLUS,SWAP,XDO\r
+BDUMPL DC.L    I,LIT16\r
+       DC.W    4\r
+       DC.L    XDOTR,LIT16\r
+       DC.W    $3A\r
+       DC.L    EMIT,SPACE\r
+       DC.L    I,BLINE,CR,LIT16\r
+       DC.W    BYTPLN\r
+       DC.L    XPLOOP\r
+       DC.L    BDUMPL-*-NATWID\r
+       DC.L    SEMIS\r
+*\r
+* ======>>  XX  <<\r
+* ( --- )\r
+* Place holder for triggering low-level debuggers (not in fig Forth).\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    'BREA'  ; 'BREAK'\r
+       DC.B    'K'|$80\r
+       DC.L    BDUMP-6-NATWID\r
+BREAK  DC.L    *+NATWID\r
+BREAKF NOP                     ; set a low-level break in here\r
+       NOP\r
+       NOP\r
+       RTS\r
+*\r
+*\r
+       EVEN\r
+       DC.B    $85\r
+       DC.B    'TROF'  ; 'TROFF'\r
+       DC.B    'F'|$80\r
+       DC.L    BREAK-6-NATWID\r
+TROFF  DC.L    *+NATWID\r
+       CLR.W   TRACEM-UORIG(UP)\r
+       RTS\r
+*\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $84\r
+       DC.B    'TRO'   ; 'TRON'\r
+       DC.B    'N'|$80\r
+       DC.L    TROFF-6-NATWID\r
+TRON   DC.L    *+NATWID\r
+       MOVE.W  #1,TRACEM-UORIG(UP)\r
+       RTS\r
+*\r
+*\r
+* NOOP NEXT    a useful no-op\r
+*\r
+* ======>>  XX  <<\r
+* ( --- )\r
+* Mostly for place holding (fig Forth).\r
+       EVEN\r
+       DC.B    0\r
+       DC.B    $84\r
+       DC.B    'NOO'   ; 'NOOP'\r
+       DC.B    'P'|$80\r
+       DC.L    TRON-5-NATWID\r
+NOOP   DC.L    *+NATWID\r
+       NOP\r
+       NOP\r
+       NOP\r
+       RTS\r
+* NOOP NEXT    a useful no-op\r
+ZZZZ   DC.L    0,0,0,0,0,0,0,0 end of rom program\r
+\r
+* About 10.3K in the dictionary image proper.\r
+* This is not surprising, given that the 6809 image is about 6.9K. \r
+* (The 6800 image is about 6.3K, if I remember right.)\r
+* Since the image is mostly pointers, and pointers in the 68000 are 32 bits, not 16\r
+* (since we don't want to limit ourselves to a 32K or so dictionary),\r
+* the 68000 image should be something less than double the size of the 6809 or 6800 image.\r
+\r
+       PAGE\r
+*\r
+\r
+\r
+*\r
+* Build test lists here:\r
+*TESTNEXT:\r
+*      DC.L    LIT,$FEEDBEEF\r
+*      DC.L    LIT16\r
+*      DC.W    $FF0F\r
+*      DC.L    LIT,AND\r
+*      DC.L    EXEC\r
+*      DC.L    BRAN\r
+*      DC.L    TESTNEXT-*-NATWID\r
+*\r
+*TESTMIN:\r
+*      DC.L    LIT,5\r
+*      DC.L    SIGNUM\r
+*      DC.L    LIT,-10\r
+*      DC.L    SIGNUM\r
+*      DC.L    MIN\r
+*      DC.L    LIT,100\r
+*      DC.L    MIN\r
+*      DC.L    DROP\r
+*TESTSUB:\r
+*      DC.L    LIT,$DEEFEED\r
+*      DC.L    LIT,$FEDDEBB\r
+*      DC.L    SUB     ; DEEFEED - FEDDEBB\r
+*      DC.L    BRAN\r
+*      DC.L    TESTNEXT-*-NATWID\r
+*\r
+\r
+* Here you can see some of the advantages and disadvantages of the inner interpreter loop,\r
+* and of indirect threading.\r
+* PTRACE saves and restores D0/D1/D2/A2 so it can use them.\r
+* PEMIT will also save and restore D1/D2/A2 to protect them from the BIOS calls.\r
+D1MKHX:\r
+       AND.L   #$0F,D1\r
+       ADD.B   #'0',D1\r
+       CMP.B   #'9',D1\r
+       BLE.S   D1MKHR\r
+       ADD.B   #'A'-'9'-1,D1\r
+D1MKHR RTS\r
+*\r
+PD1H1:\r
+       MOVEM.L D1,-(SP)\r
+       BSR.S   D1MKHX\r
+       BSR.W   PEMIT\r
+       MOVEM.L (SP)+,D1\r
+       RTS\r
+*\r
+PD1H8:\r
+       MOVEM.L D2,-(SP)\r
+       MOVE.W  #7,D2\r
+PD1H8L:\r
+       ROL.L   #4,D1   ; Grab the top four bits.\r
+       BSR.S   PD1H1\r
+       DBF     D2,PD1H8L\r
+       MOVEM.L (SP)+,D2\r
+       RTS\r
+*\r
+PTRACE:\r
+       MOVEM.L D0/D1/D2/A2,-(SP)\r
+       MOVE.B  #'|',D1\r
+       BSR.W   PEMIT\r
+       MOVE.L  (PSP),D1\r
+       BSR.S   PD1H8\r
+       MOVE.B  #'|',D1\r
+       BSR.W   PEMIT\r
+       MOVE.L  NATWID(PSP),D1\r
+       BSR.S   PD1H8\r
+       MOVE.B  #':',D1\r
+       BSR.W   PEMIT\r
+       MOVE.L  W,D1\r
+       BSR.S   PD1H8\r
+       MOVE.B  #'>',D1\r
+       BSR.W   PEMIT\r
+       BSR.S   PNAME\r
+       BSR.W   PCR\r
+       MOVEM.L (SP)+,D0/D1/D2/A2\r
+       RTS\r
+*\r
+PSTR:\r
+       SUBQ    #1,D2   ; for DBF count\r
+PSTRL  MOVE.B  (A2)+,D1\r
+       AND.L   #$7F,D1\r
+       BSR.W   PEMIT\r
+       DBF     D2,PSTRL\r
+       RTS\r
+*\r
+IXNAME:\r
+       LEA     -2*NATWID(W),A2 ; back up to one past the mode byte.\r
+       TST.B   -(A2)   ; is it a mode byte?\r
+       BPL.S   IXNAMX  ; If this is not an end/mode byte, stop.\r
+IXNAML TST.B   -(A2)   ; back up to the length byte\r
+       BPL.s   IXNAML\r
+IXNAMX RTS\r
+*\r
+PNAMN0 DC.B    $0E             ; Not a dictionary entry, unadorned length,\r
+       DC.B    '** NOT NAME **'        ; and no tail char flag.\r
+       EVEN    \r
+PNAME:\r
+       BSR.S   IXNAME\r
+       MOVE.B  (A2)+,D2        ; Length byte, point to 1st character\r
+       BPL.S   PNAMEF\r
+       AND.W   #$1F,D2         ; extract length, word for DBF\r
+       BEQ.S   PNAMEF          ; all names have length, even NUL\r
+PNAMEP BSR.S   PSTR\r
+       RTS\r
+PNAMEF LEA     PNAMN0(PC),A2\r
+       MOVE.B  (A2)+,D2        ; Error message has length (unadorned), too.\r
+       BRA.S   PNAMEP\r
+*\r
+ZZZZ2  DC.L    0,0,0,0,0,0,0,0         ; "real" end of "rom" program\r
+*      ALIGN   256     ; want to do this, but the ATARI CNOP directive doesn't look standard to me.\r
+*\r
+*      substitute for disc mass memory\r
+NBLK   EQU     4 ; # of disc buffer blocks for virtual memory\r
+* Should NBLK be SCRSZ/SECTSZ? maybe not.\r
+*  each block is SECTSZ+SECTRL bytes in size,\r
+*  holding SECTSZ characters\r
+SECTSZ EQU     256\r
+SECTRL EQU     2*NATWID        ; Currently held sector number, etc.\r
+BUFSZ  EQU     (SECTSZ+SECTRL)*NBLK\r
+*\r
+BUFBAS DS.L    BUFSZ\r
+* This is a really awkward place to define the disk buffer records.\r
+*\r
+* *BUG* SECTRL was magic-number hard-wired into several definitions.\r
+* It will take a bit of work to ferret them out.\r
+* It is too small, and it should not be hard-wired.\r
+* SECTSZ was also magic-number hard-wired into several definitions,\r
+* will I find them all?\r
+       DC.L    0,0,0,0,0,0,0,0         ; put a little space between\r
+*      ALIGN   256     ; Again, I want to, but ...\r
+MEMEND EQU     *\r
+*\r
+SCRSZ  EQU     1024\r
+*\r
+*                                              FIRST\r
+*\r
+VDISK  EQU     MEMEND\r
+*\r
+*      Screens for drive 0, including error messages.\r
+*\r
+* SCREEN 0\r
+       DC.B    "000~000: ( Index to disk SCREENS SCREEN 0 )                     " 0\r
+       DC.B    "001~002: ( More Index lines )                                   " 1\r
+       DC.B    "003~003: ( FIG Title page, FIG Copyright Notice )               " 2\r
+       DC.B    "004~005: ( FIG ERROR MESSAGES )                                 " 3\r
+       DC.B    "006~007: ( Custom Error Messages )                              " 4\r
+       DC.B    "008~???: ( Modifications, copyright notices )                   " 5\r
+       DC.B    "XXX~XXX:                                                        " 6\r
+       DC.B    "XXX~XXX:                                                        " 7\r
+       DC.B    "XXX~XXX:                                                        " 8\r
+       DC.B    "XXX~XXX:                                                        " 9\r
+       DC.B    "XXX~XXX:                                                        " 10\r
+       DC.B    "XXX~XXX:                                                        " 11\r
+       DC.B    "XXX~XXX:                                                        " 12\r
+       DC.B    "XXX~XXX:                                                        " 13\r
+       DC.B    "XXX~XXX:                                                        " 14\r
+       DC.B    "XXX~XXX:                                                        " 15\r
+* SCREEN 1\r
+       DC.B    "XXX~XXX: ( More index SCREEN 1 )                                " 0\r
+       DC.B    "XXX~XXX:                                                        " 1\r
+       DC.B    "XXX~XXX:                                                        " 2\r
+       DC.B    "XXX~XXX:                                                        " 3\r
+       DC.B    "XXX~XXX:                                                        " 4\r
+       DC.B    "XXX~XXX:                                                        " 5\r
+       DC.B    "XXX~XXX:                                                        " 6\r
+       DC.B    "XXX~XXX:                                                        " 7\r
+       DC.B    "XXX~XXX:                                                        " 8\r
+       DC.B    "XXX~XXX:                                                        " 9\r
+       DC.B    "XXX~XXX:                                                        " 10\r
+       DC.B    "XXX~XXX:                                                        " 11\r
+       DC.B    "XXX~XXX:                                                        " 12\r
+       DC.B    "XXX~XXX:                                                        " 13\r
+       DC.B    "XXX~XXX:                                                        " 14\r
+       DC.B    "XXX~XXX:                                                        " 15\r
+* SCREEN 2\r
+       DC.B    "XXX~XXX: ( More index SCREEN 2 )                                " 0\r
+       DC.B    "XXX~XXX:                                                        " 1\r
+       DC.B    "XXX~XXX:                                                        " 2\r
+       DC.B    "XXX~XXX:                                                        " 3\r
+       DC.B    "XXX~XXX:                                                        " 4\r
+       DC.B    "XXX~XXX:                                                        " 5\r
+       DC.B    "XXX~XXX:                                                        " 6\r
+       DC.B    "XXX~XXX:                                                        " 7\r
+       DC.B    "XXX~XXX:                                                        " 8\r
+       DC.B    "XXX~XXX:                                                        " 9\r
+       DC.B    "XXX~XXX:                                                        " 10\r
+       DC.B    "XXX~XXX:                                                        " 11\r
+       DC.B    "XXX~XXX:                                                        " 12\r
+       DC.B    "XXX~XXX:                                                        " 13\r
+       DC.B    "XXX~XXX:                                                        " 14\r
+       DC.B    "XXX~XXX:                                                        " 15\r
+* SCREEN 3\r
+       DC.B    "*************** Code from the fig-FORTH MODEL ***************   " 0\r
+       DC.B    "                                                                " 1\r
+       DC.B    "                   Through the courtesy of                      " 2\r
+       DC.B    "                                                                " 3\r
+       DC.B    "                    FORTH INTEREST GROUP                        " 4\r
+       DC.B    "                       P. O. BOX 1105                           " 5\r
+       DC.B    "                   SAN CARLOS, CA. 94070                        " 6\r
+       DC.B    "                                                                " 7\r
+       DC.B    "                                                                " 8\r
+       DC.B    "                         RELEASE 1                              " 9\r
+       DC.B    "                   WITH COMPILER SECURITY                       " 10\r
+       DC.B    "                           AND                                  " 11\r
+       DC.B    "                   VARIABLE LENGTH NAMES                        " 12\r
+       DC.B    "                                                                " 13\r
+       DC.B    "                                                                " 14\r
+       DC.B    "       Further distribution must include the above notice.      " 15\r
+* SCREEN 4\r
+       DC.B    "(  ERROR MESSAGES  )                                              " 0\r
+       DC.B    "DATA STACK UNDERFLOW                                            " 1\r
+       DC.B    "DICTIONARY FULL                                                 " 2\r
+       DC.B    "HAS INCORRECT ADDRESS MODE                                      " 3\r
+       DC.B    "ISN'T UNIQUE                                                    " 4\r
+       DC.B    "                                                                " 5\r
+       DC.B    "DISC RANGE?                                                     " 6\r
+       DC.B    "DATA STACK OVERFLOW                                             " 7\r
+       DC.B    "DISC ERROR!                                                     " 8\r
+       DC.B    "                                                                " 9\r
+       DC.B    "                                                                " 10\r
+       DC.B    "                                                                " 11\r
+       DC.B    "                                                                " 12\r
+       DC.B    "                                                                " 13\r
+       DC.B    "                                                                " 14\r
+       DC.B    "FORTH INTEREST GROUP                                            " 15\r
+* SCREEN 5\r
+       DC.B    "(  ERROR MESSAGES  )                                            " 0\r
+       DC.B    "COMPILATION ONLY, USE IN DEFINITION                             " 1\r
+       DC.B    "EXECUTION ONLY                                                  " 2\r
+       DC.B    "CONDITIONALS NOT PAIRED                                         " 3\r
+       DC.B    "DEFINITION NOT FINISHED                                         " 4\r
+       DC.B    "IN PROTECTED DICTIONARY                                         " 5\r
+       DC.B    "USE ONLY WHEN LOADING                                           " 6\r
+       DC.B    "OFF CURRENT EDITING SCREEN                                      " 7 \r
+       DC.B    "DECLARE VOCABULARY                                              " 8\r
+       DC.B    "                                                                " 9\r
+       DC.B    "                                                                " 10\r
+       DC.B    "                                                                " 11\r
+       DC.B    "                                                                " 12\r
+       DC.B    "                                                                " 13\r
+       DC.B    "                                                                " 14\r
+       DC.B    "FORTH INTEREST GROUP                                            " 15\r
+* SCREEN 6\r
+       DC.B    "( MORE ERROR MESSAGES SCREEN 6 )                                " 0\r
+       DC.B    "                                                                " 1\r
+       DC.B    "                                                                " 2\r
+       DC.B    "                                                                " 3\r
+       DC.B    "                                                                " 4\r
+       DC.B    "                                                                " 5\r
+       DC.B    "                                                                " 6\r
+       DC.B    "                                                                " 7\r
+       DC.B    "                                                                " 8\r
+       DC.B    "                                                                " 9\r
+       DC.B    "                                                                " 10\r
+       DC.B    "                                                                " 11\r
+       DC.B    "                                                                " 12\r
+       DC.B    "                                                                " 13\r
+       DC.B    "                                                                " 14\r
+       DC.B    "                                                                " 15\r
+* \r
+* SCREEN 7\r
+       DC.B    " ( MORE ERROR MESSAGES SCREEN 7 )                               " 0\r
+       DC.B    "                                                                " 1\r
+       DC.B    "                                                                " 2\r
+       DC.B    "                                                                " 3\r
+       DC.B    "                                                                " 4\r
+       DC.B    "                                                                " 5\r
+       DC.B    "                                                                " 6\r
+       DC.B    "                                                                " 7\r
+       DC.B    "                                                                " 8\r
+       DC.B    "                                                                " 9\r
+       DC.B    "                                                                " 10\r
+       DC.B    "                                                                " 11\r
+       DC.B    "                                                                " 12\r
+       DC.B    "                                                                " 13\r
+       DC.B    "                                                                " 14\r
+       DC.B    "                                                                " 15\r
+*\r
+* SCREEN 8\r
+       DC.B    " ( TEXT, LINE                                     WFR-79MAY01 ) " 0\r
+       DC.B    " FORTH DEFINITIONS  HEX                                         " 1\r
+       DC.B    "                                                                " 2\r
+       DC.B    " 64 CONSTANT C/L                                                " 3\r
+       DC.B    "                                                                " 4\r
+       DC.B    " : TEXT                       ( ACCEPT FOLLOWING TEXT TO PAD *) " 5\r
+       DC.B    "      HERE  C/L  1+  BLANKS  WORD  HERE  PAD  C/L  1+  CMOVE  ; " 6\r
+       DC.B    "                                                                " 7\r
+       DC.B    " : LINE             ( RELATIVE TO SCR, LEAVE ADDRESS OF LINE *) " 8\r
+       DC.B    "       DUP  FFF0  AND   17   ?ERROR     ( KEEP ON THIS SCREEN ) " 9\r
+       DC.B    "       SCR  @  (LINE)   DROP   ;                                " 10\r
+       DC.B    "                                                                " 11\r
+       DC.B    "                                                                " 12\r
+       DC.B    "                                                                " 13\r
+       DC.B    "                                                                " 14\r
+       DC.B    "                                                                " 15\r
+*\r
+* SCREEN 9\r
+       DC.B    " ( More crude editing facilities. -- one byte characters )      " 0\r
+       DC.B    "                                                                " 1\r
+       DC.B    " 0 VARIABLE LNEDBUF 62 ALLOT        ( buffer for line editing ) " 2\r
+       DC.B    "                                                                " 3\r
+       DC.B    " ( ns nl -- )              ( overwrite one line of the screen ) " 4\r
+       DC.B    " : PUTLINE LNEDBUF 64 BLANKS   ( just enough to write to disc ) " 5\r
+       DC.B    "           CR LNEDBUF 64 EXPECT CR     ( just enough to write ) " 6\r
+       DC.B    "           SL2BB LNEDBUF SWAP 64 CMOVE UPDATE ;                 " 7\r
+       DC.B    "       ( Full screen editing requires keyboard control codes. ) " 8\r
+       DC.B    "                                                                " 9\r
+       DC.B    "                                                                " 10\r
+       DC.B    "                                                                " 11\r
+       DC.B    "                                                                " 12\r
+       DC.B    "                                                                " 13\r
+       DC.B    "                                                                " 14\r
+       DC.B    "                                                                " 15\r
+*\r
+* SCREEN 10\r
+       DC.B    "                                                                " 0\r
+       DC.B    "                                                                " 1\r
+       DC.B    "                                                                " 2\r
+       DC.B    "                                                                " 3\r
+       DC.B    "                                                                " 4\r
+       DC.B    "                                                                " 5\r
+       DC.B    "                                                                " 6\r
+       DC.B    "                                                                " 7\r
+       DC.B    "                                                                " 8\r
+       DC.B    "                                                                " 9\r
+       DC.B    "                                                                " 10\r
+       DC.B    "                                                                " 11\r
+       DC.B    "                                                                " 12\r
+       DC.B    "                                                                " 13\r
+       DC.B    "                                                                " 14\r
+       DC.B    "                                                                " 15\r
+*\r
+* SCREEN 11\r
+       DC.B    "                                                                " 0\r
+       DC.B    "                                                                " 1\r
+       DC.B    "                                                                " 2\r
+       DC.B    "                                                                " 3\r
+       DC.B    "                                                                " 4\r
+       DC.B    "                                                                " 5\r
+       DC.B    "                                                                " 6\r
+       DC.B    "                                                                " 7\r
+       DC.B    "                                                                " 8\r
+       DC.B    "                                                                " 9\r
+       DC.B    "                                                                " 10\r
+       DC.B    "                                                                " 11\r
+       DC.B    "                                                                " 12\r
+       DC.B    "                                                                " 13\r
+       DC.B    "                                                                " 14\r
+       DC.B    "                                                                " 15\r
+*\r
+* SCREEN 12\r
+       DC.B    "                                                                " 0\r
+       DC.B    "                                                                " 1\r
+       DC.B    "                                                                " 2\r
+       DC.B    "                                                                " 3\r
+       DC.B    "                                                                " 4\r
+       DC.B    "                                                                " 5\r
+       DC.B    "                                                                " 6\r
+       DC.B    "                                                                " 7\r
+       DC.B    "                                                                " 8\r
+       DC.B    "                                                                " 9\r
+       DC.B    "                                                                " 10\r
+       DC.B    "                                                                " 11\r
+       DC.B    "                                                                " 12\r
+       DC.B    "                                                                " 13\r
+       DC.B    "                                                                " 14\r
+       DC.B    "                                                                " 15\r
+*\r
+* SCREEN 13\r
+       DC.B    "                                                                " 0\r
+       DC.B    "                                                                " 1\r
+       DC.B    "                                                                " 2\r
+       DC.B    "                                                                " 3\r
+       DC.B    "                                                                " 4\r
+       DC.B    "                                                                " 5\r
+       DC.B    "                                                                " 6\r
+       DC.B    "                                                                " 7\r
+       DC.B    "                                                                " 8\r
+       DC.B    "                                                                " 9\r
+       DC.B    "                                                                " 10\r
+       DC.B    "                                                                " 11\r
+       DC.B    "                                                                " 12\r
+       DC.B    "                                                                " 13\r
+       DC.B    "                                                                " 14\r
+       DC.B    "                                                                " 15\r
+*\r
+* SCREEN 14\r
+       DC.B    "                                                                " 0\r
+       DC.B    "                                                                " 1\r
+       DC.B    "                                                                " 2\r
+       DC.B    "                                                                " 3\r
+       DC.B    "                                                                " 4\r
+       DC.B    "                                                                " 5\r
+       DC.B    "                                                                " 6\r
+       DC.B    "                                                                " 7\r
+       DC.B    "                                                                " 8\r
+       DC.B    "                                                                " 9\r
+       DC.B    "                                                                " 10\r
+       DC.B    "                                                                " 11\r
+       DC.B    "                                                                " 12\r
+       DC.B    "                                                                " 13\r
+       DC.B    "                                                                " 14\r
+       DC.B    "                                                                " 15\r
+*\r
+* SCREEN 15\r
+       DC.B    "                                                                " 0\r
+       DC.B    "                                                                " 1\r
+       DC.B    "                                                                " 2\r
+       DC.B    "                                                                " 3\r
+       DC.B    "                                                                " 4\r
+       DC.B    "                                                                " 5\r
+       DC.B    "                                                                " 6\r
+       DC.B    "                                                                " 7\r
+       DC.B    "                                                                " 8\r
+       DC.B    "                                                                " 9\r
+       DC.B    "                                                                " 10\r
+       DC.B    "                                                                " 11\r
+       DC.B    "                                                                " 12\r
+       DC.B    "                                                                " 13\r
+       DC.B    "                                                                " 14\r
+       DC.B    "                                                                " 15\r
+*\r
+VDR1   EQU     *\r
+RAMDSZ EQU     VDR1-VDISK\r
+*\r
+       DS      RAMDSZ\r
+*\r
+MEMTOP EQU     *\r
+*\r
+*                                              LO\r
+*\r
+MASSLO EQU     VDISK\r
+MASSHI EQU     MEMTOP\r
+*\r
+*                                              HI\r
+*\r
+* "end" of "usable ram"        (If disc mass memory emulation is removed, actual end.)\r
+*\r
+       end     ORIG    \r
+\r
+\r
+\r
+\r
+\r