; 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.
; ======================================================================
; MFORTH Words
; ======================================================================
; ----------------------------------------------------------------------
; -ROT [MFORTH] "dash-rote" ( x1 x2 x3 -- x3 x1 x2 )
;
; Reverse-rotate the top three stack entries.
LINKTO(LINK_MFORTH,0,4,'T',"OR-")
DASHROT: SAVEDE
POP H ; Pop x3 into HL.
POP D ; Pop x2 into DE.
XTHL ; Swap TOS (x1) with HL (x3).
PUSH H ; Push x1 back onto the stack.
PUSH D ; Push x2 back onto the stack.
RESTOREDE
NEXT
; ----------------------------------------------------------------------
; .VER [MFORTH] "dot-ver" ( -- )
;
; Display the MFORTH version as a string of 16 characters ("MFORTH 1.0.0000 ").
; The space in the 16th position will be replaced with a "P" if this is a
; build that includes the profiler.
;
; ---
; : .VER ( --)
; ." MFORTH v"
; MFORTH_MAJOR [CHAR] 0 + EMIT [CHAR] . EMIT
; MFORTH_MINOR [CHAR] 0 + EMIT [CHAR] . EMIT
; BASE @ HEX MFORTH_CHANGE 0 <# # # # # #> TYPE BASE !
; [ PROFILER ] [IF] [CHAR] P EMIT [ELSE] SPACE [THEN] ;
LINKTO(DASHROT,0,4,'R',"EV.")
DOTVER: JMP ENTER
.WORD PSQUOTE,7
.BYTE "MFORTH "
.WORD TYPE
.WORD LIT,MFORTH_MAJOR,LIT,'0',PLUS,EMIT,LIT,'.',EMIT
.WORD LIT,MFORTH_MINOR,LIT,'0',PLUS,EMIT,LIT,'.',EMIT
.WORD BASE,FETCH,HEX,LIT,MFORTH_CHANGE,ZERO
.WORD LESSNUMSIGN,NUMSIGN,NUMSIGN,NUMSIGN,NUMSIGN,NUMSIGNGRTR
.WORD TYPE,BASE,STORE
#IFDEF PROFILER
.WORD LIT,'P',EMIT
#ELSE
.WORD SPACE
#ENDIF
.WORD EXIT
; ----------------------------------------------------------------------
; 2NIP [MFORTH] "two-nip" ( x1 x2 x3 x4 -- x3 x4 )
;
; Drop the first cell pair below the cell pair at the top of the stock.
LINKTO(DOTVER,0,4,'P',"IN2")
TWONIP: SAVEDE
POP H ; Pop x4.
POP D ; Pop x3.
POP PSW ; Pop x2.
POP PSW ; Pop x1.
PUSH D ; Push x3 back onto the stack.
PUSH H ; Push x4 back onto the stack.
RESTOREDE
NEXT
; ----------------------------------------------------------------------
; 8* [MFORTH] "eight-star" ( x1 -- x2 )
;
; x2 is the result of shifting x1 three bits toward the most-significant
; bit, filling the vacated least-significant bit with zero.
LINKTO(TWONIP,0,2,'*',"8")
EIGHTSTAR: POP H ; Pop x1.
DAD H ; Shift
DAD H ; ..x1
DAD H ; ..three times.
PUSH H ; Push the result onto the stack.
NEXT
; ----------------------------------------------------------------------
; GET-XY [MFORTH] "get-x-y" ( -- u1 u2 )
;
; Return the current cursor position (column u1, row u2) from the
; current input device, the upper left corner of which is column zero,
; row zero.
LINKTO(EIGHTSTAR,0,6,'Y',"X-TEG")
GETXY: MVI H,0 ; Initialize H with zero.
LDA 0F63Ah ; Get the column into A,
DCR A ; ..subtract one,
MOV L,A ; ..move it to L,
PUSH H ; ..and push the result to the stack.
LDA 0F639h ; Get the row into A,
DCR A ; ..subtract one,
MOV L,A ; ..move it to L,
PUSH H ; ..and push the result to the stack.
NEXT
; ----------------------------------------------------------------------
; COLD [MFORTH] ( i*x -- ) ( R: j*x -- )
;
; Clear the screen, display our copyright/help message, (re)insert our ROM
; trigger file, initialize our File Control Blocks, then jump to ABORT (which
; clears the stack and calls QUIT, which clears the return stack and enters
; the infinite text interpreter loop).
;
; ---
; : COLD ( i*x --; R: j*x --)
; PAGE .VER 2 SPACES ." (C)Michael Alyn Miller"
; INS-ROMTRIG INIT-FCBS ABORT ;
;
; ABORT should never return, but we HALT anyway just in case someone
; messes with the return stack.
LINKTO(GETXY,0,4,'D',"LOC")
COLD: JMP ENTER
.WORD PAGE,DOTVER,LIT,2,SPACES
.WORD PSQUOTE,22
.BYTE "(C)Michael Alyn Miller"
.WORD TYPE,INSROMTRIG,INITFCBS,ABORT
.WORD HALT
; ----------------------------------------------------------------------
; COPY-LINE [MFORTH] ( addr1 addr2 u1 -- u2 u3 )
;
; If u1 is greater than zero, copy the contents of u1 consecutive address
; units at addr1 to the u1 consecutive address units at addr2, stopping if
; a CRLF sequence is found or end-of-file is reached before u1 address units
; have been copied. After COPY-LINE completes, the u2 consecutive address
; units at addr2 contain exactly what the u2 consecutive address units at
; addr1 contained before the move. u2 is the number of address units that
; were copied. u3 is the number of address units that should be skipped
; in addr1 before the next call to COPY-LINE. u3 will normally be u2+2 if
; CRLF was reached before u1 or EOF was reached. Note that EOF is not
; included in u3, only CRLF is included in u3.
;
; ---
; : COPY-LINE ( addr1 addr2 u1 -- u2 u3)
; ROT SWAP 2>B DUP ( addr2 addr2') FORB
; B@ 26 = ?ENDB
; B@ 13 = B# 1 > AND IF B 1+ C@ 10 = IF SWAP - DUP 1+ 1+ EXIT THEN THEN
; B@ OVER C! 1+ NEXTB
; SWAP - DUP ;
LINKTO(COLD,0,9,'E',"NIL-YPOC")
COPYLINE: JMP ENTER
.WORD ROT,SWAP,TWOTOB,DUP
_copyline1: .WORD BQUES,zbranch,_copyline3
.WORD BFETCH,LIT,26,EQUALS,INVERT,zbranch,_copyline3
.WORD BFETCH,LIT,13,EQUALS,BNUMBER,ONE,GREATERTHAN,AND
.WORD zbranch,_copyline2
.WORD B,ONEPLUS,CFETCH,LIT,10,EQUALS,zbranch,_copyline2
.WORD SWAP,MINUS,DUP,ONEPLUS,ONEPLUS,EXIT
_copyline2: .WORD BFETCH,OVER,CSTORE,ONEPLUS,BPLUS,branch,_copyline1
_copyline3: .WORD SWAP,MINUS,DUP,EXIT
; ----------------------------------------------------------------------
; HALT [MFORTH] ( -- )
;
; Halt the processor.
LINKTO(COPYLINE,0,4,'T',"LAH")
HALT: HLT ; Halt the processor.
NEXT
; ----------------------------------------------------------------------
; INITRP [MFORTH] "init-r-p" ( -- ) ( R: i*x -- )
;
; Empty the return stack.
LINKTO(HALT,0,6,'P',"RTINI")
INITRP: MVI C,07Fh
NEXT
; ----------------------------------------------------------------------
; INS-ROMTRIG [MFORTH] ( -- )
;
; Insert our ROM Trigger file, replacing an existing ROM Trigger file with
; our own if one is found.
;
; ---
; : INS-ROMTRIG ( --)
; FIND-ROMTRIG DUP 0= IF FREDIR THEN >B
; 240 B!+ 255 B!+ 255 B!+ S" MFORTH" B SWAP DUP B + >B MOVE
; BL B!+ BL B!+ ;
; : FIND-ROMTRIG ( -- 0 | addr)
; [ USRDIR 11 - ] LITERAL BEGIN NXTDIR DUP WHILE
; DUP C@ 16 AND IF EXIT THEN REPEAT ;
LINKTO(INITRP,0,11,'G',"IRTMOR-SNI")
INSROMTRIG: JMP ENTER
.WORD FINDROMTRIG,DUP,ZEROEQUALS,zbranch,_insromtrig1,FREDIR
_insromtrig1:.WORD TOB,LIT,240,BSTOREPLUS,LIT,255,BSTOREPLUS,LIT,255,BSTOREPLUS
.WORD PSQUOTE,6
.BYTE "MFORTH"
.WORD B,SWAP,DUP,B,PLUS,TOB,MOVE,BL,BSTOREPLUS,BL,BSTOREPLUS
.WORD EXIT
LINKTO(INSROMTRIG,0,12,'G',"IRTMOR-DNIF")
FINDROMTRIG:JMP ENTER
.WORD LIT,0F9BAh-11
_findromtrig1:.WORD NXTDIR,DUP,zbranch,_findromtrig3
.WORD DUP,CFETCH,LIT,16,AND,zbranch,_findromtrig2
.WORD EXIT
_findromtrig2:.WORD branch,_findromtrig1
_findromtrig3:.WORD EXIT
LINKTO(FINDROMTRIG,0,6,'R',"IDTXN")
NXTDIR: POP H ; Get the entry prior to the start position.
CALL STDCALL ; Call the
.WORD 020D5h ; .."NXTDIR" routine.
JZ _nxtdirZERO ; Jump if zero to where we push zero/not found.
JMP _nxtdirFOUND; We're done.
_nxtdirZERO:LXI H,0 ; Put zero in HL.
_nxtdirFOUND:PUSH H ; Push the location (or zero) to the stack.
NEXT
LINKTO(NXTDIR,0,6,'R',"IDERF")
FREDIR: PUSH B ; Save BC (corrupted by FREDIR).
CALL STDCALL ; Call the
.WORD 020ECh ; .."FREDIR" routine.
POP B ; Restore BC.
PUSH H ; Push the location of the free entry.
NEXT
; ----------------------------------------------------------------------
; LCD [MFORTH] "l-c-d" ( -- )
;
; Select the LCD display as the output device.
LINKTO(FREDIR,0,3,'D',"CL")
LCD: CALL STDCALL ; Call the
.WORD 04B92h ; .."Reinitialize back to LCD" routine.
NEXT
; ----------------------------------------------------------------------
; PARSE-WORD [MFORTH] ( "<spaces>name<space>" -- c-addr u )
;
; Skip leading spaces and parse name delimited by a space. c-addr is the
; address within the input buffer and u is the length of the selected
; string. If the parse area is empty, the resulting string has a zero length.
;
; ---
; : PARSE-WORD ( "<spaces>name<space>" -- c-addr u) TRUE BL (parse) ;
LINKTO(LCD,0,10,'D',"ROW-ESRAP")
PARSEWORD: JMP ENTER
.WORD TRUE,BL,PPARSE,EXIT
; ----------------------------------------------------------------------
; PRN [MFORTH] "p-r-n" ( -- )
;
; Select the printer as the output device.
LINKTO(PARSEWORD,0,3,'N',"RP")
PRN: JMP ENTER
.WORD ONE,LIT,0F675h,STORE,EXIT
; ----------------------------------------------------------------------
; SP [MFORTH] ( -- a-addr )
;
; a-addr is the value of the stack pointer before a-addr was placed on
; the stack.
LINKTO(PRN,0,2,'P',"S")
SP: LXI H,0
DAD SP
PUSH H
NEXT
; ----------------------------------------------------------------------
; SP! [MFORTH] ( i*x a-addr -- )
;
; Set the stack pointer to a-addr.
LINKTO(SP,0,3,'!',"PS")
SPSTORE: POP H
SPHL
NEXT
; ----------------------------------------------------------------------
; TICKS [MFORTH] ( -- ud )
;
; ud is the number of ticks that have elapsed since MFORTH was started.
LINKTO(SPSTORE,0,5,'S',"KCIT")
TICKS: DI
LHLD TICKTICKS
PUSH H
LHLD TICKTICKS+2
EI
PUSH H
NEXT
; ----------------------------------------------------------------------
; TICKS>MS [MFORTH] "ticks-to-m-s" ( ud1 -- ud2 )
;
; Convert a tick count (ud1) to a value in milliseconds (ud2).
;
; ---
; : TICKS>MS ( ud1 -- ud2) D2* D2* ;
LINKTO(TICKS,0,8,'S',"M>SKCIT")
TICKSTOMS: JMP ENTER
.WORD DTWOSTAR,DTWOSTAR,EXIT
; ----------------------------------------------------------------------
; TIMED-EXECUTE [MFORTH] ( i*x xt -- j*x ud )
;
; Execute the given xt and return the approximate number of milliseconds
; required for execution.
;
; ---
; : TIMED-EXECUTE ( i*x xt -- j*x ud)
; TICKS 2>R EXECUTE TICKS 2R> D- ;
LINKTO(TICKSTOMS,0,13,'E',"TUCEXE-DEMIT")
TIMEDEXECUTE:JMP ENTER
.WORD TICKS,TWOTOR,EXECUTE,TICKS,TWORFROM,DMINUS,EXIT
; ----------------------------------------------------------------------
; VOCABULARY [MFORTH] ( "<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 "word list".
;
; name Execution: ( -- )
; Replace the first word list in the search order with name.
;
; ---
; : VOCABULARY ( "<spaces>name" -- )
; CREATE WORDLIST DOES> SOESTART ! ;
LINKTO(TIMEDEXECUTE,0,10,'Y',"RALUBACOV")
VOCABULARY: JMP ENTER
.WORD CREATE,LIT,-CFASZ,ALLOT,LIT,195,CCOMMA,LIT,pvocabulary,COMMA
.WORD WORDLIST
.WORD EXIT
pvocabulary:CALL DODOES
.WORD LIT,SOESTART,STORE,EXIT
; ----------------------------------------------------------------------
; [HEX] [MFORTH] "bracket-hex"
;
; Interpretation:
; Interpretation semantics for this word are undefined.
;
; Compilation: ( "<spaces>hexnum" -- )
; Skip leading space delimiters. Parse hexnum, a base 16 number
; delimited by a space. Append the run-time semantics given below to
; the current definition.
;
; Run-time: ( -- u )
; Place u, the value of hexnum, on the stack.
;
; ---
; : [HEX] ( "<spaces>name" -- u)
; BASE @ HEX PARSE-WORD ( savedbase ca u)
; NUMBER? IF ['] LIT COMPILE, , BASE ! EXIT THEN
; ABORT" Not a hex number" ; IMMEDIATE
LINKTO(VOCABULARY,1,5,']',"XEH[")
LAST_MFORTH:
BRACKETHEX: JMP ENTER
.WORD BASE,FETCH,HEX,PARSEWORD
.WORD NUMBERQ,zbranch,_brackethex1
.WORD LIT,LIT,COMPILECOMMA,COMMA,BASE,STORE,EXIT
_brackethex1:.WORD PSQUOTE,16
.BYTE "Not a hex number"
.WORD TYPE,ABORT