home .. products .. mforth .. source code ..
core.asm
; Copyright (c) 2009-2010, Michael Alyn Miller <malyn@strangeGizmo.com>.
; All rights reserved.
;
; Redistribution and use in source and binary forms, with or without
; modification, are permitted provided that the following conditions are met:
;
; 1. Redistributions of source code must retain the above copyright notice
;    unmodified, this list of conditions, and the following disclaimer.
; 2. Redistributions in binary form must reproduce the above copyright notice,
;    this list of conditions and the following disclaimer in the documentation
;    and/or other materials provided with the distribution.
; 3. Neither the name of Michael Alyn Miller nor the names of the contributors
;    to this software may be used to endorse or promote products derived from
;    this software without specific prior written permission.
;
; THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY
; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
; DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
; THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


; ======================================================================
; CORE Words
; ======================================================================

; ----------------------------------------------------------------------
; ! [CORE] 6.1.0010 "store" ( x a-addr -- )
;
; Store x at a-addr.

            LINKTO(LINK_CORE,0,1,'!',"")
STORE:      SAVEDE
            POP     D           ; Pop a-addr
            POP     H           ; Pop x.
            SHLX                ; Store x into a-addr.
            RESTOREDE
            NEXT


; ----------------------------------------------------------------------
; # [CORE] 6.1.0030 "number-sign" ( ud1 -- ud2 )
;
; Divide ud1 by the number in BASE giving the quotient ud2 and the remainder
; n.  (n is the least-significant digit of ud1.)  Convert n to external form
; and add the resulting character to the beginning of the pictured numeric
; output string.  An ambiguous condition exists if # executes outside of a
; <# #> delimited number conversion.
;
; ---
; : # ( ud1 -- ud2 )   BASE @ UD/MOD ROT >digit HOLD ;

            LINKTO(STORE,0,1,'#',"")
NUMSIGN:    JMP     ENTER
            .WORD   BASE,FETCH,UDSLASHMOD,ROT,TODIGIT,HOLD
            .WORD   EXIT


; ----------------------------------------------------------------------
; #> [CORE] 6.1.0040 "number-sign-greater" ( xd -- c-addr u )
;
; Drop xd.  Make the pictured numeric output string available as a character
; string.  c-addr and u specify the resulting character string.  A program
; may replace characters within the string.
;
; ---
; : #> ( xd -- c-addr u ) DROP DROP  HLD @  HERE HLDEND +  OVER - ;

            LINKTO(NUMSIGN,0,2,'>',"#")
NUMSIGNGRTR:JMP     ENTER
            .WORD   DROP,DROP,HLD,FETCH,HERE,LIT,HLDEND,PLUS,OVER,MINUS
            .WORD   EXIT


; ----------------------------------------------------------------------
; #S [CORE] 6.1.0050 "number-sign-s" ( ud1 -- ud2 )
;
; Convert one digit of ud1 according to the rule for #.  Continue conversion
; until the quotient is zero.  ud2 is zero.  An ambiguous condition exists
; if #S executes outside of a <# #> delimited number conversion.
;
; ---
; : #S ( ud1 -- 0 )   BEGIN # 2DUP OR WHILE REPEAT ;

            LINKTO(NUMSIGNGRTR,0,2,'S',"#")
NUMSIGNS:   JMP     ENTER
_numsigns1: .WORD   NUMSIGN,TWODUP,OR,zbranch,_numsigns2,branch,_numsigns1
_numsigns2: .WORD   EXIT


; ----------------------------------------------------------------------
; ' [CORE] 6.1.0070 "tick" ( "<spaces>name" -- xt )
;
; Skip leading space delimiters.  Parse name delimited by a space.  Find
; name and return xt, the execution token for name.  An ambiguous condition
; exists if name is not found.
;
; When interpreting, ' xyz EXECUTE is equivalent to xyz.
;
; ---
; : ' ( "<spaces>name" -- xt)
;   PARSE-WORD (FIND)  0= IF TYPE SPACE [CHAR] ? EMIT CR ABORT THEN ;

            LINKTO(NUMSIGNS,0,1,027h,"")
TICK:       JMP     ENTER
            .WORD   PARSEWORD,PFIND,ZEROEQUALS,zbranch,_tick1
            .WORD   TYPE,SPACE,LIT,'?',EMIT,CR,ABORT
_tick1:     .WORD   EXIT


; ----------------------------------------------------------------------
; ( [CORE] 6.1.0080 "paren"
;
; Compilation:
;   Perform the execution semantics given below.
;
; Execution: ( "ccc<paren>" -- )
;   Parse ccc delimited by ) (right parenthesis).  ( is an immediate word.
;   The number of characters in ccc may be zero to the number of characters
;   in the parse area.
;
; Extended by FILE:
;   When parsing from a text file, if the end of the parse area is reached
;   before a right parenthesis is found, refill the input buffer from the
;   next line of the file, set >IN to zero, and resume parsing, repeating
;   this process until either a right parenthesis is found or the end of the
;   file is reached.
;
; ---
; TODO: Need to implement the extended FILE logic.  I recommend that we modify
;       this code to use REFILL.  We could also avoid PARSE altogether and
;       just go through the input source on our own.  Note that we need to
;       rewrite this in assembly language so that we don't get hit by the
;       perf issues of processing one byte at a time in high-level code.
;
; : ( ( "ccc<quote>" --)   CHAR] ) PARSE 2DROP ;

            LINKTO(TICK,1,1,028h,"")
PAREN:      JMP     ENTER
            .WORD   LIT,029h,PARSE,TWODROP,EXIT


; ----------------------------------------------------------------------
; * [CORE] 6.1.0090 "star" ( n1|u1 n2|u2 -- n3|u3 )
;
; Multiply n1|u1 by n2|u2 giving the product n3|u3.
;
; ---
; : * ( n1|u1 n2|u2 -- n3|u3 )   UM* DROP ;

            LINKTO(PAREN,0,1,'*',"")
STAR:       JMP     ENTER
            .WORD   UMSTAR,DROP,EXIT


; ----------------------------------------------------------------------
; */ [CORE] 6.1.0100 "star-slash" ( n1 n2 n3 -- n4 )
;
; Multiply n1 by n2 producing the intermediate double-cell result d.
; Divide d by n3 giving the single-cell quotient n4.  An ambiguous
; condition exists if n3 is zero or if the quotient n4 lies outside the
; range of a signed number.  If d and n3 differ in sign, the
; implementation-defined result returned will be the same as that returned
; by either the phrase >R M* R> FM/MOD SWAP DROP or the phrase
; >R M* R> SM/REM SWAP DROP.
;
; ---
; : */ ( n1 n2 n3 -- n4)   */MOD NIP ;

            LINKTO(STAR,0,2,'/',"*")
STARSLASH:  JMP     ENTER
            .WORD   STARSLASHMOD,NIP,EXIT


; ----------------------------------------------------------------------
; */MOD [CORE] 6.1.0110 "star-slash-mod" ( n1 n2 n3 -- n4 n5 )
;
; Multiply n1 by n2 producing the intermediate double-cell result d.
; Divide d by n3 producing the single-cell remainder n4 and the
; single-cell quotient n5.  An ambiguous condition exists if n3 is zero,
; or if the quotient n5 lies outside the range of a single-cell signed
; integer.  If d and n3 differ in sign, the implementation-defined result
; returned will be the same as that returned by either the phrase
; >R M* R> FM/MOD or the phrase >R M* R> SM/REM.
;
; ---
; : */MOD ( n1 n2 n3 -- n4 n5)   >R M* R> SM/REM ;

            LINKTO(STARSLASH,0,5,'D',"OM/*")
STARSLASHMOD:JMP    ENTER
            .WORD   TOR,MSTAR,RFROM,SMSLASHREM,EXIT


; ----------------------------------------------------------------------
; + [CORE] 6.1.0120 "plus" ( n1|u1 n2|u2 -- n3|u3 )
;
; Add n2|u2 to n1|u1, giving the sum n3|u3.

            LINKTO(STARSLASHMOD,0,1,'+',"")
PLUS:       SAVEDE
            POP     D           ; Pop n2|u2.
            POP     H           ; Pop n1|u1.
            DAD     D           ; HL=HL+DE
            PUSH    H           ; Push the result onto the stack.
            RESTOREDE
            NEXT


; ----------------------------------------------------------------------
; +! [CORE] 6.1.0130 "plus-store" ( n|u a-addr -- )
;
; Add n|u to the single-cell number at a-addr.

            LINKTO(PLUS,0,2,'!',"+")
PLUSSTORE:  SAVEDE
            POP     D           ; Pop a-addr.
            POP     H           ; Pop n|u.
            PUSH    B           ; Save BC.
            MOV     B,H         ; Move n|u
            MOV     C,L         ; ..to BC.
            LHLX                ; Fetch the number at a-addr.
            DAD     B           ; Add n|u to the number.
            SHLX                ; Store the updated number.
            POP     B           ; Restore BC.
            RESTOREDE
            NEXT


; ----------------------------------------------------------------------
; +LOOP [CORE] 6.1.0140 "plus-loop"
;
; Interpretation:
;   Interpretation semantics for this word are undefined.
;
; Compilation: ( C: do-sys -- )
;   Append the run-time semantics given below to the current definition.
;   Resolve the destination of all unresolved occurrences of LEAVE between
;   the location given by do-sys and the next location for a transfer of
;   control, to execute the words following +LOOP.
;
; Run-time: ( n -- ) ( R: loop-sys1 -- | loop-sys2 )
;   An ambiguous condition exists if the loop control parameters are
;   unavailable.  Add n to the loop index.  If the loop index did not cross
;   the boundary between the loop limit minus one and the loop limit,
;   continue execution at the beginning of the loop.  Otherwise, discard the
;   current loop control parameters and continue execution immediately
;   following the loop.
;
; ---
; +LOOP   ['] (pplusloop) END-LOOP ; IMMEDIATE

            LINKTO(PLUSSTORE,1,5,'P',"OOL+")
PLUSLOOP    JMP     ENTER
            .WORD   LIT,pplusloop,ENDLOOP,EXIT


; ----------------------------------------------------------------------
; COMMA [CORE] 6.1.0150 "comma" ( x -- )
;
; Reserve one cell of data space and store x in the cell.  If the
; data-space pointer is aligned when , begins execution, it will remain
; aligned when , finishes execution.  An ambiguous condition exists if the
; data-space pointer is not aligned prior to execution of ,.
;
; ---
; : , ( x -- )   HERE !  1 CELLS ALLOT ;

            LINKTO(PLUSLOOP,0,1,02Ch,"")
COMMA:      JMP     ENTER
            .WORD   HERE,STORE,ONE,CELLS,ALLOT,EXIT


; ----------------------------------------------------------------------
; - [CORE] 6.1.0160 "minus" ( n1|u1 n2|u2 -- n3|u3 )
;
; Subtract n2|u2 from n1|u1, giving the difference n3|u3.

            LINKTO(COMMA,0,1,'-',"")
MINUS:      SAVEDE
            POP     D           ; Pop n2|u2.
            POP     H           ; Pop n1|u1.
            PUSH    B           ; Save BC.
            MOV     B,D         ; Move n2|u2
            MOV     C,E         ; ..to BC.
            DSUB                ; HL=HL-BC
            POP     B           ; Restore BC.
            PUSH    H           ; Push the result onto the stack.
            RESTOREDE
            NEXT


; ----------------------------------------------------------------------
; . [CORE] 6.1.0180 "dot" ( n -- )
;
; Display n in free field format.
;
; ---
; : . ( n -- )
;   BASE @ 10 <>  IF U. EXIT THEN
;   DUP ABS 0 <# #S ROT SIGN #> TYPE SPACE ;

            LINKTO(MINUS,0,1,'.',"")
DOT:        JMP     ENTER
            .WORD   BASE,FETCH,LIT,10,NOTEQUALS,zbranch,_dot1,UDOT,EXIT
_dot1:      .WORD   DUP,ABS,ZERO,LESSNUMSIGN,NUMSIGNS,ROT,SIGN,NUMSIGNGRTR
            .WORD   TYPE,SPACE
            .WORD   EXIT


; ----------------------------------------------------------------------
; ." [CORE] 6.1.0190 "dot-quote"
;
; Interpretation:
;   Interpretation semantics for this word are undefined.
;
; Compilation: ( "ccc<quote>" -- )
;   Parse ccc delimited by " (double-quote).  Append the run-time
;   semantics given below to the current definition.
;
; Run-time: ( -- )
;   Display ccc.
;
; ---
; : ." ( "ccc<quote>" --)   POSTPONE S" POSTPONE TYPE ; IMMEDIATE

            LINKTO(DOT,1,2,022h,".")
DOTQUOTE:   JMP     ENTER
            .WORD   SQUOTE,LIT,TYPE,COMPILECOMMA,EXIT


; ----------------------------------------------------------------------
; / [CORE] 6.1.0230 "slash" ( n1 n2 -- n3 )
;
; Divide n1 by n2, giving the single-cell quotient n3.  An ambiguous
; condition exists if n2 is zero.  If n1 and n2 differ in sign, the
; implementation-defined result returned will be the same as that returned
; by either the phrase >R S>D R> FM/MOD SWAP DROP or the phrase
; >R S>D R> SM/REM SWAP DROP.
;
; ---
; : / ( n1 n2 -- n3)   /MOD NIP ;

            LINKTO(DOTQUOTE,0,1,'/',"")
SLASH:      JMP     ENTER
            .WORD   SLASHMOD,NIP,EXIT


; ----------------------------------------------------------------------
; /MOD [CORE] 6.1.0240 "slash-mod" ( n1 n2 -- n3 n4 )
;
; Divide n1 by n2, giving the single-cell remainder n3 and the single-cell
; quotient n4.  An ambiguous condition exists if n2 is zero.  If n1 and n2
; differ in sign, the implementation-defined result returned will be the
; same as that returned by either the phrase >R S>D R> FM/MOD or the phrase
; >R S>D R> SM/REM.
;
; ---
; : /MOD ( n1 n2 -- n3 n4)   >R S>D R> SM/REM ;

            LINKTO(SLASH,0,4,'D',"OM/")
SLASHMOD:   JMP     ENTER
            .WORD   TOR,STOD,RFROM,SMSLASHREM,EXIT


; ----------------------------------------------------------------------
; 0< [CORE] 6.1.0250 "zero-less" ( b -- flag )
;
; flag is true if and only if n is less than zero.

            LINKTO(SLASHMOD,0,2,'<',"0")
ZEROLESS:   POP     H           ; Pop the value.
            MOV     A,H         ; See if the number is < 0 by moving H to A
            ORA     A           ; ..and then ORing A with itself.
            JP      _zlessFALSE ; Jump if positive to where we push false.
            LXI     H,0FFFFh    ; Put true in HL.
            JMP     _zlessDONE  ; We're done.
_zlessFALSE:LXI     H,0         ; Put false in HL.
_zlessDONE: PUSH    H           ; Push the flag to the stack.
            NEXT


; ----------------------------------------------------------------------
; 0= [CORE] 6.1.0270 "zero-equals" ( x -- flag )
;
; flag is true if and only if x is equal to zero.

            LINKTO(ZEROLESS,0,2,'=',"0")
ZEROEQUALS: POP     H           ; Pop the value.
            MOV     A,H         ; See if the flag is zero by moving H to A
            ORA     L           ; ..and then ORing A with L.
            JNZ     _zeqFALSE   ; Jump if not zero to where we push false.
            LXI     H,0FFFFh    ; Put true in HL.
            JMP     _zeqDONE    ; We're done.
_zeqFALSE:  LXI     H,0         ; Put false in HL.
_zeqDONE:   PUSH    H           ; Push the flag to the stack.
            NEXT


; ----------------------------------------------------------------------
; 1+ [CORE] 6.1.0290 "one-plus" ( n1|u1 -- n2|u2 )
;
; Add one (1) to n1|u1 giving the sum n2|u2.

            LINKTO(ZEROEQUALS,0,2,'+',"1")
ONEPLUS:    POP     H           ; Pop the value.
            INX     H           ; Increment the value.
            PUSH    H           ; Push the result onto the stack.
            NEXT


; ----------------------------------------------------------------------
; 1- [CORE] 6.1.0300 "one-minus" ( n1|u1 -- n2|u2 )
;
; Subtract one (1) from n1|u1 giving the difference n2|u2.

            LINKTO(ONEPLUS,0,2,'-',"1")
ONEMINUS:   POP     H           ; Pop the value.
            DCX     H           ; Decrement the value.
            PUSH    H           ; Push the result onto the stack.
            NEXT


; ----------------------------------------------------------------------
; 2! [CORE] 6.1.0310 "two-store" ( x1 x2 a-addr -- )
;
; Store the cell pair x1 x2 at a-addr, with x2 at a-addr and x1 at the
; next consecutive cell.  It is equivalent to the sequence
; SWAP OVER ! CELL+ !.

            LINKTO(ONEMINUS,0,2,'!',"2")
TWOSTORE:   SAVEDE
            POP     D           ; Pop a-addr.
            POP     H           ; Pop x2
            SHLX                ; Save x2.
            INX     D           ; Increment to the
            INX     D           ; ..next cell.
            POP     H           ; Pop x1.
            SHLX                ; Save x1.
            RESTOREDE
            NEXT


; ----------------------------------------------------------------------
; 2* [CORE] 6.1.0320 "two-star" ( x1 -- x2 )
;
; x2 is the result of shifting x1 one bit toward the most-significant bit,
; filling the vacated least-significant bit with zero.

            LINKTO(TWOSTORE,0,2,'*',"2")
TWOSTAR:    POP     H           ; Pop x1.
            DAD     H           ; Double x1.
            PUSH    H           ; Push the result onto the stack.
            NEXT


; ----------------------------------------------------------------------
; 2/ [CORE] 6.1.0330 "two-slash" ( x1 -- x2 )
;
; x2 is the result of shifting x1 one bit toward the least-significant bit,
; leaving the most-significant bit unchanged.

            LINKTO(TWOSTAR,0,2,'/',"2")
TWOSLASH:   POP     H           ; Pop x1.
            ANA     A           ; Clear the carry flag.
            MOV     A,H         ; Move the high byte into A,
            RLC                 ; ..rotate it left
            RRC                 ; ..and then right through carry, then
            RAR                 ; ..divide the high byte,
            MOV     H,A         ; ..and put the high byte back into H.
            MOV     A,L         ; Move the low byte into A,
            RAR                 ; ..divide the low byte,
            MOV     L,A         ; ..and put the low byte back into H.
            PUSH    H           ; Push the result onto the stack.
            NEXT


; ----------------------------------------------------------------------
; 2@ [CORE] 6.1.0350 "two-fetch" ( a-addr -- x1 x2 )
;
; Fetch the cell pair x1 x2 stored at a-addr.  x2 is stored at a-addr
; and x1 at the next consecutive cell.  It is equivalent to the sequence
; DUP CELL+ @ SWAP @.

            LINKTO(TWOSLASH,0,2,'@',"2")
TWOFETCH:   SAVEDE
            POP     D           ; Pop a-addr.
_twofetchDE:LHLX                ; Fetch x2.
            PUSH    H           ; Push x2 (which is wrong, but we'll fix it).
            INX     D           ; Increment
            INX     D           ; ..to x1,
            LHLX                ; ..and fetch x1.
            XTHL                ; Swap TOS (x2) with x1.
            PUSH    H           ; Push x2.
            RESTOREDE
            NEXT


; ----------------------------------------------------------------------
; 2DROP [CORE] 6.1.0370 "two-drop" ( x1 x2 -- )
;
; Drop cell pair x1 x2 from the stack.

            LINKTO(TWOFETCH,0,5,'P',"ORD2")
TWODROP:    POP     H
            POP     H
            NEXT


; ----------------------------------------------------------------------
; 2DUP [CORE] 6.1.0380 "two-dupe" ( x1 x2 -- x1 x2 x1 x2 )
;
; Duplicate cell pair x1 x2.

            LINKTO(TWODROP,0,4,'P',"UD2")
TWODUP:     SAVEDE
            POP     H           ; Pop x2.
            POP     D           ; Pop x1.
            PUSH    D           ; Push x1 back onto the stack.
            PUSH    H           ; Push x2 back onto the stack.
            PUSH    D           ; Push another copy of x1 onto the stack.
            PUSH    H           ; Push another copy of x2 onto the stack.
            RESTOREDE
            NEXT


; ----------------------------------------------------------------------
; 2OVER [CORE] 6.1.0400 "two-over" ( x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2 )
;
; Copy cell pair x1 x2 to the top of the stack.

            LINKTO(TWODUP,0,5,'R',"EVO2")
TWOOVER:    SAVEDE
            LDES    6           ; Get the address of the fourth stack item.
            LHLX                ; Load the fourth stack item into HL.
            PUSH    H           ; Push the fourth stack item onto the stack.
            LDES    6           ; Get the address of the third (now fourth) stack item.
            LHLX                ; Load the third stack item into HL.
            PUSH    H           ; Push the third stack item onto the stack.
            RESTOREDE
            NEXT


; ----------------------------------------------------------------------
; 2SWAP [CORE] 6.1.0430 "two-swap" ( x1 x2 x3 x4 -- x3 x4 x1 x2 )
;
; Exchange the top two cell pairs.

            LINKTO(TWOOVER,0,5,'P',"AWS2")
TWOSWAP:    SAVEDE
            POP     H           ; Pop x4.
            POP     D           ; Pop x3.
            XTHL                ; Swap x4 with x2.
            XCHG                ; Put x2 in DE, x3 in HL.
            DI                  ; Disable interrupts while we mess with SP.
            INX     SP          ; Increment SP
            INX     SP          ; ..to x1.
            XTHL                ; Swap x3 with x1.
            DCX     SP          ; Decrement back
            DCX     SP          ; ..to x4.
            EI                  ; Enable interrupts now that we're done with SP.
            XCHG                ; Put x1 in DE, x2 in HL.
            PUSH    D           ; Push x1.
            PUSH    H           ; Push x2.
            RESTOREDE
            NEXT


; ----------------------------------------------------------------------
; : [CORE] 6.1.0450 "colon" ( C: "<spaces>name" -- colon-sys )
;
; Skip leading space delimiters.  Parse name delimited by a space.  Create
; a definition for name, called a "colon definition".  Enter compilation
; state and start the current definition, producing colon-sys.  Append the
; initiation semantics given below to the current definition.
;
; The execution semantics of name will be determined by the words compiled
; into the body of the definition.  The current definition shall not be
; findable in the dictionary until it is ended (or until the execution of
; DOES> in some systems).
;
; Initiation: ( i*x -- i*x ) ( R: -- nest-sys )
;   Save implementation-dependent information nest-sys about the calling
;   definition.  The stack effects i*x represent arguments to name.
;
; name Execution: ( i*x -- j*x )
;       Execute the definition name.  The stack effects i*x and j*x
;       represent arguments to and results from name, respectively.

; ---
; : : ( "<spaces>name" -- )
;   CREATE HIDE ]  CFASZ NEGATE ALLOT  195 C, DOCOLON , ; -- JMP DOCOLON

            LINKTO(TWOSWAP,0,1,03Ah,"")
COLON:      JMP     ENTER
            .WORD   CREATE,HIDE,RTBRACKET
            .WORD   LIT,-CFASZ,ALLOT,LIT,195,CCOMMA,LIT,DOCOLON,COMMA
            .WORD   EXIT


; ----------------------------------------------------------------------
; ; [CORE] 6.1.0460 "semicolon"
;
; Interpretation:
;   Interpretation semantics for this word are undefined.
;
; Compilation: ( C: colon-sys -- )
;   Append the run-time semantics below to the current definition.  End
;   the current definition, allow it to be found in the dictionary and
;   enter interpretation state, consuming colon-sys.  If the data-space
;   pointer is not aligned, reserve enough data space to align it.
;
; Run-time: ( -- ) ( R: nest-sys -- )
;   Return to the calling definition specified by nest-sys.
;
; ---
; : ; ( -- )   REVEAL  ['] EXIT COMPILE,  POSTPONE [ ; IMMEDIATE

            LINKTO(COLON,1,1,';',"")
SEMICOLON:  JMP     ENTER
            .WORD   REVEAL,LIT,EXIT,COMPILECOMMA,LTBRACKET,EXIT


; ----------------------------------------------------------------------
; < [CORE] 6.1.0480 "less-than" ( n1 n2 -- flag )
;
; flag is true if and only if n1 is less than n2.

            LINKTO(SEMICOLON,0,1,'<',"")
LESSTHAN:   SAVEDE
            POP     D           ; Pop n2.
            POP     H           ; Pop n1.
            MOV     A,D         ; Put n2's high byte into A,
            XRA     H           ; ..XOR that with n1's high byte,
            JM      _lt1        ; ..then skip the DSUB if the signs differ.
            PUSH    B           ; Save BC.
            MOV     B,D         ; Move n2
            MOV     C,E         ; ..to BC.
            DSUB                ; HL=n1-n2
            POP     B           ; Restore BC.
_lt1:       INR     H           ; Increment HL,
            DCR     H           ; ..then decrement HL to check the sign;
            JM      _ltTRUE     ; ..n1 < n2 if HL is negative.
            LXI     H,0         ; Put false in HL.
            JMP     _ltDONE     ; We're done.
_ltTRUE:    LXI     H,0FFFFh    ; Put true in HL.
_ltDONE:    PUSH    H           ; Push the flag to the stack.
            RESTOREDE
            NEXT


; ----------------------------------------------------------------------
; <# [CORE] 6.1.0490 "less-number-sign" ( -- )
;
; Initialize the pictured numeric output conversion process.
;
; ---
; : <# ( -- )   HERE HLDEND + HLD ! ;

            LINKTO(LESSTHAN,0,2,'#',"<")
LESSNUMSIGN:JMP     ENTER
            .WORD   HERE,LIT,HLDEND,PLUS,HLD,STORE
            .WORD   EXIT


; ----------------------------------------------------------------------
; = [CORE] 6.2.0530 "equals" ( x1 x2 -- flag )
;
; flag is true if and only if x1 is bit-for-bit the same as x2.

            LINKTO(LESSNUMSIGN,0,1,'=',"")
EQUALS:     SAVEDE
            POP     H           ; Pop x2.
            POP     D           ; Pop x1.
            PUSH    B           ; Save BC.
            MOV     B,D         ; Move x1
            MOV     C,E         ; ..to BC.
            DSUB                ; HL=HL-BC
            POP     B           ; Restore BC.
            JNZ     _eqFALSE    ; Jump if not equals to where we push false.
            LXI     H,0FFFFh    ; Put true in HL.
            JMP     _eqDONE     ; We're done.
_eqFALSE:   LXI     H,0         ; Put false in HL.
_eqDONE:    PUSH    H           ; Push the flag to the stack.
            RESTOREDE
            NEXT


; ----------------------------------------------------------------------
; > [CORE] 6.1.0540 "greater-than" ( n1 n2 -- flag )
;
; flag is true if and only if n1 is greater than n2.
;
; ---
; : > ( n1 n2 -- flag)   SWAP < ;

            LINKTO(EQUALS,0,1,'>',"")
GREATERTHAN:JMP     ENTER
            .WORD   SWAP,LESSTHAN,EXIT


; ----------------------------------------------------------------------
; >BODY [CORE] 6.1.0550 "to-body" ( xt -- a-addr )
;
; a-addr is the data-field address corresponding to xt.  An ambiguous
; condition exists if xt is not for a word defined via CREATE.
;
; ---
; : >BODY ( xt -- a-addr)   CFASZ + ;

            LINKTO(GREATERTHAN,0,5,'Y',"DOB>")
TOBODY:     JMP     ENTER
            .WORD   LIT,CFASZ,PLUS,EXIT


; ----------------------------------------------------------------------
; >IN [CORE] 6.1.0560 "to-in" ( -- a-addr )
;
; a-addr is the address of a cell containing the offset in characters
; from the start of the input buffer to the start of the parse area.
;
; ---
; : >IN ( -- a-addr)  ICB ICBTOIN + ;

            LINKTO(TOBODY,0,3,'N',"I>")
TOIN:       JMP     ENTER
            .WORD   ICB,LIT,ICBTOIN,PLUS,EXIT


; ----------------------------------------------------------------------
; >NUMBER [CORE] 6.1.0567 "to-number" ( ud1 c-addr1 u1 -- ud2 c-addr2 u2 )
;
; ud2 is the unsigned result of converting the characters within the string
; specified by c-addr1 u1 into digits, using the number in BASE, and adding
; each into ud1 after multiplying ud1 by the number in BASE.  Conversion
; continues left-to-right until a character that is not convertible,
; including any "+" or "-", is encountered or the string is entirely
; converted.  c-addr2 is the location of the first unconverted character or
; the first character past the end of the string if the string was entirely
; converted.  u2 is the number of unconverted characters in the string.  An
; ambiguous condition exists if ud2 overflows during the conversion.
;
; ---
; : >NUMBER ( ud1 c-addr1 u1 -- ud2 c-addr2 u2)
;   2>B  BEGIN B? WHILE
;       B@ DIGIT? 0= IF B B# EXIT THEN
;       ( ud1 u) >R BASE @ UD* R> M+
;   B+ AGAIN  B B# ;

            LINKTO(TOIN,0,7,'R',"EBMUN>")
TONUMBER:   JMP     ENTER
            .WORD   TWOTOB
_tonumber1: .WORD   BQUES,zbranch,_tonumber3
            .WORD   BFETCH,DIGITQ,ZEROEQUALS,zbranch,_tonumber2
            .WORD   B,BNUMBER,EXIT
_tonumber2: .WORD   TOR,BASE,FETCH,UDSTAR,RFROM,MPLUS,BPLUS,branch,_tonumber1
_tonumber3: .WORD   B,BNUMBER
            .WORD   EXIT


; ----------------------------------------------------------------------
; >R [CORE] 6.1.0580 "to-r"
;
; Interpretation:
;   Interpretation semantics for this word are undefined.
;
; Execution: ( x -- ) ( R: -- x )
;   Move x to the return stack.

            LINKTO(TONUMBER,0,2,'R',">")
TOR:        POP     H
            RSPUSH(H,L)
            NEXT


; ----------------------------------------------------------------------
; ?DUP [CORE] 6.1.0630 "question-dupe" ( x -- 0 | x x )
;
; Duplicate x if it is non-zero.

            LINKTO(TOR,0,4,'P',"UD?")
QDUP:       POP     H           ; Pop x into HL.
            MOV     A,H         ; See if the value is zero by moving H to A
            ORA     L           ; ..and then ORing A with L.
            JZ      _qdupONCE   ; Jump if zero to where we push once.
            PUSH    H           ; Push the value (this is the second copy).
_qdupONCE:  PUSH    H           ; Push the value.
            NEXT


; ----------------------------------------------------------------------
; @ [CORE] 6.1.0650 "fetch" ( a-addr -- x )
;
; x is the value stored at a-addr.

            LINKTO(QDUP,0,1,'@',"")
FETCH:      POP     H           ; Pop address to fetch into HL
            MOV     A,M         ; Load LSB of cell value into A
            INX     H           ; Increment to MSB of the cell value
            MOV     H,M         ; Load MSB of the cell value into H
            MOV     L,A         ; Move LSB of cell value from A to L
            PUSH    H           ; Push cell value onto stack.
            NEXT


; ----------------------------------------------------------------------
; ABORT [CORE] 6.1.0670 ( i*x -- ) ( R: j*x -- )
;
; Empty the data stack and perform the function of QUIT, which includes
; emptying the return stack, without displaying a message.
;
; ---
; : ABORT ( i*x -- ) ( R: j*x -- )
;   TASK-PAGE [HEX] FF OR SP!  10 BASE !
;   TASK-PAGE 'FIRSTTASK @ = IF ONLY QUIT ELSE ['] BL STOPPED THEN ;
;
; Our multitasking-aware version of ABORT enters the QUIT loop if this
; is the initial task, otherwise the STOPPED loop is invoked and the
; task effectively becomes inert.  STOPPED needs an xt to call, so we
; give it BL.  That puts a value on the stack, but since STOPPED will
; never exit the value won't bother anyone.
;
; Note that ABORT will also (re-)initialize the search order if it is
; called from the initial task.
;
; The idle word should never return, but we HALT anyway just in case
; someone messes with the return stack.

            LINKTO(FETCH,0,5,'T',"ROBA")
ABORT:      JMP     ENTER
            .WORD   TASKPAGE,LIT,0ffh,OR,SPSTORE
            .WORD   LIT,10,BASE,STORE
            .WORD   TASKPAGE,LIT,TICKFIRSTTASK,FETCH,EQUALS,zbranch,_abort1
            .WORD   ONLY,QUIT,HALT
_abort1:    .WORD   LIT,BL,STOPPED,HALT


; ----------------------------------------------------------------------
; ABORT" [CORE] 6.1.0680 "abort-quote"
;
; Interpretation:
;   Interpretation semantics for this word are undefined.
;
; Compilation: ( "ccc<quote>" -- )
;   Parse ccc delimited by a " (double-quote).  Append the run-time
;   semantics given below to the current definition.
;
; Run-time: ( i*x x1 --  | i*x ) ( R: j*x --  | j*x )
;   Remove x1 from the stack.  If any bit of x1 is not zero, display ccc
;   and perform an implementation-defined abort sequence that includes the
;   function of ABORT.
;
; ---
; : ABORT"   POSTPONE IF POSTPONE ." POSTPONE ABORT THEN ; IMMEDIATE

            LINKTO(ABORT,1,6,022h,"TROBA")
ABORTQUOTE: JMP     ENTER
            .WORD   IF,DOTQUOTE,LIT,ABORT,COMPILECOMMA,THEN,EXIT


; ----------------------------------------------------------------------
; ABS [CORE] 6.1.0690 "abs" ( n -- u )
;
; u is the absolute value of n.
;
; ---
; : ABS ( n -- u )   DUP ?NEGATE ;

            LINKTO(ABORTQUOTE,0,3,'S',"BA")
ABS:        JMP     ENTER
            .WORD   DUP,QNEGATE,EXIT


; ----------------------------------------------------------------------
; ACCEPT [CORE] 6.1.0695 ( c-addr +n1 -- +n2 )
;
; Receive a string of at most +n1 characters.  An ambiguous condition
; exists if +n1 is zero or greater than 32,767.  Display graphic
; characters as they are received.  A program that depends on the
; presence or absence of non-graphic characters in the string has an
; environmental dependency.  The editing functions, if any, that the
; system performs in order to construct the string are
; implementation-defined.
;
; Input terminates when an implementation-defined line terminator is
; received.  When input terminates, nothing is appended to the string,
; and the display is maintained in an implementation-defined way.
;
; +n2 is the length of the string stored at c-addr.
;
; ---
; : ACCEPT ( c-addr max -- n)
;   2DUP 2>B DROP  ( ca-start)
;   BEGIN  KEY  DUP 13 <> WHILE
;       DUP 8 = IF
;           ( ca-start bs) DROP  B OVER - IF 8 EMIT BL EMIT 8 EMIT -1 'B +! THEN
;       ELSE
;           B? IF DUP EMIT B!+ ELSE DROP THEN
;       THEN
;   REPEAT
;   ( ca-start cr) DROP  B SWAP - ;

            LINKTO(ABS,0,6,'T',"PECCA")
ACCEPT:     JMP     ENTER
            .WORD   TWODUP,TWOTOB,DROP
_accept1:   .WORD   KEY,DUP,LIT,13,NOTEQUALS,zbranch,_accept5
            .WORD   DUP,LIT,8,EQUALS,zbranch,_accept2
            .WORD   DROP,B,OVER,MINUS,zbranch,_accept4
            .WORD   LIT,8,EMIT,BL,EMIT,LIT,8,EMIT
            .WORD       LIT,-1,TICKB,PLUSSTORE,branch,_accept4
_accept2:   .WORD   BQUES,zbranch,_accept3,DUP,EMIT,BSTOREPLUS,branch,_accept4
_accept3:   .WORD   DROP
_accept4:   .WORD   branch,_accept1
_accept5:   .WORD   DROP,B,SWAP,MINUS
            .WORD   EXIT


; ----------------------------------------------------------------------
; ALIGN [CORE] 6.1.0705 ( -- )
;
; If the data-space pointer is not aligned, reserve enough space to align it.

            LINKTO(ACCEPT,0,5,'N',"GILA")
ALIGN:      NEXT                ; No-op in MFORTH; no alignment needed.


; ----------------------------------------------------------------------
; ALIGNED [CORE] 6.1.0706 ( addr -- a-addr )
;
; a-addr is the first aligned address greater than or equal to addr.

            LINKTO(ALIGN,0,7,'D',"ENGILA")
ALIGNED:    NEXT                ; No-op in MFORTH; no alignment needed.


; ----------------------------------------------------------------------
; ALLOT [CORE] 6.1.0710 ( n -- )
;
; If n is greater than zero, reserve n address units of data space.  If
; n is less than zero, release |n| address units of data space.  If n is
; zero, leave the data-space pointer unchanged.
;
; If the data-space pointer is aligned and n is a multiple of the size of
; a cell when ALLOT begins execution, it will remain aligned when ALLOT
; finishes execution.
;
; If the data-space pointer is character aligned and n is a multiple of
; the size of a character when ALLOT begins execution, it will remain
; character aligned when ALLOT finishes execution.
;
; ---
; : ALLOT ( n -- )   DP +! ;

            LINKTO(ALIGNED,0,5,'T',"OLLA")
ALLOT:      JMP     ENTER
            .WORD   LIT,DP,PLUSSTORE,EXIT


; ----------------------------------------------------------------------
; AND [CORE] 6.1.0720 ( x1 x2 -- x3 )
;
; x3 is the bit-by-bit logical "and" of x1 with x2.

            LINKTO(ALLOT,0,3,'D',"NA")
AND:        SAVEDE
            POP     H           ; Pop x2.
            POP     D           ; Pop x1.
            MOV     A,H         ; Put x2's high byte into A,
            ANA     D           ; ..then AND x1's high byte with A,
            MOV     H,A         ; ..and put the result into H.
            MOV     A,L         ; Put x2's low byte into A,
            ANA     E           ; ..then AND x1's low byte with A,
            MOV     L,A         ; ..and put the result into L.
            PUSH    H           ; Push the result (HL).
            RESTOREDE
            NEXT


; ----------------------------------------------------------------------
; BASE [CORE] 6.1.0750 ( -- a-addr )
;
; a-addr is the address of a cell containing the current number-conversion
; radix {{2...36}}.

            LINKTO(AND,0,4,'E',"SAB")
BASE:       JMP     DOUSER
            .BYTE   USERBASE


; ----------------------------------------------------------------------
; BEGIN [CORE] 6.1.0760
;
; Interpretation:
;   Interpretation semantics for this word are undefined.
;
; Compilation: ( C: -- dest )
;   Put the next location for a transfer of control, dest, onto the control
;   flow stack.  Append the run-time semantics given below to the current
;   definition.
;
; Run-time: ( -- )
;   Continue execution.
;
; ---
; : BEGIN   HERE ; IMMEDIATE

            LINKTO(BASE,1,5,'N',"IGEB")
BEGIN:      JMP     ENTER
            .WORD   HERE,EXIT


; ----------------------------------------------------------------------
; BL [CORE] 6.1.0770 "b-l" ( -- char )
;
; char is the character value for a space.

            LINKTO(BEGIN,0,2,'L',"B")
BL:         LXI     H,020h
            PUSH    H
            NEXT


; ----------------------------------------------------------------------
; C! [CORE] 6.1.0850 "c-store" ( char c-addr -- )
;
; Store char at c-addr.  When character size is smaller than cell size,
; only the number of low-order bits corresponding to character size are
; transferred.

            LINKTO(BL,0,2,'!',"C")
CSTORE:     SAVEDE
            POP     H           ; Pop c-addr.
            POP     D           ; Pop char
            MOV     M,E         ; Store LSB of char value.
            RESTOREDE
            NEXT


; ----------------------------------------------------------------------
; C, [CORE] 6.1.0860 "c-comma" ( char -- )
;
; Reserve space for one character in the data space and store char in the
; space.  If the data-space pointer is character aligned when C, begins
; execution, it will remain character aligned when C, finishes execution.
; An ambiguous condition exists if the data-space pointer is not
; character-aligned prior to execution of C,.
;
; ---
; : C, ( char -- )   HERE C!  1 CHARS ALLOT ;

            LINKTO(CSTORE,0,2,02Ch,"C")
CCOMMA:     JMP     ENTER
            .WORD   HERE,CSTORE,ONE,CHARS,ALLOT,EXIT


; ----------------------------------------------------------------------
; C@ [CORE] 6.1.0870 "c-fetch" ( c-addr -- char )
;
; Fetch the character stored at c-addr.  When the cell size is greater
; than character size, the unused high-order bits are all zeroes.

            LINKTO(CCOMMA,0,2,'@',"C")
CFETCH:     POP     H           ; Pop address to fetch into HL.
            MOV     L,M         ; Load character into low byte of HL.
            MVI     H,0         ; Clear high byte of HL.
            PUSH    H           ; Push character value onto stack.
            NEXT


; ----------------------------------------------------------------------
; CELL+ [CORE] 6.1.0880 "cell-plus" ( a-addr1 -- a-addr2 )
;
; Add the size in address units of a cell to a-addr1, giving a-addr2.

            LINKTO(CFETCH,0,5,'+',"LLEC")
CELLPLUS:   POP     H           ; Pop a-addr1.
            INX     H           ; Add two (the size of a cell)
            INX     H           ; ..to a-addr1.
            PUSH    H           ; Push the result to the stack.
            NEXT


; ----------------------------------------------------------------------
; CELLS [CORE] 6.1.0890 ( n1 -- n2 )
;
; n2 is the size in address units of n1 cells.

            LINKTO(CELLPLUS,0,5,'S',"LLEC")
CELLS:      POP     H           ; Pop x1.
            DAD     H           ; Double x1 (cells are two bytes wide).
            PUSH    H           ; Push the result onto the stack.
            NEXT


; ----------------------------------------------------------------------
; CHAR [CORE] 6.1.0895 "char" ( "<spaces>name" -- char )
;
; Skip leading space delimiters.  Parse name delimited by a space.  Put
; the value of its first character onto the stack.
;
; ---
; : CHAR ( "<spaces>name" -- char)   PARSE-WORD DROP C@ ;

            LINKTO(CELLS,0,4,'R',"AHC")
CHAR:       JMP     ENTER
            .WORD   PARSEWORD,DROP,CFETCH,EXIT


; ----------------------------------------------------------------------
; CHAR+ [CORE] 6.1.0897 "char-plus" ( c-addr1 -- c-addr2 )
;
; Add the size in address units of a character to c-addr1, giving c-addr2.

            LINKTO(CHAR,0,5,'+',"RAHC")
CHARPLUS:   POP     H           ; Pop c-addr1.
            INX     H           ; Add one (the size of a char) to c-addr1.
            PUSH    H           ; Push the result to the stack.
            NEXT


; ----------------------------------------------------------------------
; CHARS [CORE] 6.1.0898 "chars" ( n1 -- n2 )
;
; n2 is the size in address units of n1 characters.

            LINKTO(CHARPLUS,0,5,'S',"RAHC")
CHARS:      NEXT                ; No-op in MFORTH, because chars are 1 byte.


; ----------------------------------------------------------------------
; CONSTANT [CORE] 6.1.0950 ( x "<spaces>name" -- )
;
; Skip leading space delimiters.  Parse name delimited by a space.  Create
; a definition for name with the execution semantics defined below.
;
; name is referred to as a "constant".
;
; name Execution: ( -- x )
;   Place x on the stack.
;
; ---
; : CONSTANT ( x "<spaces>name" -- )
;   CREATE  CFASZ NEGATE ALLOT  195 C, DOCONSTANT ,  , ; -- JMP DOCONSTANT

            LINKTO(CHARS,0,8,'T',"NATSNOC")
CONSTANT:   JMP     ENTER
            .WORD   CREATE,LIT,-CFASZ,ALLOT,LIT,195,CCOMMA,LIT,DOCONSTANT,COMMA
            .WORD   COMMA,EXIT


; ----------------------------------------------------------------------
; COUNT [CORE] 6.1.0980 ( c-addr1 -- c-addr2 u )
;
; Return the character string specification for the counted string stored
; at c-addr1.  c-addr2 is the address of the first character after c-addr1.
; u is the contents of the character at c-addr1, which is the length in
; characters of the string at c-addr2.

            LINKTO(CONSTANT,0,5,'T',"NUOC")
COUNT:      POP     H           ; Pop the address into HL.
            MOV     A,M         ; Fetch the string count into A.
            INX     H           ; Increment HL to the address of the string.
            PUSH    H           ; Push the address of the string to the stack.
            MVI     H,0         ; Clear the high byte of HL,
            MOV     L,A         ; ..set the low byte to the count,
            PUSH    H           ; ..and push the count to the stack.
            NEXT


; ----------------------------------------------------------------------
; CR [CORE] 6.1.0990 "c-r" ( -- )
;
; Cause subsequent output to appear at the beginning of the next line.

            LINKTO(COUNT,0,2,'R',"C")
CR:         CALL    STDCALL     ; Call the
            .WORD   04222h      ; .."Send CRLF" routine.
            NEXT


; ----------------------------------------------------------------------
; CREATE [CORE] 6.1.1000 ( "<spaces>name" -- )
;
; Skip leading space delimiters.  Parse name delimited by a space.  Create
; a definition for name with the execution semantics defined below.  If
; the data-space pointer is not aligned, reserve enough data space to
; align it.  The new data-space pointer defines name's data field.  CREATE
; does not allocate data space in name's data field.
;
;   name Execution: ( -- a-addr )
;       a-addr is the address of name's data field.  The execution
;       semantics of name may be extended by using DOES>.
;
; ---
; : CREATE ( "<spaces>name" -- )
;   PARSE-WORD  DUP 0= IF ABORT THEN DUP 63 > IF ABORT THEN
;   2>B  B# 1+ ALLOT  HERE 1-  B# OVER C!
;   FORB 1- B@ OVER C! NEXTB  DUP C@ 128 OR SWAP C!
;   LATEST @ ,  [ PROFILER ] [IF] 0 , [THEN]
;   HERE NFATOCFASZ - LATEST !  195 C, DOCREATE , -- JMP DOCREATE
;

            LINKTO(CR,0,6,'E',"TAERC")
CREATE:     JMP     ENTER
            .WORD   PARSEWORD,DUP,ZEROEQUALS,zbranch,_create1,ABORT
_create1:   .WORD   DUP,LIT,63,GREATERTHAN,zbranch,_create2,ABORT
_create2:   .WORD   TWOTOB,BNUMBER,ONEPLUS,ALLOT,HERE,ONEMINUS
            .WORD       BNUMBER,OVER,CSTORE
_create3:   .WORD   BQUES,zbranch,_create4,ONEMINUS,BFETCH,OVER,CSTORE
            .WORD       BPLUS,branch,_create3
_create4:   .WORD   DUP,CFETCH,LIT,128,OR,SWAP,CSTORE
            .WORD   LATEST,FETCH,COMMA
#IFDEF PROFILER
            .WORD   ZERO,COMMA
#ENDIF
            .WORD   HERE,LIT,NFATOCFASZ,MINUS,LATEST,STORE
            .WORD       LIT,195,CCOMMA,LIT,DOCREATE,COMMA
            .WORD   EXIT


; ----------------------------------------------------------------------
; DECIMAL [CORE] 6.1.1170 ( -- )
;
; Set the numeric conversion radix to ten (decimal).

            LINKTO(CREATE,0,7,'L',"AMICED")
DECIMAL:    JMP     ENTER
            .WORD   LIT,10,BASE,STORE,EXIT


; ----------------------------------------------------------------------
; DEPTH [CORE] 6.1.1200 ( -- +n )
;
; +n is the number of single-cell values contained in the data stack
; before +n was placed on the stack.
;
; ---
; : DEPTH ( -- +n)   SP  TASK-PAGE [HEX] FF OR  SWAP - 2/ ;

            LINKTO(DECIMAL,0,5,'H',"TPED")
DEPTH:      JMP     ENTER
            .WORD   SP,TASKPAGE,LIT,0ffh,OR,SWAP,MINUS,TWOSLASH,EXIT


; ----------------------------------------------------------------------
; DO [CORE] 6.1.1240
;
; Interpretation:
;   Interpretation semantics for this word are undefined.
;
; Compilation: ( C: -- do-sys )
;   Place do-sys onto the control-flow stack.  Append the run-time
;   semantics given below to the current definition.  The semantics are
;   incomplete until resolved by a consumer of do-sys such as LOOP.
;
; Run-time: ( n1|u1 n2|u2 -- ) ( R: -- loop-sys )
;   Set up loop control parameters with index n2|u2 and limit n1|u1. An
;   ambiguous condition exists if n1|u1 and n2|u2 are not both the same
;   type.  Anything already on the return stack becomes unavailable until
;   the loop-control parameters are discarded.
;
; ---
; do-sys in MFORTH is ( do-orig ).  LEAVE locations chain from the most
; recent LEAVE to the oldest LEAVE and then to zero, which signifies the
; end of the LEAVE list.  LOOP/+LOOP go through the LEAVE list and fix
; up the addresses.
;
; : DO   0 'PREVLEAVE !  ['] (do) COMPILE,  HERE ; IMMEDIATE

            LINKTO(DEPTH,1,2,'O',"D")
DO:         JMP     ENTER
            .WORD   ZERO,LIT,TICKPREVLEAVE,STORE,LIT,pdo,COMPILECOMMA,HERE,EXIT


; ----------------------------------------------------------------------
; DOES> [CORE] 6.1.1250
;
; Interpretation:
;   Interpretation semantics for this word are undefined.
;
; Compilation: ( C: colon-sys1 -- colon-sys2 )
;   Append the run-time semantics below to the current definition.  Whether
;   or not the current definition is rendered findable in the dictionary by
;   the compilation of DOES> is implementation defined.  Consume colon-sys1
;   and produce colon-sys2.  Append the initiation semantics given below to
;   the current definition.
;
; Run-time: ( -- ) ( R: nest-sys1 -- )
;   Replace the execution semantics of the most recent definition, referred
;   to as name, with the name execution semantics given below.  Return
;   control to the calling definition specified by nest-sys1.  An ambiguous
;   condition exists if name was not defined with CREATE or a user-defined
;   word that calls CREATE.
;
; Initiation: ( i*x -- i*x a-addr ) ( R: -- nest-sys2 )
;   Save implementation-dependent information nest-sys2 about the calling
;   definition.  Place name's data field address on the stack.  The stack
;   effects i*x represent arguments to name.
;
; name Execution: ( i*x -- j*x )
;   Execute the portion of the definition that begins with the initiation
;   semantics appended by the DOES> which modified name.  The stack effects
;   i*x and j*x represent arguments to and results from name, respectively.
;
; ---
; : (does>)
;   R>                  -- Get the new CFA for this def'n, which also exits
;                       -- the current def'n since we just popped the defining
;                       -- word's address from the return stack.
;   LATEST @ NFA>CFA    -- Get address of LATEST's CFA.
;   195 OVER C!  1+ !   -- Replace CFA with a JMP (195) to the code after DOES>
;                       -- which in our implementation is CALL DODOES and then
;                       -- the high-level thread after DOES>.
; ;
;
; : DOES> ( -- )
;   ['] (does>) COMPILE,  205 C, DODOES , -- CALL DODOES
; ; IMMEDIATE

            LINKTO(DO,1,5,'>',"SEOD")
DOES:       JMP     ENTER
            .WORD   LIT,pdoes,COMPILECOMMA,LIT,205,CCOMMA,LIT,DODOES,COMMA,EXIT
pdoes:      JMP     ENTER
            .WORD   RFROM,LATEST,FETCH,NFATOCFA
            .WORD   LIT,195,OVER,CSTORE,ONEPLUS,STORE,EXIT


; ----------------------------------------------------------------------
; DROP [CORE] 6.1.1260  ( x -- )
;
; Remove x from the stack.

            LINKTO(DOES,0,4,'P',"ORD")
DROP:       POP     H
            NEXT


; ----------------------------------------------------------------------
; DUP [CORE] 6.1.1290 "dupe" ( x -- x x )
;
; Duplicate x.

            LINKTO(DROP,0,3,'P',"UD")
DUP:        POP     H
            PUSH    H
            PUSH    H
            NEXT


; ----------------------------------------------------------------------
; ELSE [CORE] 6.1.1310
;
; Interpretation:
;   Interpretation semantics for this word are undefined.
;
; Compilation: ( C: orig1 -- orig2 )
;   Put the location of a new unresolved forward reference orig2 onto the
;   control flow stack.  Append the run-time semantics given below to the
;   current definition.  The semantics will be incomplete until orig2 is
;   resolved (e.g., by THEN).  Resolve the forward reference orig1 using
;   the location following the appended  run-time semantics.
;
; Run-time: ( -- )
;   Continue execution at the location given by the resolution of orig2.
;
; ---
; : ELSE   ['] branch COMPILE,  HERE DUP ,  SWAP POSTPONE THEN ; IMMEDIATE

            LINKTO(DUP,1,4,'E',"SLE")
ELSE:       JMP     ENTER
            .WORD   LIT,branch,COMPILECOMMA,HERE,DUP,COMMA,SWAP,THEN,EXIT


; ----------------------------------------------------------------------
; EMIT [CORE] 6.1.1320 ( x -- )
;
; If x is a graphic character in the implementation-defined character set,
; display x.  The effect of EMIT for all other values of x is
; implementation-defined.
;
; When passed a character whose character-defining bits have a value between
; hex 20 and 7E inclusive, the corresponding standard character, specified by
; 3.1.2.1 Graphic characters, is displayed.  Because different output devices
; can respond differently to control characters, programs that use control
; characters to perform specific functions have an environmental dependency.
; Each EMIT deals with only one character.

            LINKTO(ELSE,0,4,'T',"IME")
EMIT:       POP     H           ; Pop the character into HL
            MOV     A,L         ; ..and then move it into A.
            CALL    STDCALL     ; Call the
            .WORD   04B44h      ; .."character output" routine.
            NEXT


; ----------------------------------------------------------------------
; ENVIRONMENT? [CORE] 6.1.1345 "environment-query" ( c-addr u -- false | i*x true )
;
; c-addr is the address of a character string and u is the string's character
; count.  u may have a value in the range from zero to an implementation-defined
; maximum which shall not be less than 31.  The character string should contain
; a keyword from 3.2.6 Environmental queries or the optional word sets to be
; checked for correspondence with an attribute of the present environment.  If
; the system treats the attribute as unknown, the returned flag is false;
; otherwise, the flag is true and the i*x returned is of the type specified in
; the table for the attribute queried.
;
; TODO: Implement ENVIRONMENT?


; ----------------------------------------------------------------------
; EVALUATE [CORE] 6.2.1360 ( i*x c-addr u -- j*x )
;
; Save the current input source specification.  Store minus-one (-1) in
; SOURCE-ID if it is present.  Make the string described by c-addr and u
; both the input source and input buffer, set >IN to zero, and interpret.
; When the parse area is empty, restore the prior input source specification.
; Other stack effects are due to the words EVALUATEd.
;
; ---
; : EVALUATE ( i*x c-addr u -- j*x)
;   PUSHICB  OVER + ICB 2!  -1 ICB ICBSOURCEID + !  INTERPRET  POPICB ;

            LINKTO(EMIT,0,8,'E',"TAULAVE")
EVALUATE:   JMP     ENTER
            .WORD   PUSHICB,OVER,PLUS,ICB,TWOSTORE
            .WORD   LIT,-1,ICB,LIT,ICBSOURCEID,PLUS,STORE
            .WORD   INTERPRET,POPICB,EXIT


; ----------------------------------------------------------------------
; EXECUTE [CORE] 6.1.1370 ( i*x xt -- j*x )
;
; Remove xt from the stack and perform the semantics identified by it.
; Other stack effects are due to the word EXECUTEd.

            LINKTO(EVALUATE,0,7,'E',"TUCEXE")
EXECUTE:    POP     H           ; Pop xt.
            PCHL                ; Execute xt.


; ----------------------------------------------------------------------
; EXIT [CORE] 6.1.1380
;
; Interpretation:
;   Interpretation semantics for this word are undefined.
;
; Execution: ( -- ) ( R: nest-sys -- )
;   Return control to the calling definition specified by nest-sys.  Before
;   executing EXIT within a do-loop, a program shall discard the loop-control
;   parameters by executing UNLOOP.

            LINKTO(EXECUTE,0,4,'T',"IXE")
EXIT:       RSPOP(D,E)
            NEXT


; ----------------------------------------------------------------------
; FILL [CORE] 6.1.1540 ( c-addr u char -- )
;
; If u is greater than zero, store char in each of u consecutive
; characters of memory beginning at c-addr.
;
; ---
; : FILL ( c-addr u char --)   ROT ROT 2>B FORB DUP B! NEXTB DROP ;

            LINKTO(EXIT,0,4,'L',"LIF")
FILL:       JMP     ENTER
            .WORD   ROT,ROT,TWOTOB
_fill1:     .WORD   BQUES,zbranch,_fill2
            .WORD   DUP,BSTORE,BPLUS,branch,_fill1
_fill2:     .WORD   DROP,EXIT


; ----------------------------------------------------------------------
; FIND [CORE] 6.1.1550 ( c-addr -- c-addr 0 | xt 1 | xt -1 )
;
; Find the definition named in the counted string at c-addr.  If the
; definition is not found after searching all the word lists in the
; search order, return c-addr and zero.  If the definition is found,
; return xt.  If the definition is immediate, also return one (1);
; otherwise also return minus-one (-1).  For a given string, the values
; returned by FIND while compiling may differ from those returned while
; not compiling.
;
; ---
; : FIND ( c-addr -- c-addr 0 | xt 1 | xt -1 )
;   COUNT (FIND) ?DUP 0= IF DROP 1- 0 THEN ;

            LINKTO(FILL,0,4,'D',"NIF")
FIND:       JMP     ENTER
            .WORD   COUNT,PFIND,QDUP,ZEROEQUALS,zbranch,_find1
            .WORD   DROP,ONEMINUS,ZERO
_find1:     .WORD   EXIT


; ----------------------------------------------------------------------
; FM/MOD [CORE] 6.1.1561 "f-m-slash-mod" ( d1 n1 -- n2 n3 )
;
; Divide d1 by n1, giving the floored quotient n3 and the remainder n2.
; Input and output stack arguments are signed.  An ambiguous condition
; exists if n1 is zero or if the quotient lies outside the range of a
; single-cell signed integer.
;
; ---
; Floored division is integer division in which the remainder carries the
; sign of the divisor or is zero, and the quotient is rounded to its
; arithmetic floor.
;
; ---
; : FM/MOD ( d1 n1 -- n2 n3)
;   DUP >R ( num den R:signrem) 2DUP XOR ( num den signquo R:signrem)
;   SWAP ABS DUP >R ( num signquo +den R:signrem +den)
;   SWAP >R >R DABS R> ( num +den R:signrem +den signquo) SM/REM ( rem quo R:..)
;   R> 0< IF NEGATE OVER 0<> IF 1- SWAP R> SWAP - SWAP ELSE R> DROP THEN
;       ELSE R> DROP THEN
;   R> 0< IF SWAP NEGATE SWAP THEN ;

            LINKTO(FIND,0,6,'D',"OM/MF")
FMSLASHMOD: JMP     ENTER
            .WORD   DUP,TOR,TWODUP,XOR,SWAP,ABS,DUP,TOR
            .WORD   SWAP,TOR,TOR,DABS,RFROM,UMSLASHMOD
            .WORD   RFROM,ZEROLESS,zbranch,_fmslashmod1
            .WORD   NEGATE,OVER,ZERONOTEQUALS,zbranch,_fmslashmod1
            .WORD   ONEMINUS,SWAP,RFROM,SWAP,MINUS,SWAP,branch,_fmslashmod2
_fmslashmod1:.WORD  RFROM,DROP
_fmslashmod2:.WORD  RFROM,ZEROLESS,zbranch,_fmslashmod3
            .WORD   SWAP,NEGATE,SWAP
_fmslashmod3:.WORD  EXIT


; ----------------------------------------------------------------------
; HERE [CORE] 6.1.1650 ( -- addr )
;
; addr is the data-space pointer.

            LINKTO(FMSLASHMOD,0,4,'E',"REH")
HERE:       LHLD    DP
            PUSH    H
            NEXT


; ----------------------------------------------------------------------
; HOLD [CORE] 6.1.1670 ( char -- )
;
; Add char to the beginning of the pictured numeric output string.  An
; ambiguous condition exists if HOLD executes outside of a <# #> delimited
; number conversion.
;
; ---
; : HOLD ( c -- )   HLD @ 1- DUP HLD ! C! ;

            LINKTO(HERE,0,4,'D',"LOH")
HOLD:       JMP     ENTER
            .WORD   HLD,FETCH,ONEMINUS,DUP,HLD,STORE,CSTORE
            .WORD   EXIT


; ----------------------------------------------------------------------
; I [CORE] 6.1.1680
;
; Interpretation:
;   Interpretation semantics for this word are undefined.
;
; Execution: ( -- n|u ) ( R:  loop-sys -- loop-sys )
;   n|u is a copy of the current (innermost) loop index.  An ambiguous
;   condition exists if the loop control parameters are unavailable.

            LINKTO(HOLD,0,1,'I',"")
I:          RSFETCH(H,L)        ; Get the loop index into HL
            PUSH    H           ; ..and push it onto the stack.
            NEXT


; ----------------------------------------------------------------------
; IF [CORE] 6.1.1700
;
; Interpretation:
;   Interpretation semantics for this word are undefined.
;
; Compilation: ( C: -- orig )
;   Put the location of a new unresolved forward reference orig onto the
;   control flow stack. Append the run-time semantics given below to the
;   current definition.  The semantics are incomplete until orig is resolved,
;   e.g., by THEN or ELSE.
;
; Run-time: ( x -- )
;   If all bits of x are zero, continue execution at the location specified
;   by the resolution of orig.
;
; ---
; : IF   ['] 0branch COMPILE,  HERE DUP , ; IMMEDIATE

            LINKTO(I,1,2,'F',"I")
IF:         JMP     ENTER
            .WORD   LIT,zbranch,COMPILECOMMA,HERE,DUP,COMMA,EXIT


; ----------------------------------------------------------------------
; IMMEDIATE [CORE] 6.1.1710 ( -- )
;
; Make the most recent definition an immediate word.  An ambiguous
; condition exists if the most recent definition does not have a name.
;
; ---
; : IMMEDIATE ( -- )   LATEST @  DUP C@ [HEX] 80 OR  SWAP C! ;

            LINKTO(IF,0,9,'E',"TAIDEMMI")
IMMEDIATE:  JMP     ENTER
            .WORD   LATEST,FETCH,DUP,CFETCH,LIT,080h,OR,SWAP,CSTORE,EXIT


; ----------------------------------------------------------------------
; INVERT [CORE] 6.1.1720 ( x1 -- x2 )
;
; Invert all bits of x1, giving its logical inverse x2.

            LINKTO(IMMEDIATE,0,6,'T',"REVNI")
INVERT:     POP     H           ; Pop x1.
            MOV     A,H         ; Put x1's high byte into A,
            CMA                 ; ..then complement x1's high byte,
            MOV     H,A         ; ..and put the result back into H.
            MOV     A,L         ; Put x1's low byte into A,
            CMA                 ; ..then complement x1's low byte,
            MOV     L,A         ; ..and put the result back into L.
            PUSH    H           ; Push the result (HL).
            NEXT


; ----------------------------------------------------------------------
; J [CORE] 6.1.1730
;
; Interpretation:
;   Interpretation semantics for this word are undefined.
;
; Execution: ( -- n|u ) ( R: loop-sys1 loop-sys2 -- loop-sys1 loop-sys2 )
;   n|u is a copy of the next-outer loop index.  An ambiguous condition
;   exists if the loop control parameters of the next-outer loop, loop-sys1,
;   are unavailable.

            LINKTO(INVERT,0,1,'J',"")
J:          RSPICK2(H,L)        ; Get the second loop index (the 3rd RS item)
            PUSH    H           ; ..into HL and push it onto the stack.
            NEXT


; ----------------------------------------------------------------------
; KEY [CORE] 6.1.1750 ( -- char )
;
; Receive one character char, a member of the implementation-defined
; character set.  Keyboard events that do not correspond to such characters
; are discarded until a valid character is received, and those events are
; subsequently unavailable.
;
; All standard characters can be received.  Characters received by KEY are
; not displayed.
;
; Any standard character returned by KEY has the numeric value specified in
; 3.1.2.1 Graphic characters.  Programs that require the ability to receive
; control characters have an environmental dependency.
;
; ---
; NOTE: Wake up from power off generates a null key event, which we need
; to ignore.
;
; : KEY ( -- char)   BEGIN  BEGIN PAUSE KEY? UNTIL  (KEY) ?DUP 0<> UNTIL ;

            LINKTO(J,0,3,'Y',"EK")
KEY:        JMP     ENTER
_key1:      .WORD   PAUSE,KEYQ,zbranch,_key1
            .WORD   PKEY,QDUP,ZERONOTEQUALS,zbranch,_key1
            .WORD   EXIT


; ----------------------------------------------------------------------
; LEAVE [CORE] 6.1.1760
;
; Interpretation:
;   Interpretation semantics for this word are undefined.
;
; Execution: ( -- ) ( R: loop-sys -- )
;   Discard the current loop control parameters.  An ambiguous condition
;   exists if they are unavailable.  Continue execution immediately
;   following the innermost syntactically enclosing DO ... LOOP or
;   DO ... +LOOP.
;
; ---
; LEAVE ( do-orig)
;   ['] UNLOOP COMPILE,  ['] branch COMPILE,
;   HERE  'PREVLEAVE @ ,  'PREVLEAVE !
; ; IMMEDIATE

            LINKTO(KEY,1,5,'E',"VAEL")
LEAVE:      JMP     ENTER
            .WORD   LIT,UNLOOP,COMPILECOMMA,LIT,branch,COMPILECOMMA
            .WORD   HERE,LIT,TICKPREVLEAVE,FETCH,COMMA
            .WORD   LIT,TICKPREVLEAVE,STORE,EXIT


; ----------------------------------------------------------------------
; LITERAL [CORE] 6.1.1780
;
; Interpretation:
;   Interpretation semantics for this word are undefined.
;
; Compilation: ( x -- )
;   Append the run-time semantics given below to the current definition.
;
; Run-time: ( -- x )
;   Place x on the stack.
;
; ---
; : LITERAL ( x -- )   ['] LIT COMPILE,  ,  ; IMMEDIATE

            LINKTO(LEAVE,1,7,'L',"ARETIL")
LITERAL:    JMP     ENTER
            .WORD   LIT,LIT,COMPILECOMMA,COMMA,EXIT


; ----------------------------------------------------------------------
; LOOP [CORE] 6.1.1800
;
; Interpretation:
;   Interpretation semantics for this word are undefined.
;
; Compilation: ( C: do-sys -- )
;   Append the run-time semantics given below to the current definition.
;   Resolve the destination of all unresolved occurrences of LEAVE between
;   the location given by do-sys and the next location for a transfer of
;   control, to execute the words following the LOOP.
;
; Run-time: ( -- ) ( R: loop-sys1 -- | loop-sys2 )
;   An ambiguous condition exists if the loop control parameters are
;   unavailable.  Add one to the loop index.  If the loop index is then
;   equal to the loop limit, discard the loop parameters and continue
;   execution immediately following the loop.  Otherwise continue execution
;   at the beginning of the loop.
;
; ---
; : LOOP   ['] (loop) END-LOOP ; IMMEDIATE

            LINKTO(LITERAL,1,4,'P',"OOL")
LOOP:       JMP     ENTER
            .WORD   LIT,ploop,ENDLOOP,EXIT


; ----------------------------------------------------------------------
; LSHIFT [CORE] 6.1.1805 "l-shift" ( x1 u -- x2 )
;
; Perform a logical left shift of u bit-places on x1, giving x2.  Put
; zeroes into the least significant bits vacated by the shift.  An
; ambiguous condition exists if u is greater than or equal to the number
; of bits in a cell.

            LINKTO(LOOP,0,6,'T',"FIHSL")
LSHIFT:     POP     H           ; Pop u into HL,
            MOV     A,L         ; ..then move the low byte into H.
            POP     H           ; Pop x1 into HL.
_lshift1:   ANA     A           ; See if the count is zero;
            JZ      _lshiftDONE ; ..we're done if so.
            DAD     H           ; Left-shift HL by adding HL to itself.
            DCR     A           ; Decrement the counter
            JMP     _lshift1    ; ..and continue looping.
_lshiftDONE:PUSH    H           ; Push the result (HL).
            NEXT


; ----------------------------------------------------------------------
; M* [CORE] 6.1.1810 "m-star" ( n1 n2 -- d )
;
; d is the signed product of n1 times n2.
;
; ---
; : M* ( n1 n2 -- d )   2DUP XOR 0< >R  ABS SWAP ABS UM*  R> ?DNEGATE ;

            LINKTO(LSHIFT,0,2,'*',"M")
MSTAR:      JMP     ENTER
            .WORD   TWODUP,XOR,ZEROLESS,TOR,ABS,SWAP,ABS,UMSTAR
            .WORD   RFROM,QDNEGATE,EXIT


; ----------------------------------------------------------------------
; MAX [CORE] 6.1.1870 ( n1 n2 -- n3 )
;
; n3 is the greater of n1 and n2.
;
; ---
; : MAX ( n1 n2 -- n3 )   2DUP < IF SWAP THEN DROP ;

            LINKTO(MSTAR,0,3,'X',"AM")
MAX:        JMP     ENTER
            .WORD   TWODUP,LESSTHAN,zbranch,_maxDONE,SWAP
_maxDONE:   .WORD   DROP,EXIT


; ----------------------------------------------------------------------
; MIN [CORE] 6.1.1880 ( n1 n2 -- n3 )
;
; n3 is the lesser of n1 and n2.
;
; ---
; : MIN ( n1 n2 -- n3 )   2DUP > IF SWAP THEN DROP ;

            LINKTO(MAX,0,3,'N',"IM")
MIN:        JMP     ENTER
            .WORD   TWODUP,GREATERTHAN,zbranch,_minDONE,SWAP
_minDONE:   .WORD   DROP,EXIT


; ----------------------------------------------------------------------
; MOD [CORE] 6.1.1890 ( n1 n2 -- n3 )
;
; Divide n1 by n2, giving the single-cell remainder n3.  An ambiguous
; condition exists if n2 is zero.  If n1 and n2 differ in sign, the
; implementation-defined result returned will be the same as that returned
; by either the phrase >R S>D R> FM/MOD DROP or the phrase
; >R S>D R> SM/REM DROP.
;
; ---
; : MOD ( n1 n2 -- n3)   /MOD DROP ;

            LINKTO(MIN,0,3,'D',"OM")
MOD:        JMP     ENTER
            .WORD   SLASHMOD,DROP,EXIT


; ----------------------------------------------------------------------
; MOVE [CORE] 6.1.1900 ( addr1 addr2 u -- )
;
; If u is greater than zero, copy the contents of u consecutive address
; units at addr1 to the u consecutive address units at addr2.  After MOVE
; completes, the u consecutive address units at addr2 contain exactly what
; the u consecutive address units at addr1 contained before the move.
;
; ---
; : MOVE ( addr1 addr2 u --)
;   >R 2DUP SWAP DUP R@ + WITHIN R> SWAP IF CMOVE> ELSE CMOVE THEN ;

            LINKTO(MOD,0,4,'E',"VOM")
MOVE:       JMP     ENTER
            .WORD   TOR,TWODUP,SWAP,DUP,RFETCH,PLUS,WITHIN
            .WORD   RFROM,SWAP,zbranch,_move1
            .WORD   CMOVEUP,EXIT
_move1:     .WORD   CMOVE,EXIT


; ----------------------------------------------------------------------
; NEGATE [CORE] 6.1.1910 ( n1 -- n2 )
;
; Negate n1, giving its arithmetic inverse n2.

            LINKTO(MOVE,0,6,'E',"TAGEN")
NEGATE:     POP     H
            MOV     A,L
            CMA
            MOV     L,A
            MOV     A,H
            CMA
            MOV     H,A
            INX     H
            PUSH    H
            NEXT


; ----------------------------------------------------------------------
; OR [CORE] 6.1.1980 ( x1 x2 -- x3 )
;
; x3 is the bit-by-bit inclusive-or of x1 with x2.

            LINKTO(NEGATE,0,2,'R',"O")
OR:         SAVEDE
            POP     H           ; Pop x2.
            POP     D           ; Pop x1.
            MOV     A,H         ; Put x2's high byte into A,
            ORA     D           ; ..then OR x1's high byte with A,
            MOV     H,A         ; ..and put the result into H.
            MOV     A,L         ; Put x2's low byte into A,
            ORA     E           ; ..then OR x1's low byte with A,
            MOV     L,A         ; ..and put the result into L.
            PUSH    H           ; Push the result (HL).
            RESTOREDE
            NEXT


; ----------------------------------------------------------------------
; OVER [CORE] 6.1.1990 ( x1 x2 -- x1 x2 x1 )
;
; Place a copy of x1 on top of the stack.

            LINKTO(OR,0,4,'R',"EVO")
OVER:       PUSH    D           ; Save DE on the stack.
            LDES    4           ; Get the address of the third stack item.
            LHLX                ; Load the third stack item into HL.
            POP     D           ; Restore DE.
            PUSH    H           ; Push the third stack item onto the stack.
            NEXT


; ----------------------------------------------------------------------
; POSTPONE [CORE] 6.1.2033
;
; Interpretation:
;   Interpretation semantics for this word are undefined.
;
; Compilation: ( "<spaces>name" -- )
;   Skip leading space delimiters.  Parse name delimited by a space.  Find
;   name.  Append the compilation semantics of name to the current
;   definition.  An ambiguous condition exists if name is not found.
;
; ---
; Postponing a non-immediate word requires the compiler to add code to the
; current definition that compiles the postponed word into the then-current
; definition when the current definition is executed.  Postponing an
; immediate word requires the word to be compiled directly into the current
; definition.
;
; : POSTPONE ( "<spaces>name" --)
;   PARSE-WORD (FIND)  DUP 0= IF DROP TYPE SPACE [CHAR] ? EMIT CR ABORT THEN
;   0< IF  ['] LIT COMPILE,  ,  ['] COMPILE, COMPILE, ELSE COMPILE, THEN
; ; IMMEDIATE

            LINKTO(OVER,1,8,'E',"NOPTSOP")
POSTPONE:   JMP     ENTER
            .WORD   PARSEWORD,PFIND,DUP,ZEROEQUALS,zbranch,_postpone1
            .WORD   DROP,TYPE,SPACE,LIT,'?',EMIT,CR,ABORT
_postpone1: .WORD   ZEROLESS,zbranch,_postpone2
            .WORD   LIT,LIT,COMPILECOMMA,COMMA,LIT,COMPILECOMMA,COMPILECOMMA
            .WORD       branch,_postpone3
_postpone2: .WORD   COMPILECOMMA
_postpone3: .WORD   EXIT


; ----------------------------------------------------------------------
; QUIT [CORE] 6.1.2050 ( -- ) ( R:  i*x -- )
;
; Empty the return stack, store zero in SOURCE-ID if it is present, make
; the user input device the input source, and enter interpretation state.
; Do not display a message.  Repeat the following:
;   - Accept a line from the input source into the input buffer, set >IN
;     to zero, and interpret.
;   - Display the implementation-defined system prompt if in interpretation
;     state, all processing has been completed, and no ambiguous condition
;     exists.
;
; ---
; : QUIT  ( --; R: i*x --)
;   INITRP  0 STATE !  INIT-ICBS  TIB  ICB ICBLINESTART +  !
;   BEGIN
;       TIB TIBSIZE  ACCEPT  TIB +  ICB ICBLINEEND + !
;       SPACE INTERPRET
;       CR  STATE @ 0= IF ." ok " THEN
;   AGAIN ;

            LINKTO(POSTPONE,0,4,'T',"IUQ")
QUIT:       JMP     ENTER
            .WORD   INITRP
            .WORD   ZERO,STATE,STORE
            .WORD   INITICBS,TIB,ICB,LIT,ICBLINESTART,PLUS,STORE
_quit1:     .WORD   TIB,LIT,TIBSIZE,ACCEPT
            .WORD   TIB,PLUS,ICB,LIT,ICBLINEEND,PLUS,STORE
            .WORD   SPACE,INTERPRET
            .WORD   CR,STATE,FETCH,ZEROEQUALS,zbranch,_quit2
            .WORD   PSQUOTE,3
            .BYTE   "ok "
            .WORD   TYPE
_quit2:     .WORD   branch,_quit1


; ----------------------------------------------------------------------
; R> [CORE] 6.1.2060 "r-from"
;
; Interpretation:
;   Interpretation semantics for this word are undefined.
;
; Execution: ( -- x ) ( R: x -- )
;   Move x from the return stack to the data stack.

            LINKTO(QUIT,0,2,'>',"R")
RFROM:      RSPOP(H,L)
            PUSH    H
            NEXT


; ----------------------------------------------------------------------
; R@ [CORE] 6.1.2070 "r-fetch"
;
; Interpretation:
;   Interpretation semantics for this word are undefined.
;
; Execution: ( -- x ) ( R: x -- x )
;   Copy x from the return stack to the data stack.

            LINKTO(RFROM,0,2,'@',"R")
RFETCH:     RSFETCH(H,L)
            PUSH    H
            NEXT


; ----------------------------------------------------------------------
; RECURSE [CORE] 6.1.2120
;
; Interpretation:
;   Interpretation semantics for this word are undefined.
;
; Compilation: ( -- )
;   Append the execution semantics of the current definition to the current
;   definition.  An ambiguous condition exists if RECURSE appears in a
;   definition after DOES>.
;
; ---
; RECURSE   LATEST @ NFA>CFA , ; IMMEDIATE

            LINKTO(RFETCH,1,7,'E',"SRUCER")
RECURSE:    JMP     ENTER
            .WORD   LATEST,FETCH,NFATOCFA,COMMA,EXIT


; ----------------------------------------------------------------------
; REPEAT [CORE] 6.1.2140
;
; Interpretation:
;   Interpretation semantics for this word are undefined.
;
; Compilation: ( C: orig dest -- )
;   Append the run-time semantics given below to the current definition,
;   resolving the backward reference dest.  Resolve the forward reference
;   orig using the location following the appended run-time semantics.
;
; Run-time: ( -- )
;   Continue execution at the location given by dest.
;
; ---
; REPEAT   POSTPONE AGAIN  POSTPONE THEN ; IMMEDIATE

            LINKTO(RECURSE,1,6,'T',"AEPER")
REPEAT:     JMP     ENTER
            .WORD   AGAIN,THEN,EXIT


; ----------------------------------------------------------------------
; ROT [CORE] 6.1.2160 "rote" ( x1 x2 x3 -- x2 x3 x1 )
;
; Rotate the top three stack entries.

            LINKTO(REPEAT,0,3,'T',"OR")
ROT:        SAVEDE
            POP     D           ; Pop x3 into DE.
            POP     H           ; Pop x2 into HL.
            XTHL                ; Swap TOS (x1) with HL (x2).
            PUSH    D           ; Push x3 back onto the stack.
            PUSH    H           ; Push x1 back onto the stack.
            RESTOREDE
            NEXT


; ----------------------------------------------------------------------
; RSHIFT [CORE] 6.1.1805 "l-shift" ( x1 u -- x2 )
;
; Perform a logical left shift of u bit-places on x1, giving x2.  Put
; zeroes into the least significant bits vacated by the shift.  An
; ambiguous condition exists if u is greater than or equal to the number
; of bits in a cell.

            LINKTO(ROT,0,6,'T',"FIHSR")
RSHIFT:     SAVEDE
            POP     D           ; Pop u into DE, although we only care about E.
            POP     H           ; Pop x1 into HL.
            INR     E           ; Increment E so that the loop can pre-test.
_rshift1:   DCR     E           ; Decrement E and see if the count is zero;
            JZ      _rshiftDONE ; ..we're done if so.
            ANA     A           ; Clear carry.
            MOV     A,H         ; Move the high byte into A,
            RAR                 ; ..rotate right with carry,
            MOV     H,A         ; ..then put the high byte back into H.
            MOV     A,L         ; Move the low byte into A,
            RAR                 ; ..rotate right with carry,
            MOV     L,A         ; ..then put the low byte back into L.
            JMP     _rshift1    ; Continue looping.
_rshiftDONE:PUSH    H           ; Push the result (HL).
            RESTOREDE
            NEXT


; ----------------------------------------------------------------------
; S" [CORE] 6.1.2165 "s-quote"
;
; Interpretation:
;   Interpretation semantics for this word are undefined.
;
;   Extended by FILE: ( "ccc<quote>" -- c-addr u )
;       Parse ccc delimited by " (double quote).  Store the resulting
;       string c-addr u at a temporary location.  The maximum length of
;       the temporary buffer is implementation-dependent but shall be no
;       less than 80 characters.  Subsequent uses of S" may overwrite the
;       temporary buffer.  At least one such buffer shall be provided.
;
; Compilation: ( "ccc<quote>" -- )
;   Parse ccc delimited by " (double-quote).  Append the run-time
;   semantics given below to the current definition.
;
; Run-time: ( -- c-addr u )
;   Return c-addr and u describing a string consisting of the characters
;   ccc.  A program shall not alter the returned string.
;
; ---
; : S" ( "ccc<quote>" --)
;   [CHAR] " PARSE ( caS uS)
;   STATE @ 0= IF  DUP 'S"SIZE > ABORT" String too long"
;       'S" OVER 2SWAP ( caD uS caS uS)  'S"
;   ELSE ['] (S") COMPILE,  DUP ,  HERE OVER ALLOT THEN
;   ( caS uS caD) SWAP CMOVE ;

            LINKTO(RSHIFT,1,2,022h,"S")
SQUOTE:     JMP     ENTER
            .WORD   LIT,022h,PARSE,STATE,FETCH,ZEROEQUALS,zbranch,_squote2
            .WORD   DUP,LIT,SQSIZE,GREATERTHAN,zbranch,_squote1
            .WORD   PSQUOTE,12
            .BYTE   "String too long"
            .WORD   TYPE,ABORT
_squote1:   .WORD   TICKSQUOTE,OVER,TWOSWAP,TICKSQUOTE,branch,_squote3
_squote2:   .WORD   LIT,PSQUOTE,COMPILECOMMA,DUP,COMMA,HERE,OVER,ALLOT
_squote3:   .WORD   SWAP,CMOVE,EXIT


; ----------------------------------------------------------------------
; S>D [CORE] 6.1.2170 "s-to-d" ( n -- d )
;
; Convert the number n to the double-cell number d with the same numerical value.
;
; ---
; : S>D ( n -- d)   DUP 0< ;

            LINKTO(SQUOTE,0,3,'D',">S")
STOD:       JMP     ENTER
            .WORD   DUP,ZEROLESS,EXIT


; ----------------------------------------------------------------------
; SIGN [CORE] 6.1.2210 ( n -- )
;
; If n is negative, add a minus sign to the beginning of the pictured
; numeric output string.  An ambiguous condition exists if SIGN executes
; outside of a <# #> delimited number conversion.
;
; ---
; : SIGN ( n -- )   0< IF 45 HOLD THEN ;

            LINKTO(STOD,0,4,'N',"GIS")
SIGN:       JMP     ENTER
            .WORD   ZEROLESS,zbranch,_signDONE,LIT,45,HOLD
_signDONE:  .WORD   EXIT


; ----------------------------------------------------------------------
; SM/REM [CORE] 6.1.2214 "s-m-slash-rem" ( d1 n1 -- n2 n3 )
;
; Divide d1 by n1, giving the symmetric quotient n3 and the remainder n2.
; Input and output stack arguments are signed.  An ambiguous condition
; exists if n1 is zero or if the quotient lies outside the range of a
; single-cell signed integer.
;
; ---
; : SM/REM ( d1 n1 -- n2 n3)
;   OVER >R  2DUP XOR >R  ( R:remsign quosign)
;   ABS >R DABS R>
;   UM/MOD ( +rem +quo)
;   R> ?NEGATE ( +rem +-quo)  SWAP R> ?NEGATE SWAP ( +-rem +-quo) ;

            LINKTO(SIGN,0,6,'M',"ER/MS")
SMSLASHREM: JMP     ENTER
            .WORD   OVER,TOR,TWODUP,XOR,TOR,ABS,TOR,DABS,RFROM,UMSLASHMOD
            .WORD   RFROM,QNEGATE,SWAP,RFROM,QNEGATE,SWAP,EXIT


; ----------------------------------------------------------------------
; SOURCE [CORE] 6.1.2216 ( -- c-addr u )
;
; c-addr is the address of, and u is the number of characters in, the
; input buffer.
;
; ---
; : SOURCE ( -- c-addr u)   ICB 2@ OVER - ;

            LINKTO(SMSLASHREM,0,6,'E',"CRUOS")
SOURCE:     JMP     ENTER
            .WORD   ICB,TWOFETCH,OVER,MINUS,EXIT


; ----------------------------------------------------------------------
; SPACE [CORE] 6.1.2220 ( -- )
;
; Display one space.

            LINKTO(SOURCE,0,5,'E',"CAPS")
SPACE:      MVI     A,020h      ; Put the space character in A.
            CALL    STDCALL     ; Call the
            .WORD   04B44h      ; .."character output" routine.
            NEXT


; ----------------------------------------------------------------------
; SPACES [CORE] 6.1.2230 ( n -- )
;
; If n is greater than zero, display n spaces.
;
; ---
; : SPACES ( n -- )   DUP IF SPACE 1- THEN DROP ;

            LINKTO(SPACE,0,6,'S',"ECAPS")
SPACES:     JMP     ENTER
_spaces1:   .WORD   DUP,zbranch,_spacesDONE,SPACE,ONEMINUS,branch,_spaces1
_spacesDONE:.WORD   DROP
            .WORD   EXIT


; ----------------------------------------------------------------------
; STATE [CORE] 6.1.2250 ( -- a-addr )
;
; a-addr is the address of a cell containing the compilation-state flag.
; STATE is true when in compilation state, false otherwise.  The true
; value in STATE is non-zero, but is otherwise implementation-defined.
; Only the following standard words alter the value in STATE:  : (colon),
; ; (semicolon), ABORT, QUIT, :NONAME, [ (left-bracket), and ] (right-bracket).
;
; Note: A program shall not directly alter the contents of STATE.

            LINKTO(SPACES,0,5,'E',"TATS")
STATE:      LXI     H,TICKSTATE
            PUSH    H
            NEXT


; ----------------------------------------------------------------------
; SWAP [CORE] 6.1.2260 "two-dupe" ( x1 x2 -- x2 x1 )
;
; Exchange the top two stack items.

            LINKTO(STATE,0,4,'P',"AWS")
SWAP:       POP     H           ; Pop x2 into HL.
            XTHL                ; Swap TOS (x1) with HL (x2).
            PUSH    H           ; Push x1 back onto the stack.
            NEXT


; ----------------------------------------------------------------------
; THEN [CORE] 6.1.2270
;
; Interpretation:
;   Interpretation semantics for this word are undefined.
;
; Compilation: ( C: orig -- )
;   Append the run-time semantics given below to the current definition.
;   Resolve the forward reference orig using the location of the appended
;   run-time semantics.
;
; Run-time: ( -- )
;   Continue execution.
;
; ---
; : THEN   HERE SWAP ! ; IMMEDIATE

            LINKTO(SWAP,1,4,'N',"EHT")
THEN:       JMP     ENTER
            .WORD   HERE,SWAP,STORE,EXIT


; ----------------------------------------------------------------------
; TYPE [CORE] 6.1.2310 ( c-addr u -- )
;
; If u is greater than zero, display the character string specified by
; c-addr and u.
;
; When passed a character in a character string whose character-defining
; bits have a value between hex 20 and 7E inclusive, the corresponding
; standard character, specified by 3.1.2.1 graphic characters, is displayed.
; Because different output devices can respond differently to control
; characters, programs that use control characters to perform specific
; functions have an environmental dependency.

            LINKTO(THEN,0,4,'E',"PYT")
TYPE:       SAVEDE
            POP     D           ; Pop the count into DE.
            POP     H           ; Pop the address into HL.
_type1:     MOV     A,D         ; See if the count is zero by moving D to A
            ORA     E           ; ..and then ORing A with E.
            JZ      _typeDONE   ; We're done if the count is zero.
            MOV     A,M         ; Get the current character.
            CALL    STDCALL     ; Call the
            .WORD   04B44h      ; .."character output" routine.
            INX     H           ; Move to the next character.
            DCX     D           ; Decrement the remaining count.
            JMP     _type1      ; Keep going.
_typeDONE:  RESTOREDE
            NEXT


; ----------------------------------------------------------------------
; U. [CORE] 6.1.2320 "u-dot" ( u -- )
;
; Display u in free field format.
;
; ---
; : U. ( u -- )   0 UD.

            LINKTO(TYPE,0,2,'.',"U")
UDOT:       JMP     ENTER
            .WORD   ZERO,UDDOT,EXIT


; ----------------------------------------------------------------------
; U< [CORE] 6.1.2340 "u-less-than" ( u1 u2 -- flag )
;
; flag is true if and only if u1 is less than u2.

            LINKTO(UDOT,0,2,'<',"U")
ULESSTHAN:  SAVEDE
            POP     D           ; Pop u2.
            POP     H           ; Pop u1.
            PUSH    B           ; Save BC.
            MOV     B,D         ; Move u2
            MOV     C,E         ; ..to BC.
            DSUB                ; HL=u1-u2
            POP     B           ; Restore BC.
            SBB     A           ; Propagate carry throughout A
            MOV     H,A         ; ..and fill HL
            MOV     L,A         ; ..with the contents of A (0000 or FFFF).
            PUSH    H           ; Push the flag to the stack.
            RESTOREDE
            NEXT


; ----------------------------------------------------------------------
; UM* [CORE] 6.1.2360 "u-m-star" ( u1 u2 -- ud )
;
; Multiply u1 by u2, giving the unsigned double-cell product ud.  All
; values and arithmetic are unsigned
;
; ---
; This is U* copied verbatim from fig-FORTH 8080 v1.3.
; The only changes were to save and restore DE in HOLDD.  BC was already
; getting saved since that is the fig-FORTH Instruction Pointer.  The
; fig-FORTH comments are unchanged, so replace "IP" with "RSP".

            LINKTO(ULESSTHAN,0,3,'*',"MU")
UMSTAR:     SAVEDE

            ; fig-FORTH code:
            POP     D           ; (DE) <- MPLIER
            POP     H           ; (HL) <- MPCAND
            PUSH    B           ; SAVE IP
            MOV     B,H
            MOV     A,L         ; (BA) <- MPCAND
            CALL    MPYX        ; (AHL)1 <- MPCAND.LB * MPLIER
            ; 1ST PARTIAL PRODUCT
            PUSH    H           ; SAVE (HL)1
            MOV     H,A
            MOV     A,B
            MOV     B,H         ; SAVE (A)1
            CALL    MPYX        ; (AHL)2 <- MPCAND.HB * MPLIER
            ; 2ND PARTIAL PRODUCT
            POP     D           ; (DE) <- (HL)1
            MOV     C,D         ; (BC) <- (AH)1
            ; FORM SUM OF PARTIALS:
            ;      (AHL) 1
            ;    + (AHL) 2
            ;   --------
            ;     (AHLE)
            DAD     B           ; (HL) <- (HL)2 + (AH)1
            ACI     0           ; (AHLE) <- (BA) * (DE)
            MOV     D,L
            MOV     L,H
            MOV     H,A         ; (HLDE) <- MPLIER * MPCAND
            POP     B           ; RESTORE IP
            PUSH    D           ; (S2) <- PRODUCT.LW

            ; MFORTH code:
            PUSH    H           ; (S1) <- PRODUCT.HW
            RESTOREDE
            NEXT
            ;
            ;   MULTIPLY PRIMITIVE
            ;           (AHL) <- (A) * (DE)
            ;   #BITS =   24      8     16
MPYX:       LXI     H,0         ; (HL) <- 0 = PARTIAL PRODUCT.LW
            MVI     C,4         ; LOOP COUNTER
MPYX1:      DAD     H           ; LEFT SHIFT (AHL) 24 BITS
            RAL
            JNC     MPYX2       ; IF NEXT MPLIER BIT = 1
            DAD     D           ; THEN ADD MPCAND
            ACI     0
MPYX2:      DAD     H
            RAL
            JNC     MPYX3
            DAD     D
            ACI     0
MPYX3:      DCR     C           ; IF NOT LAST MPLIER BIT
            JNZ     MPYX1       ; THEN LOOP AGAIN
            RET                 ; ELSE DONE


; ----------------------------------------------------------------------
; UM/MOD [CORE] 6.1.2370 "u-m-slash-mod" ( ud u1 -- u2 u3 )
;
; Divide ud by u1, giving the quotient u3 and the remainder u2.  All values
; and arithmetic are unsigned.  An ambiguous condition exists if u1 is zero
; or if the quotient lies outside the range of a single-cell unsigned integer.
;
; ---
; This is U/ copied verbatim from fig-FORTH 8080 v1.3.
; The only changes were to save and restore DE in HOLDD.  BC was already
; getting saved since that is the fig-FORTH Instruction Pointer.  The
; fig-FORTH comments are unchanged, so replace "IP" with "RSP".

            LINKTO(UMSTAR,0,6,'D',"OM/MU")
UMSLASHMOD: SAVEDE

            ; fig-FORTH code:
            MOV     H,B
            MOV     L,C         ; (HL) <- (IP)
            POP     B           ; (BC) <- (S1) = DENOMINATOR
            POP     D           ; (DE) <- (S2) = NUMERATOR.HIGH
            XTHL                ; (S1) <- (IP)
            XCHG                ; (HLDE) = NUMERATOR, 32 BITS
            MOV     A,L
            SUB     C
            MOV     A,H         ; IF OVERFLOW
            SBB     B
            JNC     USBAD       ; THEN RETURN BAD VALUE
            MOV     A,H
            MOV     H,L
            MOV     L,D         ; (AHL) <- 24 BITS OF NUMERATOR
            MVI     D,8         ; (D) <- INIT COUNTER
            PUSH    D           ; SAVE D & E
            CALL    USLA        ; PARTIAL DIVISION
            POP     D           ; RESTORE COUNTER & NUM.MSBYTE
            PUSH    H           ; (S1) <- (L) = BYTE OF QUOTIENT
            MOV     L,E
            CALL    USLA
            MOV     D,A
            MOV     E,H         ; (DE) <- REMAINDER
            POP     B           ; RESTORE QUOTIENT.HIGH
            MOV     H,C         ; (HL) <- QUOTIENT
            POP     B           ; RESTORE (IP)

            ; MFORTH code:
            PUSH    D
            PUSH    H
            RESTOREDE
            NEXT

USL0:       MOV     E,A
            MOV     A,H
            SUB     C
            MOV     H,A
            MOV     A,E
            SBB     B
            JNC     USL1        ; IF CARRY
            MOV     A,H         ; THEN ADD (BC) INTO (AH)
            ADD     C
            MOV     H,A
            MOV     A,E
            DCR     D
            RZ                  ; RETURN FROM USLA

USLA:       DAD     H           ; 24BIT LEFT-SHIFT ( *2 )
            RAL
            JNC     USL0        ; SUBTRACT & TEST
            MOV     E,A
            MOV     A,H
            SUB     C           ; (AH) <- (AH) - (BC)
            MOV     H,A
            MOV     A,E
            SBB     B
USL1:       INR     L           ; 1 BIT OF QUOT INTO RIGHT SIDE
            DCR     D           ;   OF (AHL)
            JNZ     USLA        ; CONTINUE DIVISION
            RET                 ; ALL 8 TRIAL COMPLETE

USBAD:      LXI     H,0FFFFh    ; OVERFLOW, RETURN 32BIT -1
            POP     B           ; RESTORE (IP)

            ; MFORTH code:
            PUSH    H
            RESTOREDE
            NEXT


; ----------------------------------------------------------------------
; UNLOOP [CORE] 6.1.2380
;
; Interpretation:
;   Interpretation semantics for this word are undefined.
;
; Execution: ( -- ) ( R: loop-sys -- )
;   Discard the loop-control parameters for the current nesting level.
;   An UNLOOP is required for each nesting level before the definition may
;   be EXITed.  An ambiguous condition exists if the loop-control parameters
;   are unavailable.
;
; ---
; UNLOOP  R> DROP R> DROP ;

            LINKTO(UMSLASHMOD,0,6,'P',"OOLNU")
UNLOOP:     RSPOP(H,L)
            RSPOP(H,L)
            NEXT


; ----------------------------------------------------------------------
; UNTIL [CORE] 6.1.2390
;
; Compilation: ( C: dest -- )
;   Append the run-time semantics given below to the current definition,
;   resolving the backward reference dest.
;
; Run-time: ( x -- )
;   If all bits of x are zero, continue execution at the location specified
;   by dest.
;
; ---
; : UNTIL   ['] 0branch COMPILE,  , ; IMMEDIATE

            LINKTO(UNLOOP,1,5,'L',"ITNU")
UNTIL:      JMP     ENTER
            .WORD   LIT,zbranch,COMPILECOMMA,COMMA,EXIT


; ----------------------------------------------------------------------
; VARIABLE [CORE] 6.1.2410 ( "<spaces>name" -- )
;
; Skip leading space delimiters.  Parse name delimited by a space.  Create
; a definition for name with the execution semantics defined below.  Reserve
; one cell of data space at an aligned address.
;
; name is referred to as a "variable".
;
; name Execution: ( -- a-addr )
;   a-addr is the address of the reserved cell.  A program is responsible
;   for initializing the contents of the reserved cell.
;
; ---
; : VARIABLE ( "<spaces>name" -- )
;   CREATE  CFASZ NEGATE ALLOT  195 C, DOVARIABLE ,  0 , ; -- JMP DOVARIABLE

            LINKTO(UNTIL,0,8,'E',"LBAIRAV")
VARIABLE:   JMP     ENTER
            .WORD   CREATE,LIT,-CFASZ,ALLOT,LIT,195,CCOMMA,LIT,DOVARIABLE,COMMA
            .WORD   ZERO,COMMA,EXIT


; ----------------------------------------------------------------------
; WHILE [CORE] 6.1.2430
;
; Compilation: ( C: dest -- orig dest )
;   Put the location of a new unresolved forward reference orig onto the
;   control flow stack, under the existing dest.  Append the run-time
;   semantics given below to the current definition.  The semantics are
;   incomplete until orig and dest are resolved (e.g., by REPEAT).
;
; Run-time: ( x -- )
;   If all bits of x are zero, continue execution at the location specified
;   by the resolution of orig.
;
; ---
; : WHILE   POSTPONE IF  SWAP ; IMMEDIATE

            LINKTO(VARIABLE,1,5,'E',"LIHW")
WHILE:      JMP     ENTER
            .WORD   IF,SWAP,EXIT


; ----------------------------------------------------------------------
; WORD [CORE] 6.1.2450 ( char "<chars>ccc<char>" -- c-addr )
;
; Skip leading delimiters.  Parse characters ccc delimited by char.  An
; ambiguous condition exists if the length of the parsed string is greater
; than the implementation-defined length of a counted string.
;
; c-addr is the address of a transient region containing the parsed word as
; a counted string.  If the parse area was empty or contained no characters
; other than the delimiter, the resulting string has a zero length.  A space,
; not included in the length, follows the string.  A program may replace
; characters within the string.
;
; Note: The requirement to follow the string with a space is obsolescent and
; is included as a concession to existing programs that use CONVERT.  A
; program shall not depend on the existence of the space.
;
; ---
; : WORD ( char "<chars>ccc<char>" -- c-addr)
;   TRUE SWAP (parse) >R 'WORD 1+ R@ CMOVE
;   R@ 'WORD C!  BL 'WORD 1+ R> + C!
;   'WORD ;

            LINKTO(WHILE,0,4,'D',"ROW")
WORD:       JMP     ENTER
            .WORD   TRUE,SWAP,PPARSE,TOR,TICKWORD,ONEPLUS,RFETCH,CMOVE
            .WORD   RFETCH,TICKWORD,CSTORE,BL,TICKWORD,ONEPLUS,RFROM,PLUS,CSTORE
            .WORD   TICKWORD,EXIT


; ----------------------------------------------------------------------
; XOR [CORE] 6.1.2490 ( x1 x2 -- x3 )
;
; x3 is the bit-by-bit exclusive-or of x1 with x2.

            LINKTO(WORD,0,3,'R',"OX")
XOR:        SAVEDE
            POP     H           ; Pop x2.
            POP     D           ; Pop x1.
            MOV     A,H         ; Put x2's high byte into A,
            XRA     D           ; ..then XOR x1's high byte with A,
            MOV     H,A         ; ..and put the result into H.
            MOV     A,L         ; Put x2's low byte into A,
            XRA     E           ; ..then XOR x1's low byte with A,
            MOV     L,A         ; ..and put the result into L.
            PUSH    H           ; Push the result (HL).
            RESTOREDE
            NEXT


; ----------------------------------------------------------------------
; [ [CORE] 6.1.2500 "left-bracket" ( -- )
;
; Interpretation:
;   Interpretation semantics for this word are undefined.
;
; Compilation:
;   Perform the execution semantics given below.
;
; Execution: ( -- )
;   Enter interpretation state.  [ is an immediate word.

            LINKTO(XOR,1,1,'[',"")
LTBRACKET:  LXI     H,0
            SHLD    TICKSTATE
            NEXT


; ----------------------------------------------------------------------
; ['] [CORE] 6.1.2510 "bracket-tick"
;
; Interpretation:
;   Interpretation semantics for this word are undefined.
;
; Compilation: ( "<spaces>name" -- )
;   Skip leading space delimiters.  Parse name delimited by a space.
;   Find name.  Append the run-time semantics given below to the current
;   definition.
;
;   An ambiguous condition exists if name is not found.
;
; Run-time: ( -- xt )
;   Place name's execution token xt on the stack.  The execution token
;   returned by the compiled phrase "['] X " is the same value returned by
;   "' X " outside of compilation state.
;
; ---
; : ['] ( "<spaces>name" -- )   '  ['] LIT COMPILE,  , ; IMMEDIATE

            LINKTO(LTBRACKET,1,3,']',"\'[")
BRACKETTICK:JMP     ENTER
            .WORD   TICK,LIT,LIT,COMPILECOMMA,COMMA,EXIT


; ----------------------------------------------------------------------
; [CHAR] [CORE] 6.1.2520 "bracket-char"
;
; Interpretation:
;   Interpretation semantics for this word are undefined.
;
; Compilation: ( "<spaces>name" -- )
;   Skip leading space delimiters.  Parse name delimited by a space.
;   Append the run-time semantics given below to the current definition.
;
; Run-time: ( -- char )
;   Place char, the value of the first character of name, on the stack.
;
; ---
; : [CHAR] ( "<spaces>name" -- char)   CHAR  ['] LIT COMPILE,  , ; IMMEDIATE

            LINKTO(BRACKETTICK,1,6,']',"RAHC[")
BRACKETCHAR:JMP     ENTER
            .WORD   CHAR,LIT,LIT,COMPILECOMMA,COMMA,EXIT


; ----------------------------------------------------------------------
; ] [CORE] 6.1.2540 "right-bracket" ( -- )
;
; Enter compilation state.

            LINKTO(BRACKETCHAR,0,1,']',"")
RTBRACKET:  LXI     H,0FFFFh
            SHLD    TICKSTATE
            NEXT



; ======================================================================
; CORE Constants (implementation details)
; ======================================================================

; ----------------------------------------------------------------------
; Input Control Block
;
; Stores information about an input source.

ICBLINEEND: .EQU    0           ; Offset to end of line.
ICBLINESTART:.EQU   2           ; Offset from ICB to start of line cell.
ICBSOURCEID:.EQU    4           ; Offset to SOURCE-ID for this source.
ICBTOIN:    .EQU    6           ; Offset to >IN value.


; ======================================================================
; CORE Words (implementation details)
; ======================================================================

; ----------------------------------------------------------------------
; 'S" [MFORTH] "tick-s-quote" ( -- addr )
;
; addr is the address of the start of the S" buffer.

            LINKTO(RTBRACKET,0,3,022h,"S\'")
TICKSQUOTE: LHLD    DP
            PUSH    D
            LXI     D,SQOFFSET
            DAD     D
            XTHL
            XCHG
            NEXT


; ----------------------------------------------------------------------
; 'WORD [MFORTH] "tick-word" ( -- addr )
;
; addr is the address of the start of the WORD buffer.

            LINKTO(TICKSQUOTE,0,5,'D',"ROW\'")
TICKWORD:   LHLD    DP
            PUSH    D
            LXI     D,WORDOFFSET
            DAD     D
            XTHL
            XCHG
            NEXT


; ----------------------------------------------------------------------
; (?do) [MFORTH] "paren-question-do-paren" ( n1|u1 n2|u2 -- ) ( R: -- | loop-sys )
;
; If n1|u1 is equal to n2|u2, continue execution at the location given by
; the consumer of do-sys.  Otherwise set up loop control parameters with
; index n2|u2 and limit n1|u1 and continue executing immediately following
; ?DO.  Anything already on the return stack becomes unavailable until the
; loop control parameters are discarded.  An ambiguous condition exists if
; n1|u1 and n2|u2 are not both of the same type.

            LINKTO(TICKWORD,0,5,029h,"od?(")
pqdo:       SAVEDE
            POP     H           ; Pop index into HL.
            POP     D           ; Pop limit into DE.
            RSPUSH(D,E)         ; Push limit onto return stack.
            RSPUSH(H,L)         ; Push index onto return stack.
            PUSH    B           ; Save BC.
            MOV     B,D         ; Move the limit
            MOV     C,E         ; ..to BC.
            DSUB                ; HL=HL-BC
            POP     B           ; Restore BC.
            RESTOREDE
            JNZ     _pqdoBEGIN  ; Begin the loop if the values are not equal.
            RSPOP(H,L)          ; Remove the loop
            RSPOP(H,L)          ; ..items from the return stack.
            LHLX                ; Get the branch address into HL.
            XCHG                ; Swap the branch address into DE.
            JMP     _pqdoDONE   ; We're done.
_pqdoBEGIN: INX     D           ; Skip the
            INX     D           ; ..branch address.
_pqdoDONE:  NEXT


; ----------------------------------------------------------------------
; (do) [MFORTH] "paren-do-paren" ( n1|u1 n2|u2 -- ) ( R: -- loop-sys )
;
; Set up loop control parameters with index n2|u2 and limit n1|u1. An
; ambiguous condition exists if n1|u1 and n2|u2 are not both the same type.
; Anything already on the return stack becomes unavailable until the
; loop-control parameters are discarded.

            LINKTO(pqdo,0,4,029h,"od(")
pdo:        POP     H           ; Pop index into HL,
            XTHL                ; ..swap the index and the limit,
            RSPUSH(H,L)         ; ..and push the limit onto the return stack.
            POP     H           ; Pop index into HL
            RSPUSH(H,L)         ; ..and push the index onto the return stack.
            NEXT


; ----------------------------------------------------------------------
; (+loop) [MFORTH] "plus-loop" ( n -- ) ( R: loop-sys1 -- | loop-sys2 )
;
; An ambiguous condition exists if the loop control parameters are
; unavailable.  Add n to the loop index.  If the loop index did not cross
; the boundary between the loop limit minus one and the loop limit, continue
; execution at the beginning of the loop.  Otherwise, discard the current
; loop control parameters and continue execution immediately following the loop.

            LINKTO(pdo,0,7,029h,"pool+(")
pplusloop:  SAVEDE
            RSPOP(H,L)          ; Get the current loop index from the RS.
            POP     D           ; Get the increment from the stack.
            MOV     A,D         ; Move the high byte of the increment to A,
            ORA     A           ; ..see if the increment is positive or zero,
            PUSH    PSW         ; ..and then store the result on the stack.
            DAD     D           ; Increment the loop index.
            RSFETCH(D,E)        ; Get the loop limit from the RS
            RSPUSH(H,L)         ; ..and put the new loop index back onto the RS.
            POP     PSW         ; See if the increment is positive or zero
            JP      _pplPOSINCR ; ..and then calculate the flag appropriately.
_pplsNEGINCR:PUSH   B           ; Save BC.
            MOV     B,D         ; Move the loop limit
            MOV     C,E         ; ..into BC.
            DSUB                ; Subtract the limit from the index.
            POP     B           ; Restore BC.
            JP      _pplCONTINUE; Continue if index was >= limit,
            JMP     _pplUNLOOP  ; ..otherwise unloop.
_pplPOSINCR:PUSH    B           ; Save BC.
            MOV     B,D         ; Move the loop limit
            MOV     C,E         ; ..into BC.
            DSUB                ; Subtract the limit from the index.
            POP     B           ; Restore BC.
            JP      _pplUNLOOP  ; Unloop if index was >= limit.
_pplCONTINUE:RESTOREDE
            LHLX                ; Get the branch address into HL.
            XCHG                ; Swap the branch address into DE.
            JMP     _pplDONE    ; We're done.
_pplUNLOOP: RESTOREDE
            RSPOP(H,L)          ; Pop the loop index.
            RSPOP(H,L)          ; Pop the loop limit.
            INX     D           ; Skip the
            INX     D           ; ..branch address.
_pplDONE:   NEXT


; ----------------------------------------------------------------------
; (loop) [MFORTH] "paren-loop-paren" ( -- ) ( R: loop-sys1 -- | loop-sys2 )
;
; An ambiguous condition exists if the loop control parameters are
; unavailable.  Add one to the loop index.  If the loop index is then equal
; to the loop limit, discard the loop parameters and continue execution
; immediately following the loop.  Otherwise continue execution at the
; beginning of the loop.

            LINKTO(pplusloop,0,6,029h,"pool(")
ploop:      SAVEDE
            RSPOP(H,L)          ; Get the current loop index from the RS
            INX     H           ; ..and increment the loop index.
            RSFETCH(D,E)        ; Get the loop limit from the RS
            RSPUSH(H,L)         ; ..and put the new loop index back onto the RS.
            PUSH    B           ; Save BC.
            MOV     B,D         ; Move the loop limit
            MOV     C,E         ; ..into BC.
            DSUB                ; Subtract the limit from the index.
            POP     B           ; Restore BC.
            RESTOREDE
            JZ      _ploopUNLOOP; Loop is done if the values are equal (zero).
            LHLX                ; Get the branch address into HL.
            XCHG                ; Swap the branch address into DE.
            JMP     _ploopDONE  ; We're done.
_ploopUNLOOP:RSPOP(H,L)         ; Pop the loop index.
            RSPOP(H,L)          ; Pop the loop limit.
            INX     D           ; Skip the
            INX     D           ; ..branch address.
_ploopDONE: NEXT


; ----------------------------------------------------------------------
; (s") [MFORTH] "paren-s-quote-paren" ( -- c-addr u )
;
; Runtime behavior of S": return c-addr and u.

            LINKTO(ploop,0,4,029h,"\"s(")
PSQUOTE:    LHLX                ; Read string count from instruction stream.
            INX     D           ; Skip over count
            INX     D           ; ..in instruction stream.
            PUSH    D           ; Push string address onto the stack.
            PUSH    H           ; Push string count onto the stack.
            XCHG                ; IP to HL, count to DE.
            DAD     D           ; Add count to address to skip over string.
            XCHG                ; Put IP back in DE (pointing after string).
            NEXT


; ----------------------------------------------------------------------
; 0 [MFORTH] "zero" ( -- 0 )
;
; Push zero onto the stack.

            LINKTO(PSQUOTE,0,1,'0',"")
ZERO:       LXI     H,0
            PUSH    H
            NEXT


; ----------------------------------------------------------------------
; 0branch [MFORTH] "zero-branch" ( flag -- )
;
; If flag is false, then set the instruction pointer to the address that is
; in the next cell of the instruction stream, otherwise skip over the branch
; address and continue processing instructions.

            LINKTO(ZERO,0,7,'h',"cnarb0")
zbranch:    POP     H           ; Get the flag.
            MOV     A,H         ; See if the flag is zero by moving H to A
            ORA     L           ; ..and then ORing A with L.
            JNZ     _zbraTRUE   ; True?  Skip the branch.
            LHLX                ; Get the branch address into HL.
            XCHG                ; Swap the branch address into DE.
            JMP     _zbraDONE   ; We're done.
_zbraTRUE:  INX     D           ; Skip the
            INX     D           ; ..branch address.
_zbraDONE:  NEXT


; ----------------------------------------------------------------------
; 1 [MFORTH] "one" ( -- 1 )
;
; Push one onto the stack.

            LINKTO(zbranch,0,1,'1',"")
ONE:        LXI     H,1
            PUSH    H
            NEXT


; ----------------------------------------------------------------------
; >DIGIT [MFORTH] "to-digit" ( u -- char )
;
; char is the digit u converted to the values 0-9A-Z.
;
; ---
; >DIGIT ( u -- c ) DUP 9 > 7 AND + 48 + ;

            LINKTO(ONE,0,6,'T',"IGID>")
TODIGIT:    POP     H
            MOV     A,L
            CPI     00Ah
            JC       _todigit2  ; u is < 10, so just add 030h for 0-9.
            ADI     7           ; u is >= 10, add an extra 7 to get to A-Z.
_todigit2:  ADI     030h
            MOV     L,A
            PUSH    H
            NEXT


; ----------------------------------------------------------------------
; ?DNEGATE [MFORTH] ( d1 n -- d2 )
;
; Negate d1 if n is negative.
;
; ---
; : ?DNEGATE ( d1 n -- d2)   0< IF DNEGATE THEN ;

            LINKTO(TODIGIT,0,8,'E',"TAGEND?")
QDNEGATE:   JMP     ENTER
            .WORD   ZEROLESS,zbranch,_dnegate1,DNEGATE
_dnegate1:  .WORD   EXIT


; ----------------------------------------------------------------------
; ?NEGATE [MFORTH] ( n1 n2 -- n3 )
;
; Negate n1 if n2 is negative.
;
; ---
; : ?NEGATE ( n1 n2 -- n3)   0< IF NEGATE THEN ;

            LINKTO(QDNEGATE,0,7,'E',"TAGEN?")
QNEGATE:    JMP     ENTER
            .WORD   ZEROLESS,zbranch,_negate1,NEGATE
_negate1:   .WORD   EXIT


; ----------------------------------------------------------------------
; branch [MFORTH] ( -- )
;
; Set the instruction pointer to the address that is in the next cell of
; the instruction stream.

            LINKTO(QNEGATE,0,6,'h',"cnarb")
branch:     LHLX                ; Get the branch address into HL.
            XCHG                ; Swap the branch address into DE.
            NEXT


; ----------------------------------------------------------------------
; DIGIT? [MFORTH] "digit-question" ( char -- u -1 | 0 )
;
; Attempts to convert char to a numeric value using the current BASE.
; Pushes the numeric value and -1 to the stack if the value was converted,
; otherwise pushes 0 to the stack.

            LINKTO(branch,0,6,'?',"TIGID")
DIGITQ:     MOV     H,B         ; Get the contents
            MVI     L,USERBASE  ; ..of the BASE
            MOV     L,M         ; ..user variable in L.
            XTHL                ; Swap the character with the BASE,
            MOV     A,L         ; ..move the character into A,
            POP     H           ; ..and then get the BASE back into L.
            SUI     030h        ; Is char > "0"
            CPI     00Ah        ; ..and > "9"?
            JC      _digitq1    ; ..No: check the base and continue.
            SUI     7           ; Yes: subtract 7,
            CPI     00Ah        ; ..make sure that the char is > "9"
            JC      _digitqFLSE ; ..and fail if not (char between "9" and "A").
_digitq1:   CMP     L           ; Make sure that digit is less than BASE
            JNC     _digitqFLSE ; ..and fail if not.
            MOV     L,A         ; Move the digit to L,
            MVI     H,0         ; ..clear H,
            PUSH    H           ; ..and push the digit.
            LXI     H,0FFFFh    ; Put true in HL.
            JMP     _digitqDONE ; We're done.
_digitqFLSE:LXI     H,0         ; Put false in HL.
_digitqDONE:PUSH    H           ; Push the flag to the stack.
            NEXT


; ----------------------------------------------------------------------
; END-LOOP [MFORTH] ( do-orig pdo-xt -- )
;
; Completes the loop whose loop-sys parameters on the stack.  pdo-xt
; points to either (loop) or (+loop) and is compiled into the end of
; the loop.
;
; ---
; : END-LOOP ( do-orig pdo-xt)
;   COMPILE, ,  'PREVLEAVE @ HERE>CHAIN ; IMMEDIATE

ENDLOOP:    JMP     ENTER
            .WORD   COMPILECOMMA,COMMA
            .WORD   LIT,TICKPREVLEAVE,FETCH,HERETOCHAIN,EXIT


; ----------------------------------------------------------------------
; (FIND) [MFORTH] "paren-find-paren" ( c-addr u -- c-addr u 0 | xt 1 | xt -1 )
;
; Find the definition named in the string at c-addr with length u in the
; word list whose latest definition is pointed to by nfa.  If the
; definition is not found, return the string and zero.  If the
; definition is found, return its execution token xt.  If the definition
; is immediate, also return one (1), otherwise also return minus-one
; (-1).  For a given string, the values returned by FIND while compiling
; may differ from those returned while not compiling.
;
; ---
; : (FIND) ( c-addr u -- c-addr u 0 | xt 1 | xt -1 )
;   CONTEXT >R  BEGIN
;       2DUP R@ @ SEARCH-WORDLIST ( ca u 0 | ca u xt 1 | ca u xt -1)
;       ?DUP 0<> IF 2NIP R> DROP EXIT THEN ( ca u)
;       R> CELL+  DUP @ 0= IF DROP 0 EXIT THEN  >R
;   AGAIN ;

            LINKTO(DIGITQ,0,6,029h,"DNIF(")
PFIND:      JMP     ENTER
            .WORD   CONTEXT,TOR
_pfind1:    .WORD   TWODUP,RFETCH,FETCH,SEARCHWORDLIST,
            .WORD   QDUP,ZERONOTEQUALS,zbranch,_pfind2
            .WORD   TWONIP,RFROM,DROP,EXIT
_pfind2:    .WORD   RFROM,CELLPLUS,DUP,FETCH,ZEROEQUALS,zbranch,_pfind3
            .WORD   DROP,ZERO,EXIT
_pfind3:    .WORD   TOR,branch,_pfind1


; ----------------------------------------------------------------------
; (KEY) [MFORTH] "paren-key-paren" ( -- char )
;
; Receive one character char, a member of the implementation-defined
; character set.  Keyboard events that do not correspond to such characters
; are discarded until a valid character is received, and those events are
; subsequently unavailable.
;
; All standard characters can be received.  Characters received by KEY are
; not displayed.
;
; Any standard character returned by KEY has the numeric value specified in
; 3.1.2.1 Graphic characters.  Programs that require the ability to receive
; control characters have an environmental dependency.
;
; ---
; TODO: Apparently the Model 100 does magical, special things here and can
; convert function keys to text (maybe we can use this as a macro feature?),
; and sets Carry when the key is "special".  We probably want to avoid "special"
; keys and just accept non-special keys.  For now we just take the easy route.

            LINKTO(PFIND,0,5,029h,"YEK(")
PKEY:       CALL    STDCALL     ; Call the
            .WORD   012CBh      ; ..CHGET routine.
            MVI     H,0         ; Clear H,
            MOV     L,A         ; ..put the character in L,
            PUSH    H           ; ..and push the character onto the stack.
            NEXT


; ----------------------------------------------------------------------
; HERE>CHAIN [MFORTH] "here-to-chain" ( addr -- )
;
; Store HERE in the zero-terminated chain beginning at addr.  Each addr
; is expected to contain the addr of the previous element in the chain.
; The last element in the chain (which could be addr itself) should
; contain zero.
;
; ---
; HERE>CHAIN ( addr -- )
;   BEGIN ?DUP WHILE DUP @ HERE ( a a' h) ROT ! REPEAT ;

            LINKTO(PKEY,0,10,'N',"IAHC>EREH")
HERETOCHAIN:JMP     ENTER
_htc1:      .WORD   QDUP,zbranch,_htc2
            .WORD   DUP,FETCH,HERE,ROT,STORE,branch,_htc1
_htc2:      .WORD   EXIT


; ----------------------------------------------------------------------
; HIDDEN? [MFORTH] ( dict-addr -- flag )
;
; flag is true if and only if the given dictionary word is hidden.
;
; ---
; : HIDDEN ( dict-addr -- f )   C@ 64 AND 0<> ;

            LINKTO(HERETOCHAIN,0,7,'?',"NEDDIH")
HIDDENQ:    JMP     ENTER
            .WORD   CFETCH,LIT,64,AND,ZERONOTEQUALS,EXIT


; ----------------------------------------------------------------------
; HIDE [MFORTH] ( -- )
;
; Prevent the most recent definition from being found in the dictionary.
; ---
; : HIDE ( -- )   LATEST @  DUP C@ [HEX] 40 OR  SWAP C! ;

            LINKTO(HIDDENQ,0,4,'E',"DIH")
HIDE:       JMP     ENTER
            .WORD   LATEST,FETCH,DUP,CFETCH,LIT,040h,OR,SWAP,CSTORE,EXIT


; ----------------------------------------------------------------------
; HLD [MFORTH] "h-l-d" ( -- c-addr )
;
; c-addr is the address of the cell containing the current location in
; the Pictured Numeric Output hold buffer.

            LINKTO(HIDE,0,3,'D',"LH")
HLD:        LXI     H,TICKHLD
            PUSH    H
            NEXT


; ----------------------------------------------------------------------
; ICB [MFORTH] "i-c-b" ( -- c-addr )
;
; c-addr is the address of the current Input Control Block.

            LINKTO(HLD,0,3,'B',"CI")
ICB:        LHLD    TICKICB
            PUSH    H
            NEXT


; ----------------------------------------------------------------------
; INIT-ICBS [MFORTH] "init-icbs" ( -- )
;
; Initialize all of the Input Control Blocks.  The current Input Control
; Block should be configured immediately after executing this word.
;
; ---
; : INIT-ICBS ( -- )
;   ICBSTART [ MAXICBS 2* 2* 2* ] 0 FILL  ICBSTART TO ICB ;

            LINKTO(ICB,0,9,'S',"BCI-TINI")
INITICBS:   JMP     ENTER
            .WORD   LIT,ICBSTART,LIT,MAXICBS*8,ZERO,FILL
            .WORD   LIT,ICBSTART,LIT,TICKICB,STORE,EXIT


; ----------------------------------------------------------------------
; INTERPRET [MFORTH] ( i*x -- j*x )
;
; Interpret the line in the current Input Control Block.
;
; : INTERPRET ( i*x -- j*x )
;   0 >IN !
;   BEGIN  PARSE-WORD  DUP WHILE
;       (FIND) ( ca u 0=notfound | xt 1=imm | xt -1=interp)
;       ?DUP IF ( xt 1=imm | xt -1=interp)
;           1+  STATE @ 0=  OR ( xt 2=imm | xt 0=interp)
;           IF EXECUTE ELSE COMPILE, THEN
;       ELSE
;           NUMBER? IF
;               STATE @ IF POSTPONE LITERAL THEN
;               -- Interpreting; leave number on stack.
;           ELSE
;               TYPE  SPACE  [CHAR] ? EMIT  CR  ABORT
;           THEN
;       THEN
;   REPEAT ( j*x ca u) 2DROP ;

            LINKTO(INITICBS,0,9,'T',"ERPRETNI")
INTERPRET:  JMP     ENTER
            .WORD   ZERO,TOIN,STORE
_interpret1:.WORD   PARSEWORD,DUP,zbranch,_interpret6
            .WORD   PFIND,QDUP,zbranch,_interpret3
            .WORD   ONEPLUS,STATE,FETCH,ZEROEQUALS,OR,zbranch,_interpret2
            .WORD   EXECUTE,branch,_interpret5
_interpret2:.WORD   COMPILECOMMA,branch,_interpret5
_interpret3:.WORD   NUMBERQ,zbranch,_interpret4
            .WORD   STATE,FETCH,zbranch,_interpret5
            .WORD   LITERAL,branch,_interpret5
_interpret4:.WORD   TYPE,SPACE,LIT,'?',EMIT,CR,ABORT
_interpret5:.WORD   branch,_interpret1
_interpret6:.WORD   TWODROP
            .WORD   EXIT


; ----------------------------------------------------------------------
; LATEST [MFORTH] "latest" ( -- a-addr )
;
; a-addr is the address of a cell containing the address of the link
; field of the latest word added to the dictionary.

            LINKTO(INTERPRET,0,6,'T',"SETAL")
LATEST:     JMP     ENTER
            .WORD   GETCURRENT,EXIT


; ----------------------------------------------------------------------
; LIT [MFORTH] ( -- x)
;
; Push the next value in the PFA to the stack.

            LINKTO(LATEST,0,3,'T',"IL")
LIT:        LHLX            ; Read constant from instruction stream.
            PUSH    H       ; ..and push constant to stack.
            INX     D       ; Skip over constant
            INX     D       ; ..in instruction stream.
            NEXT


; ----------------------------------------------------------------------
; NFA>CFA [MFORTH] "n-f-a-to-c-f-a" ( nfa-addr -- cfa-addr )
;
; cfa-addr is the Code Field Address for the word whose Name Field Address
; is nfa-addr.
;
; ---
; : NFA>CFA ( nfa-addr -- cfa-addr)   NFATOCFASZ + ;

            LINKTO(LIT,0,7,'A',"FC>AFN")
NFATOCFA:   POP     H
            INXNFATOCFA(H)
            PUSH    H
            NEXT


; ----------------------------------------------------------------------
; NFA>LFA [MFORTH] "n-f-a-to-l-f-a" ( nfa-addr -- lfa-addr )
;
; lfa-addr is the Link Field Address for the word whose Name Field Address
; is nfa-addr.
;
; ---
; : NFA>LFA ( nfa-addr -- lfa-addr)   1+ ;

            LINKTO(NFATOCFA,0,7,'A',"FL>AFN")
NFATOLFA:   POP     H
            INX     H
            PUSH    H
            NEXT


; ----------------------------------------------------------------------
; NUMBER? [MFORTH] "number-question" ( c-addr u -- c-addr u 0 | n -1 )
;
; Attempt to convert a string at c-addr of length u into digits, using
; the radix in BASE.  The number and -1 is returned if the conversion
; was successful, otherwise 0 is returned.
;
; ---
; : NUMBER? ( ca u -- ca u 0 | n -1 )
;   SIGN? >R  2DUP 0 0 2SWAP  >NUMBER  ( ca u ud ca2 u2)
;   IF DROP 2DROP  R> DROP  0 ELSE
;      DROP 2NIP DROP  >R ?NEGATE  -1 THEN ;

            LINKTO(NFATOLFA,0,7,'?',"REBMUN")
NUMBERQ:    JMP     ENTER
            .WORD   SIGNQ,TOR,TWODUP,ZERO,ZERO,TWOSWAP
            .WORD       TONUMBER,zbranch,_numberq1
            .WORD   DROP,TWODROP,RFROM,DROP,ZERO,branch,_numberq2
_numberq1:  .WORD   DROP,TWONIP,DROP,RFROM,QNEGATE,LIT,0FFFFh
_numberq2:  .WORD   EXIT


; ----------------------------------------------------------------------
; POPICB [MFORTH] "push-i-c-b" ( -- )
;
; Point ICB at the previous Input Control Block.
;
; ---
; : POPICB ( --)  ICB 8 - TO ICB ;

            LINKTO(NUMBERQ,0,6,'B',"CIPOP")
POPICB:     JMP     ENTER
            .WORD   ICB,LIT,8,MINUS,LIT,TICKICB,STORE,EXIT


; ----------------------------------------------------------------------
; PUSHICB [MFORTH] "push-i-c-b" ( -- )
;
; Point ICB at the next Input Control Block.
;
; ---
; : PUSHICB ( --)  ICB 8 + TO ICB ;

            LINKTO(POPICB,0,7,'B',"CIHSUP")
PUSHICB:    JMP     ENTER
            .WORD   ICB,LIT,8,PLUS,LIT,TICKICB,STORE,EXIT


; ----------------------------------------------------------------------
; REVEAL [MFORTH] ( -- )
;
; Allow the most recent definition to be found in the dictionary.
;
; ---
; : REVEAL ( -- )   LATEST @  DUP C@ [HEX] BF AND  SWAP C! ;

            LINKTO(PUSHICB,0,6,'L',"AEVER")
REVEAL:     JMP     ENTER
            .WORD   LATEST,FETCH,DUP,CFETCH,LIT,0BFh,AND,SWAP,CSTORE,EXIT


; ----------------------------------------------------------------------
; SIGN? [MFORTH] "sign-question" ( c-addr1 u1 -- c-addr2 u2 flag )
;
;
; Attempt to convert a string at c-addr of length u into digits, using
; the radix in BASE.  The number and -1 is returned if the conversion
; was successful, otherwise 0 is returned.
;
; ---
; : SIGN? ( ca1 u1 -- ca2 u2 f )
;   OVER  C@  DUP [CHAR] - =  OVER [CHAR] + = OR  IF
;       [CHAR] - = IF -1 ELSE 0 THEN  >R 1 /STRING R>
;   ELSE DROP 0 THEN ;

            LINKTO(REVEAL,0,5,'?',"NGIS")
SIGNQ:      JMP     ENTER
            .WORD   OVER,CFETCH,DUP,LIT,'-',EQUALS,OVER,LIT,'+',EQUALS,OR
            .WORD       zbranch,_signq3
            .WORD   LIT,'-',EQUALS,zbranch,_signq1,LIT,0FFFFh,branch,_signq2
_signq1:    .WORD   ZERO
_signq2:    .WORD   TOR,ONE,SLASHSTRING,RFROM,branch,_signq4
_signq3:    .WORD   DROP,ZERO
_signq4:    .WORD   EXIT


; ----------------------------------------------------------------------
; UD* [MFORTH] "u-d-star" ( ud1 u1 -- ud2 )
;
; Multiply ud1 by u1, giving the unsigned double-cell product ud2.
;
; ---
; UD* ( ud1 u1 -- ud2)   DUP >R UM* DROP  SWAP R> UM* ROT + ;

            LINKTO(SIGNQ,0,3,'*',"DU")
UDSTAR:     JMP     ENTER
            .WORD   DUP,TOR,UMSTAR,DROP
            .WORD   SWAP,RFROM,UMSTAR,ROT,PLUS
            .WORD   EXIT


; ----------------------------------------------------------------------
; UD. [MFORTH] "u-d-dot" ( ud -- )
;
; Display ud in free field format.
;
; ---
; : UD. ( ud -- )   <# #S #> TYPE SPACE ;

            LINKTO(UDSTAR,0,3,'.',"DU")
UDDOT:      JMP     ENTER
            .WORD   LESSNUMSIGN,NUMSIGNS,NUMSIGNGRTR,TYPE,SPACE
            .WORD   EXIT


; ----------------------------------------------------------------------
; UD/MOD [MFORTH] "u-d-slash-mod" ( ud1 u1 -- n ud2 )
;
; Divide ud1 by u1 giving the quotient ud2 and the remainder n.
;
; ---
; UD/MOD ( ud1 u1 -- n ud2 )   >R 0 R@ UM/MOD  R> SWAP >R UM/MOD R> ;

            LINKTO(UDDOT,0,6,'D',"OM/DU")
LAST_CORE:
UDSLASHMOD: JMP     ENTER
            .WORD   TOR,ZERO,RFETCH,UMSLASHMOD
            .WORD   RFROM,SWAP,TOR,UMSLASHMOD,RFROM
            .WORD   EXIT