OSDN Git Service

0a8846a36cfb52530fd46ff9c4347da251c7ed92
[fast-forth/master.git] / forthMSP430FR.asm
1 ;
2 ;-------------------------------------------------------------------------------
3 ; Vingt fois sur le métier remettez votre ouvrage,
4 ; Polissez-le sans cesse, et le repolissez,
5 ; Ajoutez quelquefois, et souvent effacez.               Boileau, L'Art poétique
6 ;-------------------------------------------------------------------------------
7
8 ;-------------------------------------------------------------------------------
9 ; SCITE editor: copy https://www.scintilla.org/Sc4xx.exe to \prog\scite.exe
10 ;-------------------------------------------------------------------------------
11 ; MACRO ASSEMBLER AS
12 ; unzip http://john.ccac.rwth-aachen.de:8000/ftp/as/precompiled/i386-unknown-win32/aswcurr.zip
13 ;-------------------------------------------------------------------------------
14     .listing purecode   ; reduce listing to true conditionnal parts
15     MACEXP_DFT noif     ; reduce macros listing to true part
16     .PAGE  0            ; listing without pagination
17 ;-------------------------------------------------------------------------------
18
19 VER .equ "V400"     ; FORTH version
20
21 ;===============================================================================
22 ; before assembling or programming you must set TARGET in scite param1 (SHIFT+F8)
23 ; according to the selected (uncommented) TARGET below
24 ;===============================================================================
25 ;    TARGET        ;
26 ;MSP_EXP430FR5739  ; compile for MSP-EXP430FR5739 launchpad
27 ;MSP_EXP430FR5969  ; compile for MSP-EXP430FR5969 launchpad
28 MSP_EXP430FR5994  ;; compile for MSP-EXP430FR5994 launchpad
29 ;MSP_EXP430FR6989  ; compile for MSP-EXP430FR6989 launchpad
30 ;MSP_EXP430FR4133  ; compile for MSP-EXP430FR4133 launchpad
31 ;MSP_EXP430FR2355  ; compile for MSP-EXP430FR2355 launchpad
32 ;MSP_EXP430FR2433  ; compile for MSP-EXP430FR2433 launchpad
33 ;LP_MSP430FR2476   ; compile for LP_MSP430FR2476  launchpad
34 ;CHIPSTICK_FR2433  ; compile for "CHIPSTICK" of M. Ken BOAK
35
36 ; choose DTC model (Direct Threaded Code); if you don't know, choose 2
37 DTC .equ 2  ; DTC model 1 : DOCOL = CALL rDOCOL           14 cycles 1 word      shortest DTC model
38             ; DTC model 2 : DOCOL = PUSH IP, CALL rEXIT   13 cycles 2 words     best compromize to mix FORTH/ASM code
39             ; DTC model 3 : inlined DOCOL (and LO2HI)      9 cycles 4 words     fastest
40
41 THREADS     .equ 16 ;  1,  2 ,  4 ,  8 ,  16,  32  search entries in word-set.
42                     ; +0, +28, +48, +56, +90, +154 bytes, usefull to speed up compilation;
43                     ; the FORTH interpreter is speed up by about a square root factor of THREADS.
44
45 FREQUENCY   .equ 8 ; fully tested at 1,2,4,8,16 MHz, plus 24 MHz for MSP430FR57xx,MSP430FR2355
46
47
48 ; ==============================================================================
49 ;UART_TERMINAL ; COMMENT TO SWITCH FROM UART TO I2C TERMINAL
50 ; ==============================================================================
51     .IFDEF UART_TERMINAL
52 TERMINALBAUDRATE    .equ 4000000
53 TERMINAL3WIRES      ;; + 18 bytes  enable 3 wires XON/XOFF software flow control
54 TERMINAL4WIRES      ;; + 12 bytes  enable 4 wires RTS hardware flow control
55 ;TERMINAL5WIRES      ; + 10 bytes  enable 5 wires RTS/CTS hardware flow control
56 ;HALFDUPLEX          ; switch to UART half duplex TERMINAL input
57     .ELSE
58 I2C_TERM_ADR .equ 18 ; I2C_TERMINAL_Slave_Address << 1
59     .ENDIF
60
61 ;===============================================================================
62 ; KERNEL ADDONs that can't be added later
63 ;===============================================================================
64 DOUBLE_INPUT        ;; +   60 bytes : adds the interpretation engine for double numbers (numbers with dot)
65 FIXPOINT_INPUT      ;; +   68 bytes : adds the interpretation engine for Q15.16 numbers (numbers with comma)
66 VOCABULARY_SET      ;; +  194 bytes : adds words: WORDSET FORTH hidden PREVIOUS ONLY DEFINITIONS
67 SD_CARD_LOADER      ;; + 1582 bytes : to load source files from SD_card
68 BOOTLOADER          ;; +   82 bytes : includes in WARM process the bootloader SD_CARD\BOOT.4TH.
69 SD_CARD_READ_WRITE  ;; + 1168 bytes : to read, create, write and del files + copy text files from PC to target SD_Card
70 LARGE_CODE          ;; +  506 bytes : allows assembler to execute code up to 1MB.
71 LARGE_DATA          ;; + 1212 bytes : extended assembler to 20 bits addresses and datas.
72 ;PROMPT              ; +   18 bytes : to display the prompt "ok ", (obsolete).
73 ;===============================================================================
74
75 ;-------------------------------------------------------------------------------
76 ; OPTIONS that can be added later by downloading their source file >------------------------------------+
77 ; however, added here, they are protected against WIPE and Deep Reset.                                  |
78 ;-------------------------------------------------------------------------------                        v
79 ;CORE_COMPLEMENT     ; + 2304 bytes, if you want a conventional FORTH ANS94 compliant               CORE_ANS.f
80 ;FIXPOINT            ; +  422/528 bytes add HOLDS F+ F- F/ F* F#S F. S>F                            FIXPOINT.f
81 ;UTILITY             ; +  434/524 bytes (1/16threads) : add .S .RS WORDS U.R DUMP ?                 UTILITY.f
82 ;SD_TOOLS            ; +  142 bytes for trivial DIR, FAT, CLUSTR. and SECTOR. view, (adds UTILITY)  SD_TOOLS.f
83 ;DOUBLE              ;              DOUBLE word set                                                 DOUBLE.f
84     .save
85     .listing off
86 ;===============================================================================
87 ; Software control flow XON/XOFF configuration:
88 ;===============================================================================
89 ; Launchpad <-> UARTtoUSB device <-> TeraTerm TERMINAL
90 ;        RX <-- TX
91 ;        TX --> RX
92 ;       GND <-> GND
93 ;
94 ; TERATERM config terminal:     NewLine receive : LF,
95 ;                               NewLine transmit : CR+LF
96 ;                               Size : 96 chars x 49 lines (adjust lines according to your display)
97 ;
98 ; TERATERM config serial port:  TERMINALBAUDRATE value,
99 ;                               8 bits, no parity, 1 Stop bit,
100 ;                               XON/XOFF flow control,
101 ;                               delay = 0ms/line, 0ms/char
102 ;
103 ; don't forget to save always new TERATERM configuration !
104
105 ; ------------------------------------------------------------------------------
106 ; Only two usb2uart bridges correctly handle XON / XOFF: cp2102 and pl2303.
107 ; ------------------------------------------------------------------------------
108 ; the best and cheapest: UARTtoUSB cable with Prolific PL2303HXD (or PL2303TA)
109 ; works well in 3 WIRES (XON/XOFF) and 4WIRES (GND,RX,TX,RTS) config
110 ; ------------------------------------------------------------------------------
111 ;       PL2303TA 4 wires CABLE                         PL2303HXD 6 wires CABLE
112 ; pads upside: 3V3,txd,rxd,gnd,5V               pads upside: gnd, 3V3,txd,rxd,5V
113 ;    downside: cts,dcd,dsr,rts,dtr                 downside:     rts,cts
114 ; ------------------------------------------------------------------------------
115 ; WARNING ! if you use PL2303TA/HXD cable as supply, open the box before to weld red wire on 3v3 pad !
116 ; ------------------------------------------------------------------------------
117 ; up to 115200  Bds  (500kHz)
118 ; up to 230400  Bds  (1MHz)
119 ; up to 460800  Bds  (2MHz)
120 ; up to 921600  Bds  (4MHz)
121 ; up to 1843200 Bds  (8MHz)
122 ; up to 3 MBds       (12MHz,PL2303HXD with shortened cable < 80cm)
123 ; up to 4 MBds       (16MHz,PL2303HXD with shortened cable < 60cm)
124 ; up to 5 MBds       (20MHz,PL2303HXD with shortened cable < 40cm)
125 ; up to 6 MBds       (24MHz,PL2303HXD with shortened cable < 20cm)
126
127 ; UARTtoUSB module with Silabs CP2102 (supply current = 20 mA)
128 ; ------------------------------------------------------------------------------
129 ; WARNING ! if you use it as supply, buy a CP2102 module with a VCC switch 5V/3V3 and swith on 3V3 !
130 ; ------------------------------------------------------------------------------
131 ; 9600,19200,38400 (250kHz)
132 ; + 57600, 115200 (500kHz)
133 ; + 134400,230400 (1MHz)
134 ; + 460800 (2MHz)
135 ; + 921600 (4MHz,8MHz,16MHz,24MHz)
136
137 ;===============================================================================
138 ; Hardware control flow configuration: RTS is wired on UART2USB CTS pin
139 ;===============================================================================
140
141 ; Launchpad <-> UARTtoUSB
142 ;        RX <-- TX
143 ;        TX --> RX
144 ;       RTS --> CTS     (see launchpad.asm for RTS selected pin)
145 ;       GND <-> GND
146
147 ; RTS pin may be permanently wired on SBWTCK/TEST pin without disturbing SBW 2 wires programming
148
149 ; TERATERM config terminal      : NewLine receive : LF,
150 ;                                 NewLine transmit : CR+LF
151 ;                                 Size : 96 chars x 49 lines (adjust lines to your display)
152
153 ; TERATERM config serial port   : TERMINALBAUDRATE value,
154 ;                                 8bits, no parity, 1Stopbit,
155 ;                                 Hardware flow control,
156 ;                                 delay = 0ms/line, 0ms/char
157
158 ; don't forget : save new TERATERM configuration !
159
160 ; notice that the control flow seems not necessary for TX (CTS <-- RTS)
161
162 ; UARTtoUSB module with PL2303TA/HXD
163 ; ------------------------------------------------------------------------------
164 ; WARNING ! if you use PL2303TA/HXD cable as supply, open the box before to weld red wire on 3v3 pad !
165 ; ------------------------------------------------------------------------------
166 ; up to 250 kbds / MHz
167 ; ----------------------------------
168 ; 9600,19200,38400,57600    (250kHz)
169 ; + 115200                  (500kHz)
170 ; + 201600,230400,250000    (1MHz)
171 ; + 403200,460800           (2MHz)
172 ; + 806400,921600           (4MHz)
173 ; + 1843200                 (8MHz)
174 ; + 2764800                 (12MHz)
175 ; + 4000000                 (16MHz)
176 ; + 5000000                 (20MHz)
177 ; + 6000000                 (24MHz)
178
179 ; UARTtoUSB module with FTDI FT232RL (FT230X don't work correctly)
180 ; ------------------------------------------------------------------------------
181 ; WARNING ! buy a FT232RL module with a switch 5V/3V3 and select 3V3 !
182 ; ------------------------------------------------------------------------------
183 ; 9600,19200,38400,57600,115200 (500kHz)
184 ; + 230400 (1MHz)
185 ; + 460800 (2MHz)
186 ; + 921600 (4,8,16 MHz)
187
188 ; ------------------------------------------------------------------------------
189 ; UARTtoBluetooth 2.0 module (RN42 sparkfun bluesmirf) at 921600bds
190 ; ------------------------------------------------------------------------------
191 ; 9600,19200,38400,57600,115200 (500kHz)
192 ; + 230400 (1MHz)
193 ; + 460800 (2MHz)
194 ; + 921600 (4,8,16 MHz)
195
196 ; RN42 config : connect RN41/RN42 module on teraterm, via USBtoUART bridge,
197 ; -----------   8n1, 115200 bds, no flow control, echo on
198 ;               $$$         // enter control mode, response: AOK
199 ;               SU,92       // set 921600 bds, response: AOK
200 ;               R,1         // reset module to take effect
201 ;
202 ;               connect RN42 module on FastForth target
203 ;               add new bluetooth device on windows, password=1234
204 ;               open the created output COMx port with TERATERM at 921600bds
205
206
207 ; TERATERM config terminal      : NewLine receive : LF,
208 ;                                 NewLine transmit : CR+LF
209 ;                                 Size : 80 chars x 44 lines (adjust lines to your display)
210
211 ; TERATERM config serial port   : TERMINALBAUDRATE value,
212 ;                                 8bits, no parity, 1Stopbit,
213 ;                                 Hardware flow control or software flow control or ...no flow control!
214 ;                                 delay = 0ms/line, 0ms/char
215
216 ; don't forget : save new TERATERM configuration !
217
218 ; in fact, compared to using a UART USB bridge, only the COMx port is to be updated.
219     .restore
220 ; ------------------------------------------------------------------------------
221     .include "ThingsInFirst.inc" ; macros, target definitions, RAM & INFO variables...
222 ;-------------------------------------------------------------------------------
223     .org    MAIN_ORG
224 ;-------------------------------------------------------------------------------
225 ; DTCforthMSP430FR5xxx program (FRAM) memory
226 ;-------------------------------------------------------------------------------
227 ; here we place the FORTH primitives without name.
228 ; User can access them via declarations made in \inc\MSP430FRxxxx.pat
229 ; ------------------------------------------------------------------------------
230 ; COMPILING OPERATORS
231 ; ------------------------------------------------------------------------------
232 ; Primitive LIT; compiled by LITERAL
233 ; LIT      -- x    fetch inline literal to stack
234 ; This is the run-time code of LITERAL.
235 LIT         SUB #2,PSP          ; 1  save old TOS..
236             MOV TOS,0(PSP)      ; 3  ..onto stack
237             MOV @IP+,TOS        ; 2  fetch new TOS value
238             MOV @IP+,PC         ; 4  NEXT
239
240 TWODUP_XSQUOTE                  ; see [ELSE]
241             MOV TOS,-2(PSP)     ; 3
242             MOV @PSP,-4(PSP)    ; 4
243             SUB #4,PSP          ; 1
244 ; Primitive XSQUOTE; compiled by SQUOTE
245 ; (S")     -- addr u   run-time code to get address and length of a compiled string.
246 XSQUOTE     SUB #4,PSP          ; 1                 push old TOS on stack
247             MOV TOS,2(PSP)      ; 3                 and reserve one cell on stack
248             MOV.B @IP+,TOS      ; 2 -- ? u          u = lenght of string
249             MOV IP,0(PSP)       ; 3 -- addr u       IP is odd...
250             ADD TOS,IP          ; 1                 IP=addr+u=addr(end_of_string)
251             BIT #1,IP           ; 1                 IP=addr+u   Carry set/clear if odd/even
252             ADDC #0,IP          ; 1                 IP=addr+u aligned
253             MOV @IP+,PC         ; 4  16~
254
255 ; primitive MU/MOD; used by ?NUMBER UM/MOD, and M*/ in DOUBLE word set
256 ; MU/MOD    UDVDlo UDVDhi UDIVlo -- UREMlo UQUOTlo UQUOThi
257 ;-------------------------------------------------------------------------------
258 ; unsigned 32-BIT DiViDend : 16-BIT DIVisor --> 32-BIT QUOTient 16-BIT REMainder
259 ;-------------------------------------------------------------------------------
260 ; two times faster if 16 bits DiViDend (cases of U. and . among others)
261
262 ; reg     division            MU/MOD      NUM                       M*/
263 ; ---------------------------------------------------------------------
264 ; S     = DVD(15-0)         = ud1lo     = ud1lo                     ud1lo
265 ; TOS   = DVD(31-16)        = ud1hi     = ud1hi                     ud1mi
266 ; W     = DVD(47-32)/REM    = rem       = digit --> char --> -[HP]  ud1hi
267 ; T     = DIV(15-0)         = BASE      = BASE                      ud2
268 ; X     = QUOTlo            = ud2lo     = ud2lo                     QUOTlo
269 ; Y     = QUOThi            = ud2hi     = ud2hi                     QUOThi
270 ; rDODOES = count
271
272 MUSMOD      MOV TOS,T               ;1 T = DIVlo
273             MOV 2(PSP),S            ;3 S = DVDlo
274             MOV @PSP,TOS            ;2 TOS = DVDhi
275 MUSMOD1     MOV #0,W                ;1  W = REMlo = 0
276             MOV #32,rDODOES         ;2  init loop count
277             CMP #0,TOS              ;1  DVDhi=0 ?
278             JNZ MDIV1               ;2  no
279 ; ----------------------------------;
280 MDIV1DIV2   RRA rDODOES             ;1  yes:loop count / 2
281             MOV S,TOS               ;1      DVDhi <-- DVDlo
282             MOV #0,S                ;1      DVDlo <-- 0
283             MOV #0,X                ;1      QUOTlo <-- 0 (to do QUOThi = 0 at the end of division)
284 ; ----------------------------------;
285 MDIV1       CMP T,W                 ;1  REMlo U>= DIVlo ?
286             JNC MDIV2               ;2  no : carry is reset
287             SUB T,W                 ;1  yes: REMlo - DIVlo ; carry is set
288 MDIV2       ADDC X,X                ;1  RLC quotLO
289             ADDC Y,Y                ;1  RLC quotHI
290             SUB #1,rDODOES          ;1  Decrement loop counter
291             JN ENDMDIV              ;2
292             ADD S,S                 ;1  RLA DVDlo
293             ADDC TOS,TOS            ;1  RLC DVDhi
294             ADDC W,W                ;1  RLC REMlo
295             JNC MDIV1               ;2
296             SUB T,W                 ;1  REMlo - DIVlo
297             BIS #1,SR               ;1  SETC
298             JMP MDIV2               ;2
299 ENDMDIV     MOV #XDODOES,rDODOES    ;2  restore rDODOES
300             MOV W,2(PSP)            ;3  REMlo in 2(PSP)
301             MOV X,0(PSP)            ;3  QUOTlo in 0(PSP)
302             MOV Y,TOS               ;1  QUOThi in TOS
303 RET_ADR     MOV @RSP+,PC            ;4  35 words, about 466/246 cycles, not FORTH executable !
304
305 ; : SETIB SOURCE 2! 0 >IN ! ;
306 ; SETIB      org len --        set Input Buffer, shared by INTERPRET and [ELSE]
307 SETIB       MOV #0,&TOIN            ;3
308             MOV @PSP+,&SOURCE_ORG   ;4 -- len
309             MOV TOS,&SOURCE_LEN     ;3 -- len
310 DROP        MOV @PSP+,TOS           ;2 --
311             MOV @IP+,PC             ;4
312
313 ; REFILL    accept one line to input buffer and leave org len' of the filled input buffer
314 ; as it has no more host OS and as waiting command is done by ACCEPT, REFILL's flag is useless
315 ; : REFILL TIB DUP CIB_LEN ACCEPT   ;   -- org len'     shared by QUIT and [ELSE]
316 REFILL      SUB #4,PSP              ;1
317             MOV TOS,2(PSP)          ;3                  save TOS
318 TWODROP_REFILL                      ;                   see [ELSE]
319             MOV #CIB_LEN,TOS        ;2  -- x len        Current Input Buffer LENght
320             .word 40BFh             ;                   MOV #imm,index(PSP)
321 CIB_ORG     .word TIB_ORG           ;                   imm=TIB_ORG
322             .word 0                 ;4  -- org len      index=0 ==> MOV #TIB_ORG,0(PSP)
323             MOV @PSP,-2(PSP)        ;4  -- org len
324             SUB #2,PSP              ;1  -- org org len
325             JMP ACCEPT              ;2  org org len -- org len'
326
327 ; Primitive QFBRAN; compiled by IF UNTIL
328 ;Z ?FalseBranch   x --              ; branch if TOS is FALSE (TOS = 0)
329 QFBRAN      CMP #0,TOS              ; 1  test TOS value
330             MOV @PSP+,TOS           ; 2  pop new TOS value (doesn't change flags)
331 ZBRAN       JNZ SKIPBRANCH          ; 2  if TOS was <> 0, skip the branch; 10 cycles
332 BRAN        MOV @IP,IP              ; 2  take the branch destination
333             MOV @IP+,PC             ; 4  ==> branch taken, 11 cycles
334
335 XDODOES                             ; 4 for CALL rDODOES
336             SUB #2,PSP              ;+1
337             MOV TOS,0(PSP)          ;+3 save TOS on parameters stack
338             MOV @RSP+,TOS           ;+2 TOS = PFA address of master word, i.e. address of its first cell after DOES>
339             PUSH IP                 ;+3 save IP on return stack
340             MOV @TOS+,IP            ;+2 IP = CFA of Master word, TOS = BODY address of created word
341             MOV @IP+,PC             ;+4 = 19~ = ITC-2
342
343 XDOCON                              ; 4 for CALL rDOCON
344             SUB #2,PSP              ;+1
345             MOV TOS,0(PSP)          ;+3 save TOS on parameters stack
346             MOV @RSP+,TOS           ;+2 TOS = PFA address of master word CONSTANT
347             MOV @TOS,TOS            ;+2 TOS = CONSTANT value
348             MOV @IP+,PC             ;+4 = 16~ = ITC+4
349
350
351     .IFNDEF UART_TERMINAL
352         .include "forthMSP430FR_TERM_I2C.asm"
353     .ELSE
354         .IFDEF HALFDUPLEX
355             .include "forthMSP430FR_TERM_HALF.asm"
356         .ELSE
357             .include "forthMSP430FR_TERM_UART.asm"
358         .ENDIF
359     .ENDIF
360     .IFDEF SD_CARD_LOADER
361         .include "forthMSP430FR_SD_ACCEPT.asm"
362     .ENDIF
363
364     .IF DTC = 1                     ; DOCOL = CALL rDOCOL, [rDOCOL] = XDOCOL
365 XDOCOL      MOV @RSP+,W             ; 2
366             PUSH IP                 ; 3     save old IP on return stack
367             MOV W,IP                ; 1     set new IP to PFA
368             MOV @IP+,PC             ; 4     = NEXT
369     .ENDIF                          ; 10 cycles
370
371             FORTHWORD "TYPE"
372 ;https://forth-standard.org/standard/core/TYPE
373 ;C TYPE    adr u --     type string to terminal
374 TYPE        PUSH IP                 ;3
375             MOV #TYPE_NEXT+2,IP     ;2                  because SUB #2,IP
376             MOV @PSP+,X             ;2 -- len           X = adr
377 TYPELOOP    SUB #2,IP               ;1                  [IP] = TYPE_NEXT
378             SUB #2,PSP              ;1 -- x len
379             MOV TOS,0(PSP)          ;3 -- len len
380             MOV.B @X+,TOS           ;2 -- len char
381             JMP EMIT                ;22                 S T W regs are free
382 TYPE_NEXT   mNEXTADR                ;  -- len
383             SUB.B #1,TOS            ;1 -- len-1         byte operation, according to the /COUNTED-STRING value
384             JNZ TYPELOOP            ;2                  32~/19~ EMIT loop 312/526 kBds/MHz --> 7.5MBds @ 24 MHz
385             JZ DROPEXIT             ;2
386
387 ; ------------------------------------------------------------------------------
388 ; forthMSP430FR :  CONDITIONNAL COMPILATION, 114/109 words
389 ; ------------------------------------------------------------------------------
390 ; goal: speed up the false conditionnal to reach true|false equal time: reached!
391 ; ------------------------------------------------------------------------------
392
393             FORTHWORDIMM "[THEN]"   ; does nothing
394 ; https://forth-standard.org/standard/tools/BracketTHEN
395             MOV @IP+,PC
396
397 ; ------------------------------------------------------------------------------
398 ; BRanch if BAD strings COMParaison, [COMPARE ZEROEQUAL QFBRAN] replacement
399 QBRBADCOMP                  ; addr1 u1 addr2 u2 --
400             MOV TOS,S       ;1          S = u2
401             MOV @PSP+,Y     ;2          Y = addr2
402             CMP @PSP+,S     ;2          u1 = u2 ?
403             MOV @PSP+,X     ;2          X = addr1
404             MOV @PSP+,TOS   ;2 --
405             JNZ BRAN        ;2 --       branch if u1<>u2, 11+6 cycles
406 COMPLOOP    CMP.B @Y+,0(X)  ;4
407             JNZ BRAN        ;2 --       if char1<>char2; branch on first char <> in 17+6 cycles
408             ADD #1,X        ;1          addr+1
409             SUB #1,S        ;1          u-1
410             JNZ COMPLOOP    ;2          10 cycles char comp loop
411 SKIPBRANCH  ADD #2,IP       ;1
412             MOV @IP+,PC     ;4
413
414 ; [TWODROP ONEMINUS ?DUP ZEROEQUAL QFBRAN next_comp EXIT] replacement
415 QBRNEXTCMP                  ;    -- cnt addr u
416             ADD #2,PSP      ;1   -- cnt addr    NIP
417             MOV @PSP+,TOS   ;2   -- cnt         + DROP = TWODROP 
418             SUB #1,TOS      ;3   -- cnt-1       ONEMINUS
419             JNZ BRAN        ;2   -- cnt-1       branch to next comparaison if <> 0
420 DROPEXIT    MOV @PSP+,TOS   ;2   --
421             MOV @RSP+,IP    ;2
422             MOV @IP+,PC     ;4
423
424             FORTHWORDIMM  "[ELSE]"
425 ; https://forth-standard.org/standard/tools/BracketELSE
426 ;Compilation:
427 ;Perform the execution semantics given below.
428 ;Execution:
429 ;( "<spaces>name ..." -- )
430 ;Skipping leading spaces, parse and discard space-delimited words from the parse area,
431 ;including nested occurrences of [IF] ... [THEN] and [IF] ... [ELSE] ... [THEN],
432 ;until the word [THEN] has been parsed and discarded.
433 ;If the parse area becomes exhausted, it is refilled as with REFILL.
434 ;the loop back from BRACKTELSE1 to BRACKTELSE0 is shorten
435 BRACKETELSE mDOCOL
436             .word   LIT,1                   ; -- cnt
437             .word   BRAN,BRACKTELSE1        ;                   6~ versus 5~ for ONEPLUS
438 BRACKTELSE0 .word   XSQUOTE                 ;                   end of skiped line
439             .byte   5,13,"ko ",10           ;                   send CR + "ko " + LF
440             .word   TYPE                    ;                   CR ." ko " LF 
441             .word   TWODROP_REFILL          ;                   REFILL Input Buffer with next line
442             .word   SETIB                   ;                   SET Input Buffer pointers SOURCE_LEN, SOURCE_ORG and clear >IN
443 BRACKTELSE1 .word   BL_WORD,COUNT           ; -- cnt addr u     Z = 1 if u = 0
444             .word   ZBRAN,BRACKTELSE0       ; -- cnt addr 0     Z = 1 --> end of line, -6~
445             .word   TWODUP_XSQUOTE          ;                   24 ~
446             .byte   6,"[THEN]"              ; -- cnt addr u addr1 u1 addr2 u2
447             .word   QBRBADCOMP,BRACKTELSE2  ; -- cnt addr u     if [THEN] not found, jump for next comparaison
448             .word   QBRNEXTCMP,BRACKTELSE1  ;                   if found, 2DROP,  count-1, loop back if count <> 0 | DROP EXIT if count = 0
449 BRACKTELSE2 .word   TWODUP_XSQUOTE          ;
450             .byte   6,"[ELSE]"              ; -- cnt addr u addr1 u1 addr2 u2
451             .word   QBRBADCOMP,BRACKTELSE3  ; -- cnt addr u     if [ELSE] not found, jump for next comparaison
452             .word   QBRNEXTCMP,BRACKTELSE4  ;                   if found, 2DROP, count-1, loop back if count <> 0
453 BRACKTELSE3 .word   XSQUOTE                 ;                   16 ~
454             .byte   4,"[IF]"                ; -- cnt addr1 u1 addr2 u2
455             .word   QBRBADCOMP,BRACKTELSE1  ; -- cnt            if [IF] not found, loop back for next word comparaison
456 BRACKTELSE4 .word   ONEPLUS                 ; -- cnt+1          if found,  same loop back with count+1
457             .word   BRAN,BRACKTELSE1        ;         
458
459             FORTHWORDIMM "[IF]" ; flag --
460 ; https://forth-standard.org/standard/tools/BracketIF
461 ;Compilation:
462 ;Perform the execution semantics given below.
463 ;Execution: ;( flag | flag "<spaces>name ..." -- )
464 ;If flag is true, do nothing. Otherwise, skipping leading spaces,
465 ;   parse and discard space-delimited words from the parse area,
466 ;   including nested occurrences of [IF] ... [THEN] and [IF] ... [ELSE] ... [THEN],
467 ;   until either the word [ELSE] or the word [THEN] has been parsed and discarded.
468 ;If the parse area becomes exhausted, it is refilled as with REFILL. [IF] is an immediate word.
469 ;An ambiguous condition exists if [IF] is POSTPONEd,
470 ;   or if the end of the input buffer is reached and cannot be refilled before the terminating [ELSE] or [THEN] is parsed.
471 BRACKETIF   CMP #0,TOS      ; -- f
472             MOV @PSP+,TOS   ; --
473             JZ BRACKETELSE  ;       if false flag output
474             MOV @IP+,PC     ;       if true flag output
475
476             FORTHWORDIMM  "[UNDEFINED]"
477 ; https://forth-standard.org/standard/tools/BracketUNDEFINED
478 ;Compilation:
479 ;Perform the execution semantics given below.
480 ;Execution: ( "<spaces>name ..." -- flag )
481 ;Skip leading space delimiters. Parse name delimited by a space.
482 ;Return a false flag if name is the name of a word that can be found,
483 ;otherwise return a true flag.
484             mDOCOL
485             .word   BL_WORD,FIND
486             mNEXTADR
487             SUB #1,TOS      ;1 borrow if TOS was 0
488             SUBC TOS,TOS    ;1 TOS=-1 if borrow was set
489 NIP_EXIT    MOV @RSP+,IP
490 NIP         ADD #2,PSP      ;1
491             MOV @IP+,PC     ;4
492
493             FORTHWORDIMM  "[DEFINED]"
494 ; https://forth-standard.org/standard/tools/BracketDEFINED
495 ;Compilation:
496 ;Perform the execution semantics given below.
497 ;Execution:
498 ;( "<spaces>name ..." -- flag )
499 ;Skip leading space delimiters. Parse name delimited by a space.
500 ;Return a true flag if name is the name of a word that can be found,
501 ;otherwise return a false flag. [DEFINED] is an immediate word.
502 DEFINED     mDOCOL
503             .word   BL_WORD,FIND
504             .word   NIP_EXIT
505
506 ;-------------------------------------------------------------------------------
507 ; STACK OPERATIONS
508 ;-------------------------------------------------------------------------------
509 ; https://forth-standard.org/standard/core/SWAP
510 SWAP        PUSH @PSP+      ; 3
511
512 ; https://forth-standard.org/standard/core/Rfrom
513 ; R>    -- x    R: x --   pop from return stack
514 ; VARIABLE run time called by CALL rDOVAR
515 RFROM       SUB #2,PSP      ; 1
516             MOV TOS,0(PSP)  ; 3
517             MOV @RSP+,TOS   ; 2
518             MOV @IP+,PC     ; 4
519
520 ; https://forth-standard.org/standard/core/DUP
521 ; DUP      x -- x x      duplicate top of stack
522 DUP         SUB #2,PSP      ; 1
523             MOV TOS,0(PSP)  ; 3
524             MOV @IP+,PC     ; 4
525
526 ;-------------------------------------------------------------------------------
527 ; ARITHMETIC OPERATIONS
528 ;-------------------------------------------------------------------------------
529 ; https://forth-standard.org/standard/core/Minus
530 ; -      n1/u1 n2/u2 -- n3/u3      n3 = n1-n2
531 MINUS       SUB @PSP+,TOS   ;2  -- n2-n1
532 NEGATE      XOR #-1,TOS     ;1
533 ONEPLUS     ADD #1,TOS      ;1  -- n3 = -(n2-n1) = n1-n2
534             MOV @IP+,PC
535
536 ;-------------------------------------------------------------------------------
537 ; MEMORY OPERATIONS
538 ;-------------------------------------------------------------------------------
539             FORTHWORD "@"
540 ; https://forth-standard.org/standard/core/Fetch
541 ; @       a-addr -- x   fetch cell from memory
542 FETCH       MOV @TOS,TOS
543             MOV @IP+,PC
544
545             FORTHWORD "!"
546 ; https://forth-standard.org/standard/core/Store
547 ; !        x a-addr --   store cell in memory
548 STORE       MOV @PSP+,0(TOS);4
549             MOV @PSP+,TOS   ;2
550             MOV @IP+,PC     ;4
551
552 ; ------------------------------------------------------------------------------
553 ; STRINGS PROCESSING
554 ; ------------------------------------------------------------------------------
555
556 ; use SQUOTE+10 to enable separator select
557
558             FORTHWORDIMM "S\34" ; immediate
559 ; https://forth-standard.org/standard/core/Sq
560 ; S"       --             compile in-line string
561 SQUOTE      SUB #2,PSP              ;               first choose separator
562             MOV TOS,0(PSP)
563             MOV #'"',TOS            ;               separator = '"'
564 ; SQUOTE+10 address                 ;
565             MOV #0,T                ;               volatile CAPS OFF, only for WORDD+4 below
566             mDOCOL              
567             .word LIT,XSQUOTE,COMMA ;               obviously use not T register...
568             .word WORDD+4           ; -- c-addr     = DP,  W=Count_of_chars
569             mNEXTADR                ;
570             ADD #1,W                ;               to include count of chars
571             BIT #1,W                ;               C = /Z
572             ADDC W,&DP              ; -- addr       new DP is aligned
573             JMP DROPEXIT            ;
574             
575             FORTHWORDIMM ".\34"     ; immediate
576 ; https://forth-standard.org/standard/core/Dotq
577 ; ."       --              compile string to print
578 DOTQUOTE    mDOCOL
579             .word   SQUOTE
580             .word   LIT,TYPE,COMMA
581             .word   EXIT
582
583 ;-------------------------------------------------------------------------------
584 ; NUMERIC OUTPUT
585 ;-------------------------------------------------------------------------------
586 ; Numeric conversion is done last digit first, so
587 ; the output buffer is built backwards in memory.
588
589             FORTHWORD "<#"
590 ; https://forth-standard.org/standard/core/num-start
591 ; <#    --       begin numeric conversion (initialize Hold Pointer)
592 LESSNUM     MOV #HOLD_BASE,&HP
593             MOV @IP+,PC
594
595             FORTHWORD "#"
596 ; https://forth-standard.org/standard/core/num
597 ; #     ud1lo ud1hi -- ud2lo ud2hi          convert 1 digit of output
598 NUM         MOV &BASEADR,T          ;3
599 NUM1        MOV @PSP,S              ;2          -- DVDlo DVDhi              S = DVDlo
600             SUB #2,PSP              ;1          -- x x DVDhi                TOS = DVDhi
601             CALL #MUSMOD1           ;244/444    -- REMlo QUOTlo QUOThi      T is unchanged W=REMlo X=QUOTlo Y=QUOThi
602             MOV @PSP+,0(PSP)        ;4          -- QUOTlo QUOThi            W = REMlo
603 TODIGIT     CMP.B #10,W             ;2
604             JNC TODIGIT1            ;2  jump if U<
605             ADD.B #7,W              ;2
606 TODIGIT1    ADD.B #30h,W            ;2
607 HOLDW       SUB #1,&HP              ;3  store W=char --> -[HP]
608             MOV &HP,Y               ;3
609             MOV.B W,0(Y)            ;3
610             MOV @IP+,PC             ;4 22 words, about 276|476 cycles for u|ud one digit
611
612             FORTHWORD "#S"
613 ; https://forth-standard.org/standard/core/numS
614 ; #S    udlo udhi -- 0 0       convert remaining digits
615 NUMS        mDOCOL
616             .word   NUM             ;       X=QUOTlo
617             mNEXTADR                ;       next adr
618             SUB #2,IP               ;1      restore NUM return
619             BIS TOS,X               ;1
620             CMP #0,X                ;1      ud = 0 ?
621             JNZ NUM1                ;2
622 EXIT        MOV @RSP+,IP            ;2      when DTC=2 rDOCOL is loaded with this EXIT address
623             MOV @IP+,PC             ;4 10 words, about 294|494 cycles for u|ud one digit
624
625             FORTHWORD "#>"
626 ; https://forth-standard.org/standard/core/num-end
627 ; #>    udlo:udhi -- addr u    end conversion, get string
628 NUMGREATER  MOV &HP,0(PSP)          ; -- addr 0
629             MOV #HOLD_BASE,TOS      ;
630             SUB @PSP,TOS            ; -- addr u
631             MOV @IP+,PC
632
633             FORTHWORD "HOLD"
634 ; https://forth-standard.org/standard/core/HOLD
635 ; HOLD  char --        add char to output string
636 HOLD        MOV.B TOS,W             ;1
637             MOV @PSP+,TOS           ;2
638             JMP HOLDW               ;15
639
640             FORTHWORD "SIGN"
641 ; https://forth-standard.org/standard/core/SIGN
642 ; SIGN  n --           add minus sign if n<0
643 SIGN        CMP #0,TOS
644             MOV @PSP+,TOS
645             MOV.B #'-',W
646             JN HOLDW                ; jump if 0<
647             MOV @IP+,PC
648
649 BL          CALL rDOCON
650             .word   20h
651
652             FORTHWORD "U."
653 ; https://forth-standard.org/standard/core/Ud
654 ; U.    u --           display u (unsigned)
655 ; note: DDOT = UDOT + 10 (see DOUBLE.f)
656 UDOT        MOV #0,S                ; 1 -- hi=0
657             SUB #2,PSP              ; 1 convert n|u to d|ud with Y = -1|0
658             MOV TOS,0(PSP)          ; 3 -- lo lo
659             MOV S,TOS               ; 1 -- lo hi
660 DDOT        PUSHM #2,IP             ; 4             R-- IP S=sign
661             AND #-1,TOS             ; clear V, set N
662             JGE DDOTNEXT            ; if hi positive (N=0)
663             XOR #-1,0(PSP)          ;4
664             XOR #-1,TOS             ;1
665             ADD #1,0(PSP)           ;4
666             ADDC #0,TOS             ;1
667 DDOTNEXT    mASM2FORTH              ;10
668             .word   LESSNUM
669             .word   BL,HOLD         ; add a trailing space
670             .word   NUMS            ;               R-- IP sign
671             .word   RFROM,SIGN      ;               R-- IP
672             .word   NUMGREATER,TYPE
673             .word   EXIT
674
675             FORTHWORD "."
676 ; https://forth-standard.org/standard/core/d
677 ; .     n --           display n (signed)
678 DOT         CMP #0,TOS
679             JGE UDOT
680             MOV #-1,S
681             JMP UDOT+2
682
683 ;-------------------------------------------------------------------------------
684 ; INTERPRETER
685 ;-------------------------------------------------------------------------------
686
687 ; https://forth-standard.org/standard/core/WORD
688 ; WORD   char -- addr        Z=1 if len=0
689 ; parse a word delimited by char separator.
690 ; the resulting c-string is left at HERE.
691 ; if CAPS is ON, this word is CAPITALIZED unless for a 'char' input.
692 ; notice that the average lenght of all CORE definitions is about 4.
693             FORTHWORD "WORD"
694             JMP WORDD           ;2
695 ;-------------------------------;
696 BL_WORD     SUB #2,PSP          ;1              )
697             MOV TOS,0(PSP)      ;3              > 6~ instead of 16~ for CONSTANT BL runtime
698             MOV #' ',TOS        ;2 -- BL        ) 
699 WORDD       MOV &CAPS,T         ;3              CAPS OFF = 0, CAPS ON = $20.
700             MOV #SOURCE_LEN,S   ;2 --           WORDD+4 address
701             MOV @S+,X           ;2              X = src_len
702             MOV @S+,Y           ;2              Y = src_org
703             ADD Y,X             ;1              X = src_len + src_org = src_end
704             ADD @S+,Y           ;2              Y = >IN + src_org = src_ptr
705             MOV @S,W            ;2              W = HERE = dst_ptr
706 ;-------------------------------;
707 SKIPSEPLOOP CMP X,Y             ;1              src_ptr >= src_end ?
708             JC SKIPSEPEND       ;2              if yes : End Of Line !
709             CMP.B @Y+,TOS       ;2              does char = separator ?
710             JZ SKIPSEPLOOP      ;2              if yes; 7~ loop
711 ;-------------------------------;
712             SUB #1,Y            ;1              decrement the post incremented src_ptr
713 SCANTICK    CMP.B #"'",2(Y)     ;4              third char = TICK ? (allow ' as first char for a defined word)
714             JNZ SCANWRDLOOP     ;2              no
715             MOV #0,T            ;1              don't change to upper case for a 'char' input
716 ;-------------------------------;
717 SCANWRDLOOP MOV.B S,0(W)        ;3              first, S makes room in dst for word length; next, put char here.
718             CMP X,Y             ;1              src_ptr = src_end ?
719             JZ SCANWRDEND       ;2              if yes
720             MOV.B @Y+,S         ;2              S=char
721             CMP.B S,TOS         ;1 -- sep       does char = separator ?
722             JZ SCANWRDEND       ;2              if yes
723             ADD #1,W            ;1              increment dst
724             CMP.B #'a',S        ;2              char U< 'a' ?  this condition is tested at each loop
725             JNC SCANWRDLOOP     ;2              16~ upper case char loop
726             CMP.B #'z'+1,S      ;2              char U>= 'z'+1 ?
727             JC SCANWRDLOOP      ;2              U>= loopback if yes
728             SUB.B T,S           ;1              convert a...z to A...Z if CAPS ON (T=$20)
729             JMP SCANWRDLOOP     ;2              23~ lower case char loop
730 SCANWRDEND  SUB &SOURCE_ORG,Y   ;3 -- sep       Y=src_ptr - src_org = new >IN (first char separator next)
731             MOV Y,&TOIN         ;3              update >IN for next word search in this input stream
732 SKIPSEPEND  MOV &DP,TOS         ;3 -- addr      TOS = HERE
733             SUB TOS,W           ;1              W = Word_Length >= 0
734             MOV.B W,0(TOS)      ;3 -- c-addr
735             MOV @IP+,PC         ;4              Z=1 <==> Word_Length = 0 <==> EOL, tested by INTERPRET
736
737             FORTHWORD "FIND"    ;
738 ; https://forth-standard.org/standard/core/FIND
739 ; FIND     addr -- c-addr 0    if not found ; flag Z=1       c-addr at transient RAM area (HERE)
740 ;                  CFA -1      if found     ; flag Z=0
741 ;                  CFA  1      if immediate ; flag Z=0
742 ; compare WORD at c-addr (HERE)  with each of words in each of listed vocabularies in CONTEXT
743 ; start of FIND     : 5 cycles
744 ; VOCLOOP           : 5/12 cycles,
745 ; mismatch word loop: +14 cycles on len, 
746 ;                     +7  cycles on first char,
747 ;                     +10 cycles char loop,
748 ; WORDFOUND to end  : 15/16 cycles.
749 ; note: with 16 threads vocabularies, FIND takes only! 75% of CORETEST.4th processing time
750 FIND        SUB #2,PSP          ;1 -- ???? c-addr       reserve one cell, not at FINDEND which would kill the Z flag
751             MOV TOS,S           ;1                      S=c-addr
752             MOV #CONTEXT,T      ;2                      T = first cell addr of CONTEXT stack
753 VOCLOOP     MOV @T+,TOS         ;2 -- ???? VOC_PFA      T=CTXT+2
754             CMP #0,TOS          ;1                      TOS = BODY = voclink; no more vocabulary in CONTEXT ?
755             JZ FINDEND          ;2 -- ???? 0            yes ==> exit; Z=1
756     .SWITCH THREADS
757     .CASE   1                   ;                       nothing to do
758     .ELSECASE                   ;                       searching thread adds 7 cycles & 6 words
759             MOV.B 1(S),Y        ;3 -- ???? VOC_PFA0     S=c-addr Y=first char of c-addr string
760             AND.B #(THREADS-1),Y;2 -- ???? VOC_PFA0     Y=thread_x
761             ADD Y,Y             ;1 -- ???? VOC_PFA0     Y=thread_offset_x
762             ADD Y,TOS           ;1 -- ???? VOC_PFAx     TOS = words set entry
763     .ENDCASE
764             ADD #2,TOS          ;1 -- ???? VOC_PFAx+2
765 WORDLOOP    MOV -2(TOS),TOS     ;3 -- ???? NFA          -2(TOS) = [VOC_PFAx] first, then [LFA]
766             CMP #0,TOS          ;1                      no more word in the thread ?
767             JZ VOCLOOP          ;2                      yes ==> search next voc in context
768             MOV TOS,X           ;1
769             MOV.B @X+,Y         ;2                      TOS = NFA,  X= NFA+1, Y = NFA_first_byte = cnt<<2+i (i= immediate flag)
770             RRA.B Y             ;1                      remove immediate flag, the remainder is the count of the definition name.
771 LENCOMP     CMP.B @S,Y          ;2                      compare lenght
772             JNZ WORDLOOP        ;2                      14~ word loop on lenght mismatch
773             MOV S,W             ;1                      S=W=c-addr
774 CHARCOMP    CMP.B @X+,1(W)      ;4                      compare chars
775             JNZ WORDLOOP        ;2                      21~ word loop on first char mismatch
776             ADD #1,W            ;1
777             SUB.B #1,Y          ;1                      decr count
778             JNZ CHARCOMP        ;2                      10~ char loop
779 WORDFOUND   BIT #1,X            ;1
780             ADDC #0,X           ;1
781             MOV X,S             ;1                      S=aligned CFA
782             MOV.B @TOS,TOS      ;2 -- ???? NFA_1st_byte 
783             AND #1,TOS          ;1 -- ???? 0|1          test immediate flag
784             JNZ FINDEND         ;2 -- ???? 1            jump if bit 1 is set, as immediate bit
785             SUB #1,TOS          ;1 -- ???? -1
786 FINDEND     MOV S,0(PSP)        ;3 -- xt -1/0/1         if not found: -- c-addr 0    flag Z=1
787             MOV @IP+,PC         ;4 34/40 words          return to interpreter
788
789 ;             FORTHWORD "FIND"    ;
790 ; ; https://forth-standard.org/standard/core/FIND
791 ; ; FIND     addr -- c-addr 0    if not found ; flag Z=1       c-addr at transient RAM area (HERE)
792 ; ;                  CFA -1      if found     ; flag Z=0
793 ; ;                  CFA  1      if immediate ; flag Z=0
794 ; ; compare WORD at c-addr (HERE)  with each of words in each of listed vocabularies in CONTEXT
795 ; ; start of FIND     : 4/11 cycles
796 ; ; VOCLOOP           : 6 cycles,
797 ; ; mismatch word loop: +14 cycles on len, 
798 ; ;                     +7  cycles on first char,
799 ; ;                     +10 cycles char loop,
800 ; ; WORDFOUND to end  : 15/17 cycles.
801 ; ; note: with 16 threads vocabularies, FIND takes only! 75% of CORETEST.4th processing time
802 ; FIND                            ;
803 ;     .SWITCH THREADS             ;
804 ;     .CASE   1                   ;                       nothing to do
805 ;     .ELSECASE                   ;                       searching thread adds 7 cycles & 6 words
806 ;             MOV.B 1(TOS),rDOCON ;3                      S=c-addr rDOCON=first char of c-addr string
807 ;             AND.B #(THREADS-1),rDOCON;2                 rDOCON=thread_x
808 ;             ADD rDOCON,rDOCON   ;1                      rDOCON=thread_offset_x
809 ;             ADD #2,rDOCON       ;1                      rDOCON=thread_offset_x+2
810 ;     .ENDCASE
811 ;             SUB #2,PSP          ;1 -- ???? c-addr       reserve one cell, not at FINDEND which would kill the Z flag
812 ;             MOV TOS,S           ;1                      S=c-addr
813 ;             MOV #CONTEXT,T      ;2                      T = first cell addr of CONTEXT stack
814 ; VOCLOOP     MOV @T+,TOS         ;2 -- ???? VOC_PFA      T=CTXT+2
815 ;             CMP #0,TOS          ;1                      no more vocabulary in CONTEXT ?
816 ;             JZ FINDEND          ;2 -- ???? 0            yes ==> exit; Z=1
817 ;     .SWITCH THREADS
818 ;     .CASE   1                   ;                       nothing to do
819 ;             ADD #2,TOS          ;1 -- ???? VOC_PFAx+2
820 ;     .ELSECASE                   ;                       searching thread adds 7 cycles & 6 words
821 ;             ADD rDOCON,TOS      ;1 -- ???? VOC_PFAx+2   TOS = words set entry
822 ;     .ENDCASE
823 ; WORDLOOP    MOV -2(TOS),TOS     ;3 -- ???? NFA          -2(TOS) = [VOC_PFAx] first, then [LFA]
824 ;             CMP #0,TOS          ;1                      no more word in the thread ?
825 ;             JZ VOCLOOP          ;2                      yes ==> search next voc in context
826 ;             MOV TOS,X           ;1
827 ;             MOV.B @X+,Y         ;2                      TOS = NFA,  X= NFA+1, Y = NFA_first_byte = cnt<<2+i (i= immediate flag)
828 ;             RRA.B Y             ;1                      remove immediate flag, the remainder is the count of the definition name.
829 ; LENCOMP     CMP.B @S,Y          ;2                      compare lenght
830 ;             JNZ WORDLOOP        ;2                      14~ word loop on lenght mismatch
831 ;             MOV S,W             ;1                      S=W=c-addr
832 ; CHARCOMP    CMP.B @X+,1(W)      ;4                      compare chars
833 ;             JNZ WORDLOOP        ;2                      21~ word loop on first char mismatch
834 ;             ADD #1,W            ;1
835 ;             SUB.B #1,Y          ;1                      decr count
836 ;             JNZ CHARCOMP        ;2                      10~ char loop
837 ; WORDFOUND   BIT #1,X            ;1
838 ;             ADDC #0,X           ;1
839 ;             MOV X,S             ;1                      S=aligned CFA
840 ;             MOV.B @TOS,TOS      ;2 -- ???? NFA_1st_byte 
841 ;             AND #1,TOS          ;1 -- ???? 0|1          test immediate flag
842 ;             JNZ FINDEND         ;2 -- ???? 1            jump if bit 1 is set, as immediate bit
843 ;             SUB #1,TOS          ;1 -- ???? -1
844 ; FINDEND
845 ;     .CASE   1                   ;                       nothing to do
846 ;     .ELSECASE                   ;                       searching thread adds 7 cycles & 6 words
847 ;             MOV #XDOCON,rDOCON  ;2
848 ;     .ENDCASE
849 ;             MOV S,0(PSP)        ;3 -- xt -1/0/1         if not found: -- c-addr 0    flag Z=1
850 ;             MOV @IP+,PC         ;4 34/40 words          return to interpreter
851
852     .IFDEF MPY_32 ; if 32 bits hardware multiplier
853
854             FORTHWORD ">NUMBER"
855 ; >NUMBER  ud1lo ud1hi addr1 cnt1 -- ud2lo ud2hi addr2 cnt2
856 ; https://forth-standard.org/standard/core/toNUMBER
857 ; ud2 is the unsigned result of converting the characters within the string specified by c-addr1 u1 into digits,
858 ; using the number in BASE, and adding each into ud1 after multiplying ud1 by the number in BASE.
859 ; Conversion continues left-to-right until a character that is not convertible (including '.'  ','  '_')
860 ; is encountered or the string is entirely converted. c-addr2 is the location of the first unconverted character
861 ; or the first character past the end of the string if the string was entirely converted.
862 ; cnt2 is the number of unconverted characters in the string.
863 ; An ambiguous condition exists if ud2 overflows during the conversion.
864 TONUMBER    MOV &BASEADR,T      ;3                      T = base
865             MOV @PSP+,S         ;2 -- ud1lo ud1hi cnt1  S = addr1
866             MOV @PSP+,Y         ;2 -- ud1lo cnt1        Y = ud1hi
867             MOV @PSP,X          ;2 -- x cnt1            X = ud1lo
868             SUB #4,PSP          ;1 -- x x x cnt1
869 TONUMLD_OP1 MOV T,&MPY          ;3                      base = MPY = OP1 loaded out of TONUMLOOP
870 TONUMLOOP   MOV.B @S,W          ;2 -- x x x cnt         S=adr, T=base, W=char, X=udlo, Y=udhi
871 DDIGITQ     SUB.B #':',W        ;2                      all Ctrl_Chars < '0'  and all chars '0' to '9' become negative
872             JNC DDIGITQNEXT     ;2                      accept all chars U< ':'  (accept $0 up to $39)
873             SUB.B #7,W          ;2                      W = char - (':' + $07 = 'A')
874             JNC TONUMEND        ;2 -- x x x cnt         reject all Ctrl_Chars U< 'A', (with Z flag = 0)
875 DDIGITQNEXT ADD.B #0Ah,W        ;2                      restore digit value: 0 to 15 (and beyond)
876             CMP T,W             ;1                      digit-base (U>= comparaison rejects all Ctrl_Chars)
877             BIC #Z,SR           ;1                      reset Z before return to QNUMBER because else
878             JC TONUMEND         ;2                      to avoid QNUMBER conversion true with digit=base :-(
879             MOV X,&OP2L         ;3                      Load 2nd operand (ud1lo)
880             MOV Y,&OP2H         ;3                      Load 2nd operand (ud1hi)
881             MOV &RES0,X         ;3                      lo result in X (ud2lo)
882             MOV &RES1,Y         ;3                      hi result in Y (ud2hi)
883             ADD W,X             ;1                      ud2lo + digit
884             ADDC #0,Y           ;1                      ud2hi + carry
885 TONUMPLUS   ADD #1,S            ;1                      adr+1
886             SUB #1,TOS          ;1 -- x x x cnt         cnt-1
887             JNZ TONUMLOOP       ;2                      if count <>0    34~ digit loop
888 TONUMEND    MOV S,0(PSP)        ;3 -- x x addr2 cnt2
889             MOV Y,2(PSP)        ;3 -- x ud2hi addr2 cnt2
890             MOV X,4(PSP)        ;3 -- ud2lo ud2hi addr2 cnt2
891             MOV @IP+,PC         ;4 40 words
892
893 ; ?NUMBER makes the interface between INTERPRET and >NUMBER; it's a subset of INTERPRET.
894 ; convert a string to a signed number; FORTH 2012 prefixes $  %  # are recognized,
895 ; FORTH 2012 'char' numbers also, digits separator '_' also.
896 ; with DOUBLE_INPUT option, 32 bits signed numbers (with decimal point) are recognized,
897 ; with FIXPOINT_INPUT option, Q15.16 signed numbers (with comma) are recognized.
898 ; prefixes ' # % $ - are processed before calling >NUMBER
899 ; chars . , _  are processed as >NUMBER exits.
900 ;Z ?NUMBER  addr -- n|d -1  if convert ok ; flag Z=0, UF9=1 if double
901 ;Z          addr -- addr 0  if convert ko ; flag Z=1
902 QNUMBER                         ;  -- addr
903         .IFDEF DOUBLE_NUMBERS   ;                           DOUBLE_NUMBERS = DOUBLE_INPUT | FIXPOINT_INPUT
904             BIC #UF9,SR         ;2                          reset UserFlag_9 used as double number flag
905         .ENDIF                  ;
906             SUB #8,PSP          ;1 -- x x x x addr          make room for >NUMBER
907             MOV TOS,6(PSP)      ;3 -- addr x x x addr       save TOS
908             MOV #0,Y            ;1                          Y=ud1hi=0
909             MOV #0,X            ;1                          X=ud1lo=0
910             MOV &BASEADR,T      ;3                          T=BASE
911             MOV TOS,S           ;1                          S=addr
912             MOV #0,TOS          ;1                          TOS=sign of result
913             PUSHM #2,TOS        ;4 R-- sign IP              PUSH TOS,IP
914             MOV #TONUMEXIT,IP   ;2                          set TONUMEXIT as return from >NUMBER
915             MOV.B @S+,TOS       ;2 -- addr x x x cnt        TOS=count, S=addr+1
916 QNUMLDCHAR  MOV.B @S,W          ;2                          W=char
917             SUB.B #'-',W        ;2
918             JZ QNUMMINUS        ;2
919             JC TONUMLD_OP1      ;2 -- addr x x x cnt        jump if char U> '-', case of numeric chars
920 QBINARY     MOV #2,T            ;1                          preset base 2
921             ADD.B #8,W          ;1                          binary '%' prefix ?     '%' + 8 = '-'
922             JZ PREFIXNEXT       ;2                          yes
923 QDECIMAL    ADD #8,T            ;1                          preset base 10
924             ADD.B #2,W          ;1                          decimal '#' prefix ?    '#' + 2 = '%'
925             JZ PREFIXNEXT       ;2                          yes
926 QHEXA       MOV #16,T           ;2                          preset base 16
927             CMP.B #1,W          ;1                          hex '$' prefix ?        '#' + 1 = '$'
928             JZ PREFIXNEXT       ;2                          yes
929 QTICK       CMP.B #4,W          ;1                          ' prefix ?              '#' + 4 = "'"
930             JNZ QNUMNEXT        ;2 -- addr x x x cnt        no, abort because other prefixes not recognized
931             CMP #3,TOS          ;2                          count = 3 ?
932             JNZ QNUMNEXT        ;2                          no, abort
933             CMP.B @S+,1(S)      ;4 -- addr x x x 3          3rd char = 1st char ?
934             MOV.B @S,S          ;2                          does byte to word conversion
935             MOV S,4(PSP)        ;3 -- addr ud2lo x x 3      ud2lo = ASCII code of 'char'
936             JMP QNUMNEXT        ;2 -- addr ud2lo x x 3      with happy end only if 3rd char = 1st char = "'"
937 QNUMMINUS   MOV #-1,2(RSP)      ;3 R-- sign IP              set sign flag
938 PREFIXNEXT  SUB #1,TOS          ;1 -- addr x x x cnt-1      TOS=count-1
939             CMP.B @S+,0(S)      ;4                          S=adr+1; same prefix ?
940             JNZ QNUMLDCHAR      ;2                          loopback if no
941             JZ TONUMLD_OP1      ;2                          if yes, this 2nd prefix will be rejected by >NUMBER
942 ; ------------------------------;46
943 TONUMEXIT   mNEXTADR            ;  -- addr ud2lo-hi addr2 cnt2      R-- IP sign BASE    S=addr2
944             JZ QNUMNEXT         ;2                                  TOS=0 and Z=1 if conversion is ok
945             SUB #2,IP           ;1                                  redefines TONUMEXIT as >NUMBER return, if loopback applicable
946             MOV.B @S,W          ;2                                  reload rejected char
947             CMP.B #'_',W        ;2                                  rejected char by >NUMBER is a underscore ?
948             JZ TONUMPLUS        ;2                                  yes: return to >NUMBER to skip char then resume conversion, 30~ loopback
949         .IFDEF DOUBLE_NUMBERS   ;                                   DOUBLE_NUMBERS = DOUBLE_INPUT | FIXPOINT_INPUT
950             BIT #UF9,SR         ;2                                  UF9 already set ? ( if you have typed .. )
951             JNZ QNUMNEXT        ;2                                  yes, goto QNUMKO
952             BIS #UF9,SR         ;2                                  set double number flag
953         .ENDIF
954         .IFDEF DOUBLE_INPUT     ;
955             SUB.B #'.',W        ;2                                  rejected char by >NUMBER is a decimal point ?
956             JZ TONUMPLUS        ;2                                  yes, loopback to >NUMBER to skip char, 45~ loopback
957         .ENDIF                  ;
958         .IFDEF FIXPOINT_INPUT   ;
959             .IFDEF DOUBLE_INPUT
960             ADD.B #2,W          ;1                                  rejected char by >NUMBER is a comma ? (',' - '.' + 2 = 0)
961             .ELSE               ;
962             CMP.B #',',W        ;2                                  rejected char by >NUMBER is a comma ?
963             .ENDIF              ;
964             JNZ QNUMNEXT        ;2                                  no: with Z=0 ==> goto QNUMKO
965 S15Q16      MOV TOS,W           ;1 -- addr ud2lo x x x              W=cnt2
966             MOV #0,X            ;1 -- addr ud2lo x 0 x              init X = ud2lo' = 0
967 S15Q16LOOP  MOV X,2(PSP)        ;3 -- addr ud2lo ud2lo' 0 x         2(PSP) = ud2lo'
968             SUB.B #1,W          ;1                                  decrement cnt2
969             MOV W,X             ;1                                  X = cnt2-1
970             ADD S,X             ;1                                  X = end_of_string-1,-2,-3...
971             MOV.B @X,X          ;2                                  X = last char of string first (reverse conversion)
972             SUB.B #':',X        ;2
973             JNC QS15Q16DIGI     ;2                                  accept all chars U< ':'
974             SUB.B #7,X          ;2
975             JNC S15Q16EOC       ;2                                  reject all chars U< 'A'
976 QS15Q16DIGI ADD.B #10,X         ;2                                  restore digit value
977             CMP T,X             ;1                                  T=Base, is X a digit ?
978             JC S15Q16EOC        ;2 -- addr ud2lo ud2lo' ud2lo' x    if not a digit
979             MOV X,0(PSP)        ;3 -- addr ud2lo ud2lo' digit x
980             MOV T,TOS           ;1 -- addr ud2lo ud2lo' digit base  R-- IP sign
981             PUSHM #3,S          ;5                                  PUSH S,T,W: R-- IP sign addr2 base cnt2
982             CALL #MUSMOD        ;4 -- addr ud2lo ur uqlo uqhi       CALL MU/MOD
983             POPM #3,S           ;5                                  restore W,T,S: R-- IP sign
984             JMP S15Q16LOOP      ;2                                  W=cnt
985 S15Q16EOC   MOV 4(PSP),2(PSP)   ;5 -- addr ud2lo ud2hi uqlo x       ud2lo from >NUMBER becomes here ud2hi part of Q15.16
986             MOV @PSP,4(PSP)     ;4 -- addr ud2lo ud2hi x x          uqlo becomes ud2lo part of Q15.16
987             CMP.B #0,W          ;1                                  count = 0 if end of conversion ok
988         .ENDIF ; FIXPOINT_INPUT
989 ; ------------------------------;
990 QNUMNEXT    POPM #2,TOS         ;4 -- addr ud2lo-hi x sign  R: --   POPM IP,TOS  TOS = sign flag = {-1;0}
991             JZ QNUMOK           ;2 -- addr ud2lo-hi x sign          conversion OK if Z=1
992 ; ------------------------------;
993 QNUMKO      ADD #6,PSP          ;2 -- addr sign
994             AND #0,TOS          ;1 -- addr ff                       TOS=0 and Z=1 ==> conversion ko
995             MOV @IP+,PC         ;4
996 ; ------------------------------;
997         .IFDEF DOUBLE_NUMBERS   ;  -- addr ud2lo-hi x sign
998 QNUMOK      ADD #2,PSP          ;1 -- addr ud2lo-hi sign
999             MOV 2(PSP),4(PSP)   ;5 -- udlo udlo udhi sign
1000             MOV @PSP+,0(PSP)    ;4 -- udlo udhi sign                note : PSP is incremented before write back.
1001             XOR #-1,TOS         ;1 -- udlo udhi inv(sign)
1002             JNZ QDOUBLE         ;2 -- udlo udhi tf                  if jump : TOS=-1 and Z=0 ==> conversion ok
1003             XOR #-1,TOS         ;1 -- udlo udhi tf
1004 QDNEGATE    XOR #-1,2(PSP)      ;3 -- udlo udhi -1
1005             XOR #-1,0(PSP)      ;3 -- (dlo dhi)-1 tf
1006             ADD #1,2(PSP)       ;3
1007             ADDC #0,0(PSP)      ;3
1008 QDOUBLE     BIT #UF9,SR         ;2 -- dlo dhi tf                    decimal point or comma fixpoint ?
1009             JZ NIP              ;2                                  no, goto leave number
1010 QNUMEND     MOV @IP+,PC         ;4                                  TOS<>0 and Z=0 ==> conversion ok
1011         .ELSE
1012 QNUMOK      ADD #4,PSP          ;1 -- addr ud2lo sign
1013             MOV @PSP,2(PSP)     ;4 -- u u sign                      note : PSP is incremented before write back !!!
1014             XOR #-1,TOS         ;1 -- udlo udhi inv(sign)
1015             JNZ QNUMEND         ;2 -- udlo udhi tf                  if jump : TOS=-1 and Z=0 ==> conversion ok
1016             XOR #-1,TOS         ;1 -- udlo udhi sign
1017 QNEGATE     XOR #-1,2(PSP)      ;3
1018             ADD #1,2(PSP)       ;3 -- n u tf
1019 QNUMEND     ADD #2,PSP          ;1 -- n tf
1020             MOV @IP+,PC         ;4                                  TOS=-1 and Z=0 ==> conversion ok
1021         .ENDIF ; DOUBLE_NUMBERS ;
1022
1023     .ELSE ; if no hardware MPY
1024             FORTHWORD "UM*"
1025 ; T.I. UNSIGNED MULTIPLY SUBROUTINE: U1 x U2 -> Ud
1026 ; https://forth-standard.org/standard/core/UMTimes
1027 ; UM*     u1 u2 -- ud   unsigned 16x16->32 mult.
1028 UMSTAR      MOV @PSP,S          ;2 MDlo
1029 UMSTAR1     MOV #0,T            ;1 MDhi=0
1030             MOV #0,X            ;1 RES0=0
1031             MOV #0,Y            ;1 RES1=0
1032             MOV #1,W            ;1 BIT TEST REGISTER
1033 UMSTARLOOP  BIT W,TOS           ;1 TEST ACTUAL BIT MRlo
1034             JZ UMSTARNEXT       ;2 IF 0: DO NOTHING
1035             ADD S,X             ;1 IF 1: ADD MDlo TO RES0
1036             ADDC T,Y            ;1      ADDC MDhi TO RES1
1037 UMSTARNEXT  ADD S,S             ;1 (RLA LSBs) MDlo x 2
1038             ADDC T,T            ;1 (RLC MSBs) MDhi x 2
1039             ADD W,W             ;1 (RLA) NEXT BIT TO TEST
1040             JNC UMSTARLOOP      ;2 IF BIT IN CARRY: FINISHED    10~ loop
1041             MOV X,0(PSP)        ;3 low result on stack
1042             MOV Y,TOS           ;1 high result in TOS
1043             MOV @IP+,PC         ;4 17 words
1044
1045             FORTHWORD ">NUMBER"
1046 ; https://forth-standard.org/standard/core/toNUMBER
1047 ; ud2 is the unsigned result of converting the characters within the string specified by c-addr1 u1 into digits,
1048 ; using the number in BASE, and adding each into ud1 after multiplying ud1 by the number in BASE.
1049 ; Conversion continues left-to-right until a character that is not convertible, including '.', ',' or '_',
1050 ; is encountered or the string is entirely converted. c-addr2 is the location of the first unconverted character
1051 ; or the first character past the end of the string if the string was entirely converted.
1052 ; u2 is the number of unconverted characters in the string.
1053 ; An ambiguous condition exists if ud2 overflows during the conversion.
1054 ; >NUMBER  ud1lo|ud1hi addr1 count1 -- ud2lo|ud2hi addr2 count2
1055 TONUMBER    MOV &BASEADR,W         ;3                          W = base
1056             MOV @PSP,S          ;2                          S=adr
1057             MOV TOS,T           ;1                          T=count
1058 TONUMLOOP   MOV.B @S,Y          ;2 -- ud1lo ud1hi x x       S=adr, T=count, W=BASE, Y=char
1059 DDIGITQ     SUB.B #':',Y        ;2
1060             JNC DDIGITQNEXT     ;2                          accept all chars <= 9
1061             SUB.B #07,Y         ;2                          reject all chars between "9" and "A"
1062             JNC TONUMEND        ;2                          yes: for bad end
1063 DDIGITQNEXT ADD.B #10,Y         ;2                          restore number
1064             CMP W,Y             ;1 -- ud1lo ud1hi x x       digit-base
1065             BIC #Z,SR           ;1                          reset Z before jmp TONUMEND because...
1066             JC TONUMEND         ;2                          ...QNUMBER conversion will be true if Z = 1  :-(
1067 UDSTAR      PUSHM #6,IP         ;8 -- ud1lo ud1hi x x       save IP S T W X Y used by UM*   r-- IP adr count base x digit
1068             MOV 2(PSP),S        ;3 -- ud1lo ud1hi x x       S=ud1hi
1069             MOV W,TOS           ;1 -- ud1lo ud1hi x base
1070             MOV #UMSTARNEXT1,IP ;2
1071 UMSTARONE   JMP UMSTAR1         ;2                          ud1hi * base -- x ud3hi             X=ud3lo
1072 UMSTARNEXT1 mNEXTADR            ;  -- ud1lo ud1hi x ud3hi
1073             MOV X,2(RSP)        ;3                                                          r-- IP adr count base ud3lo digit
1074             MOV 4(PSP),S        ;3 -- ud1lo ud1hi x ud3hi   S=ud1lo
1075             MOV 4(RSP),TOS      ;3 -- ud1lo ud1hi x base
1076             MOV #UMSTARNEXT2,IP ;2
1077 UMSTARTWO   JMP UMSTAR1         ;2 -- ud1lo ud1hi x ud4hi   X=ud4lo
1078 UMSTARNEXT2 mNEXTADR            ;  -- ud1lo ud1hi x ud4hi
1079             ADD @RSP+,X         ;2 -- ud1lo ud1hi x ud4hi   X=ud4lo+digit=ud2lo             r-- IP adr count base ud3lo
1080             ADDC @RSP+,TOS      ;2 -- ud1lo ud1hi x ud2hi   TOS=ud4hi+ud3lo+carry=ud2hi     r-- IP adr count base
1081             MOV X,4(PSP)        ;3 -- ud2lo ud1hi x ud2hi
1082             MOV TOS,2(PSP)      ;3 -- ud2lo ud2hi x x                                       r-- IP adr count base
1083             POPM #4,IP          ;6 -- ud2lo ud2hi x x       W=base, T=count, S=adr, IP=prevIP   r--
1084 TONUMPLUS   ADD #1,S            ;1
1085             SUB #1,T            ;1
1086             JNZ TONUMLOOP       ;2 -- ud2lo ud2hi x x       S=adr+1, T=count-1, W=base     68 cycles char loop
1087 TONUMEND    MOV S,0(PSP)        ;3 -- ud2lo ud2hi adr2 count2
1088             MOV T,TOS           ;1 -- ud2lo ud2hi adr2 count2
1089             MOV @IP+,PC         ;4 48/82 words/cycles, W = BASE
1090
1091 ; ?NUMBER makes the interface between >NUMBER and INTERPRET; it's a subset of INTERPRET.
1092 ; convert a string to a signed number; FORTH 2012 prefixes ' $, %, # are recognized
1093 ; digits separator '_' also.
1094 ; with DOUBLE_INPUT switched ON, 32 bits signed numbers (with decimal point) are recognized
1095 ; with FIXPOINT_INPUT switched ON, Q15.16 signed numbers (with comma) are recognized.
1096 ; prefixes ' # % $ - are processed before calling >NUMBER
1097 ; chars . , _ are processed as >NUMBER exits
1098 ;Z ?NUMBER  addr -- n|d -1  if convert ok ; flag Z=0, UF9=1 if double
1099 ;Z          addr -- addr 0  if convert ko ; flag Z=1
1100 QNUMBER
1101         .IFDEF DOUBLE_NUMBERS   ;           DOUBLE_NUMBERS = DOUBLE_INPUT | FIXPOINT_INPUT
1102             BIC #UF9,SR         ;2          reset flag UF9, before use as double number flag
1103         .ENDIF                  ;
1104             SUB #8,PSP          ;1 -- x x x x addr
1105             MOV TOS,6(PSP)      ;3 -- addr x x x addr   save TOS
1106             MOV #0,4(PSP)       ;3                      ud1hi=0
1107             MOV #0,2(PSP)       ;3 -- addr 0 0 x addr   ud1lo=0
1108             MOV &BASEADR,W      ;3                      W=BASE
1109             MOV TOS,S           ;1 -- addr ud=0 x x     S=addr
1110             MOV #0,TOS          ;1
1111             PUSHM #2,TOS        ;4          R-- sign IP (push TOS,IP)
1112             MOV #TONUMEXIT,IP   ;2                      define >NUMBER return
1113             MOV.B @S+,T         ;2                      S=addr+1, T=count
1114 QNUMLDCHAR  MOV.B @S,Y          ;2                      Y=char
1115             SUB.B #'-',Y        ;2 -- addr ud=0 x x     sign minus ?
1116             JZ QNUMMINUS        ;2                      yes
1117             JC TONUMLOOP        ;2                      if char U> '-'
1118 QBINARY     MOV #2,W            ;1                      preset base 2
1119             ADD.B #8,Y          ;1                      binary prefix ?     '%' = '-' + 8
1120             JZ PREFIXNEXT       ;2                      yes
1121 QDECIMAL    ADD #8,W            ;1                      preset base 10
1122             ADD.B #2,Y          ;1                      decimal prefix ?    '#' = '%' + 2
1123             JZ PREFIXNEXT       ;2                      yes
1124 QHEXA       MOV #16,W           ;2                      preset base 16
1125             CMP.B #1,Y          ;1                      hex prefix ?        '$' = '#' + 1
1126             JZ PREFIXNEXT       ;2                      yes
1127 QTICK       CMP.B #4,Y          ;1                      prefix = ' ?        "'" = '#' + 4
1128             JNZ QNUMNEXT        ;2 -- addr x x x cnt    no, abort because other prefixes not recognized
1129             CMP #3,TOS          ;
1130             JNZ QNUMNEXT        ;
1131             CMP.B @S+,1(S)      ;4                      compare 3rd with first char '
1132             MOV.B @S,S          ;2                      does char to word conversion
1133             MOV S,4(PSP)        ;5 -- addr ud2lo x x 3  ud2lo = ASCII code of 'char'
1134             JMP QNUMNEXT        ;2                      with happy end if flag Z = 1
1135 QNUMMINUS   MOV #-1,2(RSP)      ;3 R-- sign IP          set sign flag
1136 PREFIXNEXT  SUB #1,T            ;1                      T=count-1
1137             CMP.B @S+,0(S)      ;4                      S=adr+1; same prefix ?
1138             JNZ QNUMLDCHAR      ;2                      no
1139             JZ TONUMLOOP        ;2                      yes, that will abort conversion
1140 ; ------------------------------;43
1141 TONUMEXIT   mNEXTADR            ;  -- addr ud2lo-hi addr2 cnt2      R-- IP sign BASE    S=addr2,T=cnt2
1142             JZ QNUMNEXT         ;2                                  if conversion is ok
1143             SUB #2,IP
1144             MOV.B @S,Y          ;                                   regenerate rejected char
1145             CMP.B #'_',Y        ;2                                  rejected char by >NUMBER is a underscore ?
1146             JZ TONUMPLUS        ;                                   yes: loopback to >NUMBER to skip char
1147         .IFDEF DOUBLE_NUMBERS   ;                                   DOUBLE_NUMBERS = DOUBLE_INPUT | FIXPOINT_INPUT
1148             BIT #UF9,SR         ;                                   UF9 already set ? (you have wrongly typed two points)
1149             JNZ QNUMNEXT        ;                                   yes, goto QNUMKO
1150             BIS #UF9,SR         ;2                                  set double number flag
1151         .ENDIF
1152         .IFDEF DOUBLE_INPUT
1153             SUB.B #'.',Y        ;1                                  rejected char by >NUMBER is a decimal point ?
1154             JZ TONUMPLUS        ;2                                  to terminate conversion
1155         .ENDIF
1156         .IFDEF FIXPOINT_INPUT   ;
1157             .IFDEF DOUBLE_INPUT
1158             ADD.B #2,Y          ;1                                  rejected char by >NUMBER is a comma ?
1159             .ELSE
1160             SUB.B #',',Y        ;1                                  rejected char by >NUMBER is a comma ?
1161             .ENDIF
1162             JNZ QNUMNEXT        ;2                                  no, goto QNUMKO
1163 S15Q16      MOV #0,X            ;1 -- addr ud2lo x 0 x              init ud2lo' = 0
1164 S15Q16LOOP  MOV X,2(PSP)        ;3 -- addr ud2lo ud2lo' ud2lo' x    X = 0(PSP) = ud2lo'
1165             SUB.B #1,T          ;1                                  decrement cnt2
1166             MOV T,X             ;1                                  X = cnt2-1
1167             ADD S,X             ;1                                  X = end_of_string-1, first...
1168             MOV.B @X,X          ;2                                  X = last char of string, first...
1169             SUB.B #':',X        ;2
1170             JNC QS15Q16DIGI     ;2                                  accept all chars U< ':'
1171             SUB.B #7,X          ;2
1172             JNC S15Q16EOC       ;2                                  reject all chars U< 'A'
1173 QS15Q16DIGI ADD.B #10,X         ;2                                  restore number
1174             CMP W,X             ;1                                  W=BASE, is X a digit ?
1175             JC  S15Q16EOC       ;2 -- addr ud2lo ud2lo' x ud2lo'    if not a digit
1176             MOV X,0(PSP)        ;3 -- addr ud2lo ud2lo' digit x
1177             MOV W,TOS           ;1 -- addr ud2lo ud2lo' digit base  R-- IP sign
1178             PUSHM #3,S          ;5                                  PUSH S,T,W: R-- IP sign addr2 cnt2 base
1179             CALL #MUSMOD        ;4 -- addr ud2lo ur uqlo uqhi
1180             POPM #3,S           ;5                                  restore W,T,S: R-- IP sign
1181             JMP S15Q16LOOP      ;2                                  W=cnt
1182 S15Q16EOC   MOV 4(PSP),2(PSP)   ;5 -- addr ud2lo ud2lo uqlo x       ud2lo from >NUMBER part1 becomes here ud2hi=S15 part2
1183             MOV @PSP,4(PSP)     ;4 -- addr ud2lo ud2hi x x          uqlo becomes ud2lo
1184             CMP.B #0,T          ;1                                  cnt2 = 0 if end of conversion ok
1185         .ENDIF ; FIXPOINT_INPUT ;
1186 ; ------------------------------;97
1187 QNUMNEXT    POPM #2,TOS         ;4 -- addr ud2lo-hi x sign  R: --   POPM IP,TOS  TOS = sign flag = {-1;0}
1188             JZ QNUMOK           ;2 -- addr ud2lo-hi x sign          conversion OK if Z=1
1189 ; ------------------------------;
1190 QNUMKO      ADD #6,PSP          ;1 -- addr sign
1191             AND #0,TOS          ;1 -- addr ff                       TOS=0 and Z=1 ==> conversion ko
1192             MOV @IP+,PC         ;4
1193 ; ------------------------------;
1194         .IFDEF DOUBLE_NUMBERS
1195 QNUMOK      ADD #2,PSP          ;1 -- addr ud2lo ud2hi sign
1196             MOV 2(PSP),4(PSP)   ;  -- udlo udlo udhi sign
1197             MOV @PSP+,0(PSP)    ;4 -- udlo udhi sign                note : PSP is incremented before write back !!!
1198             XOR #-1,TOS         ;1 -- udlo udhi inv(sign)
1199             JNZ QDOUBLE         ;2                                  if jump : TOS=-1 and Z=0 ==> conversion ok
1200             XOR #-1,TOS         ;1 -- udlo udhi tf
1201 Q2NEGATE    XOR #-1,2(PSP)      ;3
1202             XOR #-1,0(PSP)      ;3
1203             ADD #1,2(PSP)       ;3
1204             ADDC #0,0(PSP)      ;3 -- dlo dhi tf
1205 QDOUBLE     BIT #UF9,SR         ;2 -- dlo dhi tf                decimal point added ?
1206             JZ NIP              ;                                   no, goto leave number, Z=0
1207 QNUMEND     MOV @IP+,PC         ;4                              TOS=-1 and Z=0 ==> conversion ok
1208         .ELSE
1209 QNUMOK      ADD #4,PSP          ;1 -- addr ud2lo sign
1210             MOV @PSP,2(PSP)     ;4 -- udlo udlo sign            note : PSP is incremented before write back !!!
1211             XOR #-1,TOS         ;1 -- udlo udlo inv(sign)
1212             JNZ QNUMEND         ;2                              if jump : TOS=-1 and Z=0 ==> conversion ok
1213             XOR #-1,TOS         ;1 -- udlo udlo tf                   TOS=-1 and Z=0
1214 QNEGATE     XOR #-1,2(PSP)      ;3
1215             ADD #1,2(PSP)       ;3 -- n udlo tf
1216 QNUMEND     ADD #2,PSP          ;1
1217             MOV @IP+,PC         ;4                              TOS=-1 and Z=0 ==> conversion ok
1218         .ENDIF ; DOUBLE_NUMBERS
1219     .ENDIF ; of Hardware/Software MPY
1220
1221             FORTHWORDIMM "\\"       ; immediate
1222 ; https://forth-standard.org/standard/block/bs
1223 ; \         --      backslash
1224 ; everything up to the end of the current line is a comment.
1225 BACKSLASH   MOV &SOURCE_LEN,&TOIN   ;
1226             MOV @IP+,PC
1227
1228 ; ------------------------------;
1229 ; INTERPRET = BACKSLASH + 8     ;
1230 ; ------------------------------;
1231 ; INTERPRET    i*x addr u -- j*x      interpret given buffer
1232 ; This is the common factor of EVALUATE and QUIT.
1233 ; set addr u as input buffer then parse it word by word
1234 INTERPRET   mDOCOL              ;               INTERPRET = BACKSLASH + 8
1235             .word SETIB         ; --            set input buffer pointers
1236 INTLOOP     .word BL_WORD       ; -- c-addr     flag Z = 1 <=> End Of Line
1237             .word ZBRAN,FDROPEXIT;              early return if End of Line
1238             .word FIND          ;
1239             mNEXTADR            ; -- xt|c-addr|xt -1|0|+1   Z=1 --> not found
1240             MOV TOS,W           ;                           W = flag = (-1|0|+1) as (not_immediate|not_found|immediate)
1241             MOV @PSP+,TOS       ; -- xt|c-addr|xt
1242             MOV #INTQNUMNEXT,IP ;2              INTQNUMNEXT is the next of QNUMBER
1243             JZ QNUMBER          ;2              if Z=1 --> not found, search a number
1244             MOV #INTLOOP,IP     ;2              INTLOOP is the continuation of EXECUTE|COMMA
1245             XOR &STATE,W        ;3
1246             JZ COMMA            ;2 -- xt        if W xor STATE = 0 compile xt, then loop back to INTLOOP
1247 EXECUTE     PUSH TOS            ;3 -- xt
1248             MOV @PSP+,TOS       ;2 --
1249             MOV @RSP+,PC        ;4              xt --> PC, then loop back to INTLOOP
1250 ; ------------------------------;
1251 INTQNUMNEXT mNEXTADR            ;  -- n|c-addr fl   Z = 1 --> not a number, SR(UF9) double number request
1252             MOV @PSP+,TOS       ;2 -- n|c-addr
1253             MOV #INTLOOP,IP     ;2              INTLOOP is the continuation of LITERAL.
1254             JNZ LITERAL         ;2 n --         Z = 0 --> is a number, execute LITERAL then loop back to INTLOOP
1255 NOTFOUND    MOV #FABORT_TERM,IP ;2              ABORT_TERM becomes the end of INTERPRET
1256             ADD.B #1,0(TOS)     ;3 c-addr --    Z = 1 --> Not a Number : incr string count to add '?'
1257             MOV.B @TOS,Y        ;2              Y=count+1
1258             ADD TOS,Y           ;1              Y=end of string addr
1259             MOV.B #'?',0(Y)     ;5              add '?' to end of string
1260             JMP COUNT           ;2 -- addr len  return to ABORT_TERM
1261 FDROPEXIT   .word   DROPEXIT
1262
1263             FORTHWORDIMM "LITERAL"  ; immediate
1264     .IFDEF DOUBLE_NUMBERS       ; are recognized
1265 ; https://forth-standard.org/standard/core/LITERAL
1266 ; LITERAL  n --        append single numeric literal if compiling state
1267 ;          d --        append two numeric literals if compiling state and UF9<>0 (not ANS)
1268 LITERAL     CMP #0,&STATE       ;3
1269             JZ LITERALNEXT      ;2 if interpreting state, does nothing else to clear UF9 flag
1270             MOV TOS,X           ;1          X = n|dhi
1271 LITERALLOOP MOV &DP,W           ;3
1272             ADD #4,&DP          ;3
1273             MOV #LIT,0(W)       ;4
1274             MOV X,2(W)          ;3 pass 1: compile n, if pass 2: compile dhi
1275             MOV @PSP+,TOS       ;2
1276             BIT #UF9,SR         ;2 double number ?
1277 LITERALNEXT BIC #UF9,SR         ;2    in all case, clear UF9
1278             JZ LITERALEND       ;2 no  goto end if n|interpret_state
1279             MOV TOS,2(W)        ;3 yes compile dlo over dhi
1280             JMP LITERALLOOP     ;2
1281 LITERALEND  MOV @IP+,PC         ;4
1282     .ELSE
1283 ; https://forth-standard.org/standard/core/LITERAL
1284 ; LITERAL  n --        append single numeric literal if compiling state
1285 LITERAL     CMP #0,&STATE       ;3
1286             JZ LITERALEND       ;2 if interpreting state, does nothing
1287             MOV &DP,W           ;3
1288             ADD #4,&DP          ;3
1289             MOV #LIT,0(W)       ;4
1290             MOV TOS,2(W)        ;3
1291             MOV @PSP+,TOS       ;2
1292 LITERALEND  MOV @IP+,PC         ;4
1293     .ENDIF
1294
1295 ; https://forth-standard.org/standard/core/DEPTH
1296 ; DEPTH    -- +n        number of items on stack, must leave 0 if stack empty
1297 QDEPTH      MOV TOS,-2(PSP)     ; 3
1298             MOV #PSTACK,TOS     ; 2
1299             SUB PSP,TOS         ; 1 PSP-S0--> TOS
1300             RRA TOS             ; 1 TOS/2   --> TOS
1301             SUB #2,PSP          ; 1
1302 ; https://forth-standard.org/standard/core/Zeroless
1303 ; 0<     n -- flag      true if TOS negative
1304 ZEROLESS    ADD TOS,TOS         ;1 set carry if TOS negative
1305             SUBC TOS,TOS        ;1 TOS=-1 if carry was clear
1306 INVERT      XOR #-1,TOS         ;1 TOS=-1 if carry was set
1307             MOV @IP+,PC         ;4
1308
1309             FORTHWORD "COUNT"
1310 ; https://forth-standard.org/standard/core/COUNT
1311 ; COUNT   c-addr1 -- adr len   counted->adr/len
1312 COUNT       SUB #2,PSP          ;1
1313             MOV.B @TOS+,W       ;2
1314             MOV TOS,0(PSP)      ;3
1315             MOV W,TOS           ;1
1316             AND #-1,TOS         ;1       Z is set if u=0
1317             MOV @IP+,PC         ;4 12~
1318
1319 QFRAM_FULL  SUB #2,PSP          ; 2
1320             MOV TOS,0(PSP)      ; 3
1321             MOV #0,TOS          ; 1
1322             CMP #FRAM_FULL,&DP  ; 4
1323             JC INVERT           ; 2
1324             MOV @IP+,PC         ; 4 16~
1325
1326             FORTHWORD "ALLOT"
1327 ; https://forth-standard.org/standard/core/ALLOT
1328 ; ALLOT   n --         allocate n bytes
1329 ALLOT       ADD TOS,&DP
1330             MOV @PSP+,TOS
1331             MOV @IP+,PC
1332
1333 ; ----------------------------------;
1334 ; ABORT = ALLOT + $08               ;
1335 ; QUIT  = ALLOT + $0E               ;
1336 ; ----------------------------------;
1337 ;            FORTHWORD "ABORT"
1338 ; https://forth-standard.org/standard/core/ABORT
1339 ; Empty the data stack and perform the function of QUIT,
1340 ; which includes emptying the return stack, without displaying a message.
1341 ; ABORT is the common next of WARM and ABORT"
1342 ABORT       MOV #PSTACK,PSP         ; clear Parameter stack
1343             MOV #0,TOS              ; clear TOS for SYS use.
1344 ; https://forth-standard.org/standard/core/QUIT
1345 ; QUIT  --     interpret line by line the input stream
1346 QUIT        mASM2FORTH              ; QUIT is the level 0 of Return stack
1347     .IFDEF PROMPT
1348 QUIT1       .word   XSQUOTE         ;
1349             .byte   5,13,10,"ok "   ; CR+LF + Forth prompt
1350 QUIT2
1351     .ELSE
1352 QUIT2       .word   XSQUOTE         ; 16~
1353             .byte   2,13,10         ; CR+LF
1354     .ENDIF
1355             .word   TYPE            ; 79~
1356             .word   REFILL          ;       -- org len      refill the input line buffer from ACCEPT
1357 QUIT4       .word   INTERPRET       ;                       interpret it
1358 QUIT5       .word   QDEPTH          ; 15~                   stack empty test
1359             .word   XSQUOTE         ; 16~                   ABORT" stack empty"
1360             .byte   11,"stack empty";
1361             .word   QABORT          ; 14~                   see QABORT in forthMSP430FR_TERM_xxx.asm
1362             .word   QFRAM_FULL      ; 16~                   FRAM full test
1363             .word   XSQUOTE         ; 16~                   ABORT" MAIN full"
1364             .byte   9,"MAIN full"   ;
1365             .word   QABORT          ; 14~ 
1366     .IFDEF PROMPT
1367             .word   LIT,STATE,FETCH ; STATE @
1368             .word   QFBRAN,QUIT1    ; 0= case of interpretion state
1369             .word   XSQUOTE         ; 0<> case of compilation state
1370             .byte   5,13,10,"   "   ; CR+LF + 3 spaces
1371     .ENDIF
1372             .word   BRAN,QUIT2      ; 6~
1373
1374             FORTHWORDIMM "ABORT\34"
1375 ; ; ABORT" is enabled in interpretation mode (+ 11 words) :
1376 ;             PUSH IP
1377 ;             CMP #0,&STATE
1378 ;             JNZ COMP_QABORT
1379 ; EXEC_QABORT MOV #0,T              ; CAPS OFF
1380 ;             mASM2FORTH
1381 ;             .word   LIT,'"',WORDD+4,COUNT,QABORT
1382 ;             .word   DROPEXIT
1383 ;COMP_QABORT mASM2FORTH
1384 ;            .word   SQUOTE
1385 ;            .word   LIT,QABORT,COMMA    ; see QABORT in forthMSP430FR_TERM_xxx.asm
1386 ;FEXIT       .word   EXIT
1387
1388 ; https://forth-standard.org/standard/core/ABORTq
1389 ; ABORT" " (empty string) displays nothing
1390 ; ABORT"  i*x flag -- i*x   R: j*x -- j*x  flag=0
1391 ;         i*x flag --       R: j*x --      flag<>0
1392             mDOCOL
1393             .word   SQUOTE
1394             .word   LIT,QABORT,COMMA    ; see QABORT in forthMSP430FR_TERM_xxx.asm
1395 FEXIT       .word   EXIT
1396
1397             FORTHWORD "'"
1398 ; https://forth-standard.org/standard/core/Tick
1399 ; '    -- xt           find word in dictionary and leave on stack its execution address if exist else error.
1400 TICK        mDOCOL
1401             .word   BL_WORD,FIND
1402             .word   QFBRAN,FNOTFOUND;
1403             .word   EXIT
1404 FNOTFOUND   .word   NOTFOUND        ; see INTERPRET
1405
1406             FORTHWORDIMM "[']"      ; immediate word, i.e. word executed during compilation
1407 ; https://forth-standard.org/standard/core/BracketTick
1408 ; ['] <name>        --         find word & compile it as literal
1409 BRACTICK    mDOCOL
1410             .word   TICK            ; get xt of <name>
1411             .word   LIT,LIT,COMMA   ; append LIT action
1412             .word   COMMA,EXIT      ; append xt literal
1413
1414             FORTHWORDIMM "["    ; immediate
1415 ; https://forth-standard.org/standard/core/Bracket
1416 ; [        --      enter interpretative state
1417 LEFTBRACKET MOV #0,&STATE
1418             MOV @IP+,PC
1419
1420             FORTHWORD "]"
1421 ; https://forth-standard.org/standard/core/right-bracket
1422 ; ]        --      enter compiling state
1423             MOV  #-1,&STATE
1424             MOV @IP+,PC
1425
1426 ;-------------------------------------------------------------------------------
1427 ; COMPILER
1428 ;-------------------------------------------------------------------------------
1429             FORTHWORD ","
1430 ; https://forth-standard.org/standard/core/Comma
1431 ; ,    x --           append cell to dict
1432 COMMA       ADD #2,&DP          ;3
1433             MOV &DP,W           ;3
1434             MOV TOS,-2(W)       ;3
1435             MOV @PSP+,TOS       ;2
1436             MOV @IP+,PC         ;4 15~      W = DP
1437
1438             FORTHWORDIMM "POSTPONE"
1439 ; https://forth-standard.org/standard/core/POSTPONE
1440 POSTPONE    mDOCOL
1441             .word   BL_WORD,FIND
1442             .word   ZBRAN,FNOTFOUND ; BRANch to FNOTFOUND if Z = 1
1443             .word   ZEROLESS        ; immediate word ?
1444             .word   QFBRAN,POST1    ; if immediate
1445             .word   LIT,LIT,COMMA   ; else  compile LIT
1446             .word   COMMA           ;       compile xt
1447             .word   LIT,COMMA       ;       CFA of COMMA
1448 POST1       .word   COMMA,EXIT      ; then compile xt of word found if immediate else CFA of COMMA
1449
1450             FORTHWORD ":"
1451 ; https://forth-standard.org/standard/core/Colon
1452 ; : <name>     --      begin a colon definition
1453 COLON       PUSH #COLONNEXT         ;3              define COLONNEXT as HEADER return
1454 ;-----------------------------------;
1455 HEADER      BIT #1,&DP              ;3              carry set if odd
1456             ADDC #2,&DP             ;4              align and make room for LFA
1457             mDOCOL                  ;
1458             .word BL_WORD           ;               W = Count_of_chars, up to 127 for definitions
1459             mNEXTADR                ; -- HERE       HERE is the NFA of this new word
1460             MOV @RSP+,IP            ;
1461             BIS.B #1,W              ;               W=count is always odd
1462             ADD.B #1,W              ;               W=add one byte for length
1463             ADD TOS,W               ;               W=Aligned_CFA
1464             MOV &CURRENT,X          ;               X=VOC_BODY of CURRENT
1465             MOV TOS,Y               ;               Y=NFA
1466             ADD.B @TOS+,-1(TOS)     ;               shift left once NFA_1st_byte (make room for immediate flag, clear it)
1467     .SWITCH THREADS                 ;
1468     .CASE   1                       ;               nothing to do
1469     .ELSECASE                       ;               multithreading add 5~ 4words
1470             MOV.B @TOS,TOS          ; -- char       TOS=first CHAR of new word
1471             AND #(THREADS-1),TOS    ; -- offset     TOS= thread_offset in words
1472             ADD TOS,TOS             ;               TOS= thread_offset in bytes
1473             ADD TOS,X               ;               X=VOC_PFAx = thread x of VOC_PFA of CURRENT
1474     .ENDCASE                        ;
1475             MOV @PSP+,TOS           ; --
1476 HEADEREND   MOV Y,&LAST_NFA         ;               NFA --> LAST_NFA            used by QREVEAL, IMMEDIATE
1477             MOV X,&LAST_THREAD      ;               VOC_PFAx --> LAST_THREAD    used by QREVEAL
1478             MOV W,&LAST_CFA         ;               HERE=CFA --> LAST_CFA       used by DOES>, RECURSE
1479             MOV PSP,&LAST_PSP       ;               save PSP for check compiling, used by QREVEAL
1480             ADD #4,W                ;               W = BODY of created word...
1481             MOV W,&DP               ;
1482             MOV @RSP+,PC            ; RET           W is the new DP value )
1483 ;-----------------------------------;               X is LAST_THREAD      > used by compiling words: CREATE DEFER : CODE ...
1484 COLONNEXT                           ;               Y is NFA              )
1485     .SWITCH DTC                     ; Direct Threaded Code select:
1486     .CASE 1                         ; [rDOCOL] = XDOCOL
1487             MOV #DOCOL,-4(W)        ;   compile CALL R4 = rDOCOL
1488             SUB #2,&DP              ;   adjust DP
1489     .CASE 2                         ; [rDOCOL] = EXIT
1490             MOV #120Dh,-4(W)        ;   compile PUSH IP       3~
1491             MOV #DOCOL,-2(W)        ;   compile CALL R4 = rDOCOL
1492     .CASE 3                         ; [rDOCOL] = ???
1493             MOV #120Dh,-4(W)        ;   compile PUSH IP       3~
1494             MOV #400Dh,-2(W)        ;   compile MOV PC,IP     1~
1495             MOV #522Dh,0(W)         ;   compile ADD #4,IP     1~
1496             MOV #4D30h,+2(W)        ;   compile MOV @IP+,PC   4~
1497             ADD #4,&DP              ;   adjust DP
1498     .ENDCASE                        ;
1499             MOV #-1,&STATE          ; enter compiling state
1500             MOV @IP+,PC             ;
1501 ;-----------------------------------;
1502
1503 ;;Z ?REVEAL   --      if no stack mismatch, link this new word in the CURRENT vocabulary
1504 QREVEAL     CMP PSP,&LAST_PSP       ; Check SP with its saved value by , :NONAME CODE...
1505             JNZ BAD_CSP             ;
1506             JZ LINK_NFA             ;
1507 BAD_CSP     mASM2FORTH              ; if stack mismatch.
1508             .word   XSQUOTE
1509             .byte   15,"stack mismatch!"
1510 FABORT_TERM .word   ABORT_TERM
1511 LINK_NFA    MOV &LAST_NFA,Y         ;                   if no error, link this definition in its thread
1512             MOV &LAST_THREAD,X      ;
1513 REVEAL      MOV @X,-2(Y)            ; [LAST_THREAD] --> LFA         (for NONAME: LFA --> 210h unused PA reg)
1514             MOV Y,0(X)              ; LAST_NFA --> [LAST_THREAD]    (for NONAME: [LAST_THREAD] --> 212h unused PA reg)
1515             MOV @IP+,PC
1516
1517             FORTHWORDIMM ";"
1518 ; https://forth-standard.org/standard/core/Semi
1519 ; ;            --      end a colon definition
1520 SEMICOLON   CMP #0,&STATE           ; if interpret mode, semicolon becomes a comment identifier
1521             JZ BACKSLASH            ; tip: ";" is transparent to the preprocessor, so semicolon comments are kept in file.4th
1522             mDOCOL                  ; compile mode
1523             .word   LIT,EXIT,COMMA
1524             .word   QREVEAL,LEFTBRACKET,EXIT
1525
1526             FORTHWORD "IMMEDIATE"
1527 ; https://forth-standard.org/standard/core/IMMEDIATE
1528 ; IMMEDIATE        --   make last definition immediate
1529 IMMEDIATE   MOV &LAST_NFA,Y         ;3
1530             BIS.B #1,0(Y)           ;4 FIND process more easier with bit0 for IMMEDIATE flag than bit7
1531             MOV @IP+,PC
1532
1533             FORTHWORD "CREATE"
1534 ; https://forth-standard.org/standard/core/CREATE
1535 ; CREATE <name>        --          define a CONSTANT with its next address
1536 ; Execution: ( -- a-addr )          ; a-addr is the address of name's data field
1537 ;                                   ; the execution semantics of name may be extended by using DOES>
1538 CREATE      CALL #HEADER            ; --        W = DP
1539             MOV #DOCON,-4(W)        ;4          -4(W) = CFA = CALL rDOCON
1540             MOV W,-2(W)             ;3          -2(W) = PFA = W = next address
1541 CREATENEXT  JMP REVEAL              ;           to link the definition in vocabulary
1542
1543             FORTHWORD "DOES>"
1544 ; https://forth-standard.org/standard/core/DOES
1545 ; DOES>    --          set action for the latest CREATEd definition
1546 DOES        MOV &LAST_CFA,W         ;           W = CFA of CREATEd word
1547             MOV #DODOES,0(W)        ;           replace CALL rDOCON of CREATE by new CFA: CALL rDODOES
1548             MOV IP,2(W)             ;           replace PFA by the address after DOES> as execution address
1549             MOV @RSP+,IP            ;           which ends the..
1550 NEXT_ADR    MOV @IP+,PC             ;           ..of a CREATE  definition.
1551
1552             FORTHWORD ":NONAME"
1553 ; https://forth-standard.org/standard/core/ColonNONAME
1554 ; :NONAME        -- xt
1555 ; W is DP
1556 ; X is the LAST_THREAD lure value for REVEAL
1557 ; Y is the LAST_NFA lure value for REVEAL and IMMEDIATE
1558 ; ...because we don't want to modify the word set !
1559             PUSH #COLONNEXT         ; define COLONNEXT as HEADEREND RET
1560 HEADERLESS  SUB #2,PSP              ; -- TOS    common part of :NONAME and CODENNM
1561             MOV TOS,0(PSP)          ;
1562             MOV &DP,W               ;
1563             BIT #1,W                ;
1564             ADDC #0,W               ;           W = aligned CFA
1565             MOV W,TOS               ; -- xt     aligned CFA of :NONAME | CODENNM
1566             MOV #212h,X             ;           MOV Y,0(X)   writes to 212h = unused PA register address (lure for REVEAL)
1567             MOV X,Y                 ;           MOV @X,-2(Y) writes to 210h = unused PA register address (lure for REVEAL and IMMEDIATE)
1568             JMP HEADEREND           ;
1569
1570 ;; https://forth-standard.org/standard/core/DEFER
1571 ;; Skip leading space delimiters. Parse name delimited by a space.
1572 ;; Create a definition for name with the execution semantics defined below.
1573 ;;
1574 ;; name Execution:   --
1575 ;; Execute the xt that name is set to execute, i.e. NEXT (nothing),
1576 ;; until the phrase ' word IS name is executed, causing a new value of xt to be assigned to name.
1577 ;            FORTHWORD "DEFER"
1578 ;            CALL #HEADER
1579 ;            MOV #4030h,-4(W)        ;4 first CELL = MOV @PC+,PC = BR #addr
1580 ;            MOV #NEXT_ADR,-2(W)     ;3 second CELL              =   ...mNEXT : do nothing by default
1581 ;            JMP REVEAL              ; to link created word in vocabulary
1582
1583 ; used like this (high level defn.):
1584 ;   DEFER DISPLAY                       create a "do nothing" definition (2 CELLS)
1585
1586 ; or (more elegant low level defn.):
1587 ;   CODE DISPLAY                        create a "do nothing" definition (2 CELLS)
1588 ;   MOV #NEXT_ADR,PC                    NEXT_ADR is the address of NEXT code: MOV @IP+,PC
1589 ;   ENDCODE
1590
1591 ; inline command : ' U. IS DISPLAY      U. becomes the runtime of the word DISPLAY
1592 ; or in a definition : ... ['] U. IS DISPLAY ... ;
1593 ; KEY, EMIT, CR, ACCEPT are examples of DEFERred words
1594
1595 ; IS <name>        xt --
1596             FORTHWORDIMM "IS"       ; immediate
1597 IS          PUSH IP
1598             CMP #0,&STATE
1599             JNZ IS_COMPILE
1600 IS_EXEC     mASM2FORTH
1601             .word   TICK
1602             mNEXTADR
1603             MOV @RSP+,IP
1604 DEFERSTORE  MOV @PSP+,2(TOS)        ; -- CFA_DEFERed_WORD          xt --> [PFA_DEFERed_WORD]
1605             MOV @PSP+,TOS           ; --
1606             MOV @IP+,PC             ;
1607 IS_COMPILE  mASM2FORTH
1608             .word   BRACTICK        ; find the word, compile its CFA as literal
1609             .word   LIT,DEFERSTORE  ; compile DEFERSTORE
1610             .word   COMMA,EXIT
1611
1612 ;-------------------------------------------------------------------------------
1613 ; ASSEMBLER building definitions
1614 ;-------------------------------------------------------------------------------
1615            FORTHWORD "CODE"         ; a CODE word must be finished with ENDCODE
1616 ASMCODE     CALL #HEADER            ; (that sets CFA and PFA)
1617 ASMCODE1    SUB #4,&DP              ; remove default room for CFA + PFA
1618     .IFDEF VOCABULARY_SET           ; if VOCABULARY_SET
1619             JMP hidden              ; add hidden word set in CONTEXT stack
1620     .ELSE                           ;
1621 hidden      MOV &CONTEXT,&CONTEXT+2 ; add hidden word set in CONTEXT stack
1622             MOV #BODYhidden,&CONTEXT;
1623             MOV @IP+,PC             ;
1624     .ENDIF
1625
1626 ; HDNCODE (hidden CODE) is used to define a CODE word which must not to be executed by FORTH interpreter
1627 ; i.e. typically the case of an assembler definition called by CALL and ended by RET, or an interrupt routine.
1628 ; HDNCODE words are only usable in ASSEMBLER CONTEXT.
1629             FORTHWORD "HDNCODE"
1630             PUSH &CURRENT           ; save CURRENT
1631             MOV #BODYhidden,&CURRENT; select hidden word set as CURRENT to link HDNCODE definition
1632             mDOCOL
1633             .word   ASMCODE
1634             mNEXTADR
1635             MOV @RSP+,IP
1636             MOV @RSP+,&CURRENT      ; restore CURRENT
1637             MOV @IP+,PC             ;
1638
1639             FORTHWORD "CODENNM"     ; CODENoNaMe is the assembly counterpart of :NONAME
1640 CODENNM     PUSH #ASMCODE1          ; define HEADERLESS return
1641             JMP HEADERLESS          ; that makes room for CFA and PFA
1642
1643             asmword "ENDCODE"       ;
1644 ENDCODE     MOV IP,T                ; T is unused by QREVEAL
1645             mASM2FORTH              ;
1646             .word   QREVEAL
1647             mNEXTADR
1648             MOV T,IP
1649     .IFDEF VOCABULARY_SET
1650             JMP PREVIOUS            ; remove hidden word set from CONTEXT stack
1651     .ELSE                           ;
1652 PREVIOUS    MOV #BODYFORTH,&CONTEXT ; remove hidden word set from CONTEXT stack
1653             MOV #0,&CONTEXT+2       ;
1654             MOV @IP+,PC
1655     .ENDIF
1656
1657 ; here are 3 words used to switch FORTH <--> ASSEMBLER
1658
1659 ; COLON --      compile DOCOL, remove ASSEMBLER from CONTEXT stack, switch to compilation state
1660             asmword "COLON"
1661             MOV &DP,W
1662         .SWITCH DTC
1663         .CASE 1
1664             MOV #DOCOL,0(W)         ; compile CALL R4 = rDOCOL ([rDOCOL] = XDOCOL)
1665             ADD #2,&DP
1666         .CASE 2
1667             MOV #120Dh,0(W)        ; compile PUSH IP
1668 COLON1      MOV #DOCOL,2(W)        ; compile CALL R4 = rDOCOL
1669             ADD #4,&DP
1670         .CASE 3 ; inlined DOCOL
1671             MOV #120Dh,0(W)        ; compile PUSH IP
1672 COLON1      MOV #400Dh,2(W)        ; compile MOV PC,IP
1673             MOV #522Dh,4(W)         ; compile ADD #4,IP
1674             MOV #4D30h,6(W)         ; compile MOV @IP+,PC
1675             ADD #8,&DP              ;
1676         .ENDCASE ; DTC
1677 COLON2      MOV #-1,&STATE          ; enter in compile state
1678             JMP PREVIOUS            ; to restore CONTEXT
1679
1680 ; LO2HI --       same as COLON but without saving IP
1681             asmword "LO2HI"
1682         .SWITCH DTC
1683         .CASE 1                     ; compile 2 words
1684             MOV &DP,W
1685             MOV #12B0h,0(W)         ; compile CALL #EXIT, 2 words  4+6=10~
1686             MOV #EXIT,2(W)
1687             ADD #4,&DP
1688             JMP COLON2
1689         .ELSECASE                   ; CASE 2 : compile 1 word, CASE 3 : compile 3 words
1690             SUB #2,&DP              ; to skip PUSH IP
1691             MOV &DP,W
1692             JMP COLON1
1693         .ENDCASE
1694
1695 ; HI2LO --       immediate, switch to low level, set interpretation state, add ASSEMBLER to CONTEXT
1696             FORTHWORDIMM "HI2LO"    ;
1697             ADD #2,&DP              ; HERE+2
1698             MOV &DP,W               ; W = HERE+2
1699             MOV W,-2(W)             ; compile HERE+2 to HERE
1700             MOV #0,&STATE           ; LEFTBRACKET
1701             JMP hidden              ; to save CURRENT and add ASSEMBLER in context
1702
1703 ;-------------------------------------------------------------------------------
1704 ; WORDS SET for VOCABULARY, not ANS compliant,
1705 ;-------------------------------------------------------------------------------
1706     .IFDEF VOCABULARY_SET
1707
1708             FORTHWORD "WORDSET"
1709 ;X VOCABULARY       -- create a new word_set
1710 VOCABULARY  mDOCOL
1711             .word   CREATE
1712             mNEXTADR                ; W = BODY
1713         .SWITCH THREADS
1714         .CASE   1
1715             MOV #0,0(W)             ; W = BODY, init thread with 0
1716             ADD #2,W                ;
1717         .ELSECASE
1718             MOV #THREADS,X          ; count
1719 VOCABULOOP  MOV #0,0(W)             ; init threads area with 0
1720             ADD #2,W
1721             SUB #1,X
1722             JNZ VOCABULOOP
1723         .ENDCASE                    ; W = BODY + THREADS*2
1724             MOV &LASTVOC,0(W)       ; link LASTVOC
1725             MOV W,&LASTVOC
1726             ADD #2,W                ; update DP
1727             MOV W,&DP               ;
1728             mASM2FORTH              ;
1729             .word   DOES            ;
1730 ;-----------------------------------;
1731 VOCDOES     mNEXTADR                ; adds WORD-SET first in context stack
1732 ALSO        MOV #14,X               ;2 -- move up 7 words, first word in last
1733 ALSOLOOP    SUB #2,X
1734             MOV CONTEXT(X),CONTEXT+2(X) ; X=src < Y=dst copy W bytes beginning with the end
1735             JNZ ALSOLOOP
1736             MOV TOS,CONTEXT(X)      ;3  copy word-set BODY  --> first cell of CONTEXT
1737             MOV #DROPEXIT,PC
1738
1739             FORTHWORD "DEFINITIONS"
1740 ;X DEFINITIONS  --      set last context vocabulary as entry for further defining words
1741 DEFINITIONS MOV &CONTEXT,&CURRENT
1742             MOV @IP+,PC
1743
1744             FORTHWORD "ONLY"
1745 ;X ONLY     --      fill the context stack with 0 to access only the first word-set, ex.: FORTH ONLY
1746             MOV #8,T
1747             MOV #0,X
1748 ONLY_LOOP   ADD #2,X
1749             MOV #0,CONTEXT(X)
1750             SUB #1,T
1751             JNZ ONLY_LOOP
1752             MOV @IP+,PC
1753
1754             FORTHWORD "PREVIOUS"
1755 ;X  PREVIOUS   --               pop first word-set out of context stack
1756 PREVIOUS    MOV #8,Y                ;1 move down 8 words, first with CONTEXT+2 addr, last with NULL_WORD one
1757             MOV #CONTEXT+2,X        ;2 X = org = CONTEXT+2, X-2 = dst = CONTEXT
1758             CMP #0,0(X)             ;3 [org] = 0 ?
1759             JZ PREVIOUSEND          ;2 to avoid scratch of the first CONTEXT cell by human mistake
1760 PREVIOUSLOO MOV @X+,-4(X)           ;4
1761             SUB #1,Y                ;1
1762             JNZ PREVIOUSLOO         ;2 8~ loop * 8 = 64 ~
1763 PREVIOUSEND MOV @IP+,PC             ;4
1764
1765             FORTHWORD "FORTH"       ; add FORTH as first context word-set
1766             CALL rDODOES
1767             .word   VOCDOES
1768
1769     .ENDIF ; VOCABULARY_SET
1770
1771 BODYFORTH   .word   lastforthword   ; BODY of FORTH
1772     .SWITCH THREADS
1773     .CASE   2
1774             .word   lastforthword1
1775     .CASE   4
1776             .word   lastforthword1
1777             .word   lastforthword2
1778             .word   lastforthword3
1779     .CASE   8
1780             .word   lastforthword1
1781             .word   lastforthword2
1782             .word   lastforthword3
1783             .word   lastforthword4
1784             .word   lastforthword5
1785             .word   lastforthword6
1786             .word   lastforthword7
1787     .CASE   16
1788             .word   lastforthword1
1789             .word   lastforthword2
1790             .word   lastforthword3
1791             .word   lastforthword4
1792             .word   lastforthword5
1793             .word   lastforthword6
1794             .word   lastforthword7
1795             .word   lastforthword8
1796             .word   lastforthword9
1797             .word   lastforthword10
1798             .word   lastforthword11
1799             .word   lastforthword12
1800             .word   lastforthword13
1801             .word   lastforthword14
1802             .word   lastforthword15
1803     .CASE   32
1804             .word   lastforthword1
1805             .word   lastforthword2
1806             .word   lastforthword3
1807             .word   lastforthword4
1808             .word   lastforthword5
1809             .word   lastforthword6
1810             .word   lastforthword7
1811             .word   lastforthword8
1812             .word   lastforthword9
1813             .word   lastforthword10
1814             .word   lastforthword11
1815             .word   lastforthword12
1816             .word   lastforthword13
1817             .word   lastforthword14
1818             .word   lastforthword15
1819             .word   lastforthword16
1820             .word   lastforthword17
1821             .word   lastforthword18
1822             .word   lastforthword19
1823             .word   lastforthword20
1824             .word   lastforthword21
1825             .word   lastforthword22
1826             .word   lastforthword23
1827             .word   lastforthword24
1828             .word   lastforthword25
1829             .word   lastforthword26
1830             .word   lastforthword27
1831             .word   lastforthword28
1832             .word   lastforthword29
1833             .word   lastforthword30
1834             .word   lastforthword31
1835     .ELSECASE
1836     .ENDCASE
1837             .word   voclink
1838 voclink     .set    $-2
1839
1840     .IFDEF VOCABULARY_SET
1841             FORTHWORD "hidden"  ; cannot be found by FORTH interpreter because the string is not capitalized
1842 hidden      CALL rDODOES
1843             .word   VOCDOES
1844     .ENDIF
1845 BODYhidden  .word   lastasmword ; BODY of hidden words
1846     .SWITCH THREADS
1847     .CASE   2
1848             .word   lastasmword1
1849     .CASE   4
1850             .word   lastasmword1
1851             .word   lastasmword2
1852             .word   lastasmword3
1853     .CASE   8
1854             .word   lastasmword1
1855             .word   lastasmword2
1856             .word   lastasmword3
1857             .word   lastasmword4
1858             .word   lastasmword5
1859             .word   lastasmword6
1860             .word   lastasmword7
1861     .CASE   16
1862             .word   lastasmword1
1863             .word   lastasmword2
1864             .word   lastasmword3
1865             .word   lastasmword4
1866             .word   lastasmword5
1867             .word   lastasmword6
1868             .word   lastasmword7
1869             .word   lastasmword8
1870             .word   lastasmword9
1871             .word   lastasmword10
1872             .word   lastasmword11
1873             .word   lastasmword12
1874             .word   lastasmword13
1875             .word   lastasmword14
1876             .word   lastasmword15
1877     .CASE   32
1878             .word   lastasmword1
1879             .word   lastasmword2
1880             .word   lastasmword3
1881             .word   lastasmword4
1882             .word   lastasmword5
1883             .word   lastasmword6
1884             .word   lastasmword7
1885             .word   lastasmword8
1886             .word   lastasmword9
1887             .word   lastasmword10
1888             .word   lastasmword11
1889             .word   lastasmword12
1890             .word   lastasmword13
1891             .word   lastasmword14
1892             .word   lastasmword15
1893             .word   lastasmword16
1894             .word   lastasmword17
1895             .word   lastasmword18
1896             .word   lastasmword19
1897             .word   lastasmword20
1898             .word   lastasmword21
1899             .word   lastasmword22
1900             .word   lastasmword23
1901             .word   lastasmword24
1902             .word   lastasmword25
1903             .word   lastasmword26
1904             .word   lastasmword27
1905             .word   lastasmword28
1906             .word   lastasmword29
1907             .word   lastasmword30
1908             .word   lastasmword31
1909     .ELSECASE
1910     .ENDCASE
1911             .word   voclink
1912 voclink     .set    $-2
1913
1914 ;-------------------------------------------------------------------------------
1915 ; FASTFORTH environment management: RST_SET RST_RET MARKER
1916 ;-------------------------------------------------------------------------------
1917 ENV_COPY                            ; mini MOVE T words from X to W
1918     .IFDEF VOCABULARY_SET
1919             MOV #12,T               ; words count for extended environment: DP,LASTVOC,CURRENT,CONTEXT(8),NULL_WORD
1920     .ELSE
1921             MOV #4,T                ; words count for basic environment: DP,LASTVOC,CURRENT,CONTEXT
1922     .ENDIF
1923 MOV_WORDS   MOV @X+,0(W)            ; 4 X = src, W = dst, T = words count
1924             ADD #2,W                ; 1
1925             SUB #1,T                ; 1 words count -1
1926             JNZ MOV_WORDS           ; 2
1927             MOV @RSP+,PC
1928
1929             FORTHWORD "RST_SET"     ; define actual environment as new RESET environment
1930 RST_SET     MOV #DP,X               ; org = RAM value (DP first)
1931             MOV #RST_DP,W           ; dst = FRAM value (RST_DP first), see \inc\ThingsInFirst.inc
1932             CALL #ENV_COPY          ; copy environment RAM --> FRAM RST, use T,W,X
1933             MOV @IP+,PC
1934
1935             FORTHWORD "RST_RET"     ; init / return_to_previous RESET or MARKER environment
1936 RST_RET     MOV #RST_DP,X           ; org = FRAM value (first RST_DP), see \inc\ThingsInFirst.inc
1937             MOV #DP,W               ; dst = RAM value (first DP)
1938             MOV @X,S                ; S = restored DP, used below for comparaison with NFAs below
1939             CALL #ENV_COPY          ; copy environment FRAM RST --> RAM, use T,W,X
1940             MOV &LASTVOC,W          ; W = init/restored LASTVOC in RAM
1941     .SWITCH THREADS                 ; init/restore THREAD(s) with NFAs value < DP value, for all word set
1942     .CASE   1 ; mono thread word-set
1943 MARKALLVOC  MOV W,Y                 ; W=VLK   Y = VLK
1944 MRKWORDLOOP MOV -2(Y),Y             ; W=VLK   Y = [THD] then [LFA] = NFA
1945             CMP Y,S                 ; Y=NFA   S=DP        CMP = S-Y : OLD_DP-NFA
1946             JNC MRKWORDLOOP         ; loop back if S<Y : OLD_DP<NFA
1947             MOV Y,-2(W)             ; W=VLK   X=THD   Y=NFA   refresh thread with good NFA
1948     .ELSECASE ; multi threads word-set
1949 MARKALLVOC  MOV #THREADS,T          ; S=DP     T=ThdCnt (Threads Count), VLK = THD_n+1
1950             MOV W,X                 ; W = VLK   X = VLK then THD_n (VOCLINK first, then THREADn)
1951 MRKTHRDLOOP MOV X,Y                 ;
1952             SUB #2,X                ;
1953 MRKWORDLOOP MOV -2(Y),Y             ; Y = NFA = [THD_n] then [LFA]
1954             CMP Y,S                 ; Y = NFA   S=DP       CMP = S-Y : DP-NFA
1955             JNC MRKWORDLOOP         ;           loop back if S<Y : DP<NFA (if not_carry = if borrow)
1956 MARKTHREAD  MOV Y,0(X)              ; Y=NFA     X=THD_n   refresh thread with good NFA
1957             SUB #1,T                ; T=ThdCnt-1
1958             JNZ MRKTHRDLOOP         ;           loopback to process NFA of next thread (thread-1)
1959     .ENDCASE ; of THREADS           ;
1960             MOV @W,W                ; W=[VLK] = VLK-1
1961             CMP #0,W                ;                   end of vocs ?
1962             JNZ MARKALLVOC          ; W=VLK-1           no : loopback
1963             MOV @IP+,PC             ;
1964
1965 ; https://forth-standard.org/standard/core/MARKER
1966 ; MARKER
1967 ;name Execution: ( -- )
1968 ;Restore all dictionary allocation and search order pointers to the state they had just prior to the
1969 ;definition of name. Remove the definition of name and all subsequent definitions. Restoration
1970 ;of any structures still existing that could refer to deleted definitions or deallocated data space is
1971 ;not necessarily provided. No other contextual information such as numeric base is affected.
1972 ; the FORTH environment is it automaticaly restored.
1973 ; FastForth provides all that is necessary for a real time application,
1974 ; by adding a call to a custom asm subroutine to restore all user environment.
1975
1976 MARKER_DOES                         ; execution part of MARKER definition
1977             mNEXTADR                ; -- BODY
1978     .IFDEF VOCABULARY_SET
1979             MOV TOS,X               ;                       X = org (first : BODY = MARKER_DP)
1980             MOV #RST_DP,W           ;                       W = dst (first : RST_DP), see \inc\ThingsInFirst.inc
1981             CALL #ENV_COPY          ;                       restore previous FORTH environment from FRAM MARKER to FRAM RST
1982             MOV X,TOS               ; -- USER_DOES          RET_ADR by default
1983     .ELSE
1984             MOV @TOS+,&RST_DP       ; -- USER_DOES          only RST_DP is restored
1985     .ENDIF
1986             CALL @TOS+              ; -- USER_PARAM         executes defined USER_DOES subroutine (RET_ADR by default),
1987                                     ;                       IP is free, TOS is the address of first USER parameter 
1988             MOV @PSP+,TOS           ; --
1989             MOV @RSP+,IP            ;
1990             JMP RST_RET             ;                       which restores previous FORTH environment in RAM
1991
1992             FORTHWORD "MARKER"      ; definition part
1993 ;( "<spaces>name" -- )
1994 ;Skip leading space delimiters. Parse name delimited by a space. Create a definition for name
1995 ;with the execution semantics defined above.
1996 ;-------------------------------------------------------------------------------
1997 ; before that, if already defined, "name" executes its MARKER_DOES part.
1998 ; i.e. does: [DEFINED] <name> [IF] <name> [THEN]
1999 ;            MARKER <name>
2000 ;-------------------------------------------------------------------------------
2001             PUSH &TOIN              ; --                save >IN
2002             mDOCOL
2003             .word BL_WORD,FIND      ; -- addr flag
2004             .word QFBRAN,MARKER_NEXT; -- addr           if not found
2005             .word DUP,EXECUTE       ; -- MARKER_DOES    execute it
2006 MARKER_NEXT mNEXTADR                ; -- addr|MARKER_DOES
2007             MOV @PSP+,TOS           ; --
2008             MOV @RSP+,IP            ;
2009             MOV @RSP+,&TOIN         ;                   restore >IN for HEADER
2010 ;-------------------------------------------------------------------------------
2011             CALL #HEADER            ;4                  W = BODY, Y = NFA,
2012             MOV #1285h,-4(W)        ;4                  CFA = CALL rDODOES
2013             MOV #MARKER_DOES,-2(W)  ;4                  PFA = MARKER_DOES
2014             SUB #2,Y                ;1                  Y = NFA-2 = LFA = DP to be restored, W = FRAM MARKER_DDP
2015     .IFDEF VOCABULARY_SET
2016             MOV Y,&DP               ;                   Y = previous DP (just before MARKER definition)
2017             MOV #DP,X               ;                   X = org = RAM DP, W = dst = MARKER_BODY
2018             CALL #ENV_COPY          ;                   copy environment RAM --> FRAM MARKER
2019             MOV #RET_ADR,0(W)       ;4                  USER_DOES default subroutine = RET_ADR
2020             ADD #2,W                ;1
2021             MOV W,&DP               ;4                  set new RAM DP (after the end of MARKER definition)
2022     .ELSE
2023             MOV Y,0(W)              ;                   DP to be restored
2024             MOV #RET_ADR,2(W)       ;                   USER_DOES default subroutine = RET_ADR
2025             ADD #4,&DP              ;
2026     .ENDIF
2027             JMP LINK_NFA            ;                   then NEXT
2028
2029 ;-------------------------------------------------------------------------------
2030 ; PUC 7 : SELECT RST_RET|DEEP_RESET <== INIT_FORTH <== (PUC,SYS,QABORT)
2031 ;-------------------------------------------------------------------------------
2032 SEL_RST     CMP #0,TOS              ;
2033             JGE RST_RET             ; RST_RET if TOS >= 0
2034 ;-----------------------------------;
2035 ; DEEP RESET                        ; DEEP_RESET if TOS < 0
2036 ;-----------------------------------;
2037 ; DEEP INIT SIGNATURES AREA         ;
2038 ;-----------------------------------;
2039             MOV #16,X               ; max known SIGNATURES length = 12 bytes
2040 SIGNATLOOP  SUB #2,X                ;
2041             MOV #-1,SIGNATURES(X)   ; reset signatures; WARNING ! DON'T CHANGE IMMEDIATE VALUE !
2042             JNZ SIGNATLOOP          ;
2043 ;-----------------------------------;
2044 ; DEEP INIT VECTORS INT             ; X = 0 ;-)
2045 ;-----------------------------------;
2046             MOV #RESET,-2(X)        ; write RESET at addr X-2 = FFFEh
2047 INIVECLOOP  SUB #2,X                ;
2048             MOV #COLD,-2(X)         ; -2(X) = FFFCh first
2049             CMP #0FFACh+2,X         ; init 41 vectors, FFFCh down to 0FFACh
2050             JNZ INIVECLOOP          ; all vectors are initialised to execute COLD routine
2051 ;-----------------------------------;
2052 ; DEEP INIT Terminal Int vector     ;
2053 ;-----------------------------------;
2054             MOV #DEEP_ORG,X         ; DEEP_ORG values are in FRAM INFO, see \inc\ThingsInFirst.inc
2055             MOV @X+,&TERM_VEC       ; TERMINAL_INT           as default vector       --> FRAM TERM_VEC
2056 ;-----------------------------------;
2057 ; DEEP INIT FRAM RST values         ; [COLD,SOFT,HARD,BACKGRND]_APP + RST_[DP,LASTVOC,CURRENT,CONTEXT]
2058 ;-----------------------------------;
2059             MOV #RST_LEN/2,T        ; T = words count
2060             MOV #RST_ORG,W          ; W = dst, X = org
2061             CALL #MOV_WORDS         ;
2062             MOV #0,&RST_CONTEXT+2   ; to do FORTH ONLY
2063 ;-----------------------------------;
2064     .IFDEF BOOTLOADER               ; does NOBOOT:
2065             MOV #WARM,&PUCNEXT      ; removes XBOOT from PUC chain.
2066     .ENDIF
2067 ;-----------------------------------;
2068 ; WARM INIT threads of all word set ;
2069 ;-----------------------------------;
2070             JMP RST_RET             ; then go to DUP|PUCNEXT,  resp. in QABORT|RESET
2071 ;-----------------------------------;
2072
2073 ;===============================================================================
2074 ; ASSEMBLER KERNEL OPTION
2075 ;===============================================================================
2076     .IFDEF LARGE_DATA
2077         .include "forthMSP430FR_EXTD_ASM.asm"
2078     .ELSE
2079         .include "forthMSP430FR_ASM.asm"
2080     .ENDIF
2081
2082     .IFDEF SD_CARD_LOADER
2083 ;===============================================================================
2084 ; SD CARD KERNEL OPTIONS
2085 ;===============================================================================
2086         .include "forthMSP430FR_SD_LowLvl.asm"  ; SD primitives
2087         .include "forthMSP430FR_SD_INIT.asm"    ; return to INIT_TERM; without use of IP,TOS
2088         .include "forthMSP430FR_SD_LOAD.asm"    ; SD LOAD driver
2089         .IFDEF SD_CARD_READ_WRITE
2090             .include "forthMSP430FR_SD_RW.asm"  ; SD Read/Write driver
2091         .ENDIF
2092     .ENDIF
2093
2094 ;===============================================================================
2095 ; ADDONS OPTIONS; if included here they will be protected against Deep_RST
2096 ;===============================================================================
2097     .IFDEF CORE_COMPLEMENT
2098 ;-------------------------------------------------------------------------------
2099 ; COMPLEMENT of definitions to pass ANS94 CORETEST
2100 ;-------------------------------------------------------------------------------
2101         .include "ADDON/CORE_ANS.asm"
2102     .ENDIF
2103
2104     .IFDEF UTILITY
2105 ;-------------------------------------------------------------------------------
2106 ; UTILITY WORDS
2107 ;-------------------------------------------------------------------------------
2108         .include "ADDON/UTILITY.asm"
2109     .ENDIF
2110
2111     .IFDEF FIXPOINT
2112 ;-------------------------------------------------------------------------------
2113 ; FIXED POINT OPERATORS
2114 ;-------------------------------------------------------------------------------
2115         .include "ADDON/FIXPOINT.asm"
2116     .ENDIF
2117
2118     .IFDEF DOUBLE
2119 ;-------------------------------------------------------------------------------
2120 ; DOUBLE word set
2121 ;-------------------------------------------------------------------------------
2122         .include "ADDON/DOUBLE.asm"
2123     .ENDIF
2124
2125     .IFDEF SD_CARD_LOADER
2126         .IFDEF SD_TOOLS
2127 ;-------------------------------------------------------------------------------
2128 ; BASIC SD TOOLS
2129 ;-------------------------------------------------------------------------------
2130             .include "ADDON/SD_TOOLS.asm"
2131         .ENDIF
2132     .ENDIF
2133
2134 ;-------------------------------------------------------------------------------
2135 ; ADD HERE YOUR CODE TO BE INTEGRATED IN KERNEL and protected against Deep_RST
2136 ;vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
2137 ;           .include "YOUR_CODE.asm"
2138 ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2139 ; ADD HERE YOUR CODE TO BE INTEGRATED IN KERNEL (protected against Deep_RST)
2140 ;-------------------------------------------------------------------------------
2141
2142 ;-------------------------------------------------------------------------------
2143 ; RESOLVE ASSEMBLY pointers, init interrupt Vectors
2144 ;-------------------------------------------------------------------------------
2145     .include "ThingsInLast.inc"