1 ; -*- coding: utf-8 -*-
2 ; http://patorjk.com/software/taag/#p=display&f=Banner&t=Fast Forth
4 ; Fast Forth For Texas Instrument MSP430FRxxxx FRAM devices
5 ; Copyright (C) <2018> <J.M. THOORENS>
7 ; This program is free software: you can redistribute it and/or modify
8 ; it under the terms of the GNU General Public License as published by
9 ; the Free Software Foundation, either version 3 of the License, or
10 ; (at your option) any later version.
12 ; This program is distributed in the hope that it will be useful,
13 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ; GNU General Public License for more details.
17 ; You should have received a copy of the GNU General Public License
18 ; along with this program. If not, see <http://www.gnu.org/licenses/>.
20 ; ----------------------------------------------------------------------
21 ; compiled with MACROASSEMBLER AS (http://john.ccac.rwth-aachen.de:8000/as/)
22 ; ----------------------------------------------------------------------
24 ;-------------------------------------------------------------------------------
25 ; Vingt fois sur le métier remettez votre ouvrage,
26 ; Polissez-le sans cesse, et le repolissez,
27 ; Ajoutez quelquefois, et souvent effacez.
28 ; Boileau, L'Art poétique
29 ;-------------------------------------------------------------------------------
31 ;===============================================================================
32 ;===============================================================================
33 ; before assembling or programming you must set TARGET in param1 (SHIFT+F8)
34 ; according to the selected TARGET below
35 ;===============================================================================
36 ;===============================================================================
38 VER .equ "V300" ; FORTH version
40 macexp off ; uncomment to hide macro results in forthMSP430FR.lst
42 ;-------------------------------------------------------------------------------
43 ; TARGETS kernel ; sizes are for 8MHz, DTC=1, THREADS=1, 3WIRES (XON/XOFF)
44 ;-------------------------------------------------------------------------------
46 ;MSP_EXP430FR5739 ; compile for MSP-EXP430FR5739 launchpad ; 24 + 2 + 3840 bytes
47 ;MSP_EXP430FR5969 ; compile for MSP-EXP430FR5969 launchpad ; 24 + 2 + 3816 bytes
48 ;MSP_EXP430FR5994 ; compile for MSP-EXP430FR5994 launchpad ; 24 + 2 + 3842 bytes
49 ;MSP_EXP430FR6989 ; compile for MSP-EXP430FR6989 launchpad ; 24 + 2 + 3852 bytes
50 ;MSP_EXP430FR4133 ; compile for MSP-EXP430FR4133 launchpad ; 24 + 2 + 3906 bytes
51 ;MSP_EXP430FR2355 ; compile for MSP-EXP430FR2355 launchpad ; 24 + 2 + 3818 bytes
52 ;MSP_EXP430FR2433 ; compile for MSP-EXP430FR2433 launchpad ; 24 + 2 + 3804 bytes
53 CHIPSTICK_FR2433 ;; compile for the "CHIPSTICK" of M. Ken BOAK ; 24 + 2 + 3804 bytes
55 ; choose DTC (Direct Threaded Code) model, if you don't know, choose 1
56 DTC .equ 1 ; DTC model 1 : DOCOL = CALL rDOCOL 14 cycles 1 word shortest DTC model
57 ; DTC model 2 : DOCOL = PUSH IP, CALL rEXIT 13 cycles 2 words good compromize for mix FORTH/ASM code
58 ; DTC model 3 : inlined DOCOL 9 cycles 4 words fastest
60 THREADS .equ 16 ; 1, 2 , 4 , 8 , 16, 32 search entries in dictionnary.
61 ; +0, +42, +54, +70, +104, +168 bytes, usefull to speed up compilation;
64 FREQUENCY .equ 16 ; fully tested at 1,2,4,8,16 MHz (+ 24 MHz for MSP430FR57xx,MSP430FR2355)
66 ;-------------------------------------------------------------------------------
67 ; KERNEL OPTIONS that can't be added later
68 ;-------------------------------------------------------------------------------
69 CONDCOMP ;; + 368 bytes : adds conditionnal compilation : COMPARE [DEFINED] [UNDEFINED] [IF] [ELSE] [THEN] MARKER
70 MSP430ASSEMBLER ;; + 1828 bytes : adds embedded assembler with TI syntax; without, you can do all but all much more slowly...
71 ;EXTENDED_ASM ; + 1896 bytes : adds extended assembler for programming or data access beyond $FFFF.
72 NONAME ;; + 54 bytes : adds :NONAME CODENNM (CODENoNaMe)
73 VOCABULARY_SET ;; + 104 bytes : adds words: VOCABULARY FORTH ASSEMBLER ALSO PREVIOUS ONLY DEFINITIONS (FORTH83)
74 DOUBLE_INPUT ;; + 74 bytes : adds the interpretation input for double numbers (dot numbers)
75 FIXPOINT_INPUT ;; + 120 bytes : adds the interpretation input for Q15.16 numbers, mandatory for FIXPOINT ADD-ON
76 ;SD_CARD_LOADER ; + 1748 bytes : to LOAD source files from SD_card
77 ;SD_CARD_READ_WRITE ; + 1192 bytes : to read, create, write and del files + copy text files from PC to SD_Card
78 ;BOOTLOADER ; + 72 bytes : includes to <reset> SD_CARD\BOOT.4TH as bootloader. To do: ' BOOT IS QUIT
79 ;PROMPT ; + 22 bytes : to display prompt "ok "
81 ;-------------------------------------------------------------------------------
82 ; OPTIONAL ADDITIONS that can be added later by downloading their source file >-----------------------+
83 ; when added in kernel, they are protected against WIPE and Deep Reset... |
84 ;------------------------------------------------------------------------------- v
85 ;FIXPOINT ; + 422/528 bytes add HOLDS F+ F- F/ F* F#S F. S>F 2@ 2CONSTANT FIXPOINT.f
86 ;UTILITY ; + 434/524 bytes (1/16threads) : add .S .RS WORDS U.R DUMP ? UTILITY.f
87 ;SD_TOOLS ; + 142 bytes for trivial DIR, FAT, CLUSTER and SECTOR view, adds UTILITY SD_TOOLS.f
88 ;ANS_CORE_COMPLEMENT ; + 924 bytes : required to pass coretest.4th ANS_COMP.f
90 ;-------------------------------------------------------------------------------
91 ; FAST FORTH TERMINAL configuration
92 ;-------------------------------------------------------------------------------
93 ;HALFDUPLEX ; to use FAST FORTH with half duplex terminal
94 TERMINALBAUDRATE .equ 115200 ; choose value considering the frequency and the UART2USB bridge, see explanations below.
95 TERMINAL3WIRES ;; enable 3 wires (GND,TX,RX) with XON/XOFF software flow control (PL2303TA/HXD, CP2102)
96 TERMINAL4WIRES ;; + 12 bytes enable 4 wires with hardware flow control on RX with RTS (PL2303TA/HXD, FT232RL)
97 ; this RTS pin may be permanently wired on SBWTCK/TEST pin without disturbing SBW 2 wires programming
98 ;TERMINAL5WIRES ; + 6 bytes enable 5 wires with hardware flow control on RX/TX with RTS/CTS (PL2303TA/HXD, FT232RL)...
100 ;===============================================================================
101 ; Software control flow XON/XOFF configuration:
102 ;===============================================================================
103 ; Launchpad --- UARTtoUSB device
108 ; TERATERM config terminal : NewLine receive : AUTO,
109 ; NewLine transmit : CR+LF
110 ; Size : 128 chars x 49 lines (adjust lines to your display)
112 ; TERATERM config serial port : TERMINALBAUDRATE value,
113 ; 8 bits, no parity, 1 Stop bit,
114 ; XON/XOFF flow control,
115 ; delay = 0ms/line, 0ms/char
117 ; don't forget : save new TERATERM configuration !
119 ; --------------------------------------------------------------------------------------------
120 ; Only two usb2uart bridges correctly handle XON / XOFF: cp2102 and pl2303.
121 ; --------------------------------------------------------------------------------------------
122 ; the best and cheapest: UARTtoUSB cable with Prolific PL2303HXD (or PL2303TA)
123 ; works well in 3 WIRES (XON/XOFF) and 4WIRES (GND,RX,TX,RTS) config
124 ; --------------------------------------------------------------------------------------------
125 ; PL2303TA 4 wires CABLE PL2303HXD 6 wires CABLE
126 ; pads upside: 3V3,txd,rxd,gnd,5V pads upside: gnd, 3V3,txd,rxd,5V
127 ; downside: cts,dcd,dsr,rts,dtr downside: rts,cts
128 ; --------------------------------------------------------------------------------------------
129 ; WARNING ! if you use PL2303TA/HXD cable as supply, open the box before to weld red wire on 3v3 pad !
130 ; --------------------------------------------------------------------------------------------
131 ; 9600,19200,38400,57600 (250kHz)
132 ; + 115200,134400 (500kHz)
133 ; + 201600,230400,268800 (1MHz)
134 ; + 403200,460800,614400 (2MHz)
135 ; + 806400,921600,1228800 (4MHz)
136 ; + 2457600 (8MHz,PL2303TA)
137 ; + 1843200,2457600 (8MHz,PL2303HXD)
138 ; + 3MBds (16MHz,PL2303TA)
139 ; + 3MBds,4MBds,5MBds (16MHz,PL2303HXD)
140 ; + 6MBds (MSP430FR57xx,MSP430FR2355 families,24MHz)
142 ; UARTtoUSB module with Silabs CP2102 (supply current = 20 mA)
143 ; ---------------------------------------------------------------------------------------------------
144 ; WARNING ! if you use it as supply, buy a CP2102 module with a VCC switch 5V/3V3 and swith on 3V3 !
145 ; ---------------------------------------------------------------------------------------------------
146 ; 9600,19200,38400 (250kHz)
148 ; + 115200,134400,230400 (1MHz)
150 ; + 921600 (4MHz,8MHz,16MHz,24MHz)
152 ;===============================================================================
153 ; Hardware control flow configuration: RTS is wired on UART2USB CTS pin
154 ;===============================================================================
156 ; Launchpad <-> UARTtoUSB
159 ; RTS --> CTS (see launchpad.asm for RTS selected pin)
162 ; TERATERM config terminal : NewLine receive : AUTO,
163 ; NewLine transmit : CR+LF
164 ; Size : 128 chars x 49 lines (adjust lines to your display)
166 ; TERATERM config serial port : TERMINALBAUDRATE value,
167 ; 8bits, no parity, 1Stopbit,
168 ; Hardware flow control,
169 ; delay = 0ms/line, 0ms/char
171 ; don't forget : save new TERATERM configuration !
173 ; notice that the control flow seems not necessary for TX (CTS <-- RTS)
175 ; UARTtoUSB module with PL2303TA/HXD
176 ; --------------------------------------------------------------------------------------------
177 ; WARNING ! if you use PL2303TA/HXD cable as supply, open the box before to weld red wire on 3v3 pad !
178 ; --------------------------------------------------------------------------------------------
179 ; 9600,19200,38400,57600 (250kHz)
180 ; + 115200,134400 (500kHz)
181 ; + 201600,230400,268800 (1MHz)
182 ; + 403200,460800,614400 (2MHz)
183 ; + 806400,921600,1228800 (4MHz)
184 ; + 2457600,3000000 (8MHz)
185 ; + 4000000,5000000 (16MHz)
188 ; UARTtoUSB module with FTDI FT232RL (FT230X don't work correctly)
189 ; ------------------------------------------------------------------------------
190 ; WARNING ! buy a FT232RL module with a switch 5V/3V3 and select 3V3 !
191 ; ------------------------------------------------------------------------------
192 ; 9600,19200,38400,57600,115200 (500kHz)
195 ; + 921600 (4,8,16 MHz)
197 ; ------------------------------------------------------------------------------
198 ; UARTtoBluetooth 2.0 module (RN42 sparkfun bluesmirf) at 921600bds
199 ; ------------------------------------------------------------------------------
200 ; 9600,19200,38400,57600,115200 (500kHz)
203 ; + 921600 (4,8,16 MHz)
205 ; RN42 config : connect RN41/RN42 module on teraterm, via USBtoUART bridge,
206 ; ----------- 8n1, 115200 bds, no flow control, echo on
207 ; $$$ // enter control mode, response: AOK
208 ; SU,92 // set 921600 bds, response: AOK
209 ; R,1 // reset module to take effect
211 ; connect RN42 module on FastForth target
212 ; add new bluetooth device on windows, password=1234
213 ; open the created output COMx port with TERATERM at 921600bds
216 ; TERATERM config terminal : NewLine receive : AUTO,
217 ; NewLine transmit : CR+LF
218 ; Size : 128 chars x 49 lines (adjust lines to your display)
220 ; TERATERM config serial port : TERMINALBAUDRATE value,
221 ; 8bits, no parity, 1Stopbit,
222 ; Hardware flow control or software flow control or ...no flow control!
223 ; delay = 0ms/line, 0ms/char
225 ; don't forget : save new TERATERM configuration !
227 ; in fact, compared to using a UART USB bridge, only the COMx port is to be updated.
228 ; ------------------------------------------------------------------------------
230 .include "ThingsInFirst.inc" ; to define target config: I/O, memory, SFR, vectors, TERMINAL eUSCI, SD_Card eUSCI, LF_XTAL,
232 ;-------------------------------------------------------------------------------
233 ; DTCforthMSP430FR5xxx RAM memory map:
234 ;-------------------------------------------------------------------------------
236 ;-------------------------------------
237 ; name words ; comment
238 ;-------------------------------------
239 ;LSTACK = L0 = LEAVEPTR ; ----- RAM_ORG
241 LSTACK_LEN .equ 16 ; | grows up
244 PSTACK_LEN .equ 48 ; | grows down
246 ;PSTACK=S0 ; ----- RAM_ORG + $80
248 RSTACK_LEN .equ 48 ; | grows down
250 ;RSTACK=R0 ; ----- RAM_ORG + $E0
252 ;-------------------------------------
253 ; names bytes ; comments
254 ;-------------------------------------
255 ; PAD_I2CADR ; ----- RAM_ORG + $E0
257 ;PAD ; ----- RAM_ORG + $E4
259 PAD_LEN .equ 84 ; | grows up (ans spec. : PAD >= 84 chars)
261 ; TIB_I2CADR ; ----- RAM_ORG + $138
263 ; TIB_ORG ; ----- RAM_ORG + $13C
265 TIB_LEN .equ 84 ; | grows up (ans spec. : TIB >= 80 chars)
267 ; HOLDS_ORG ; ------RAM_ORG + $190
269 HOLD_LEN .equ 34 ; | grows down (ans spec. : HOLD_LEN >= (2*n) + 2 char, with n = 16 bits/cell
271 ; HOLD_BASE ; ----- RAM_ORG + $1B2
275 ; ----- RAM_ORG + $1E0
277 ; assembler variables
279 ; ----- RAM_ORG + $1F0
283 ; SD_BUF_I2CADR ; ----- RAM_ORG + $1FC
285 ; SD_BUF ; ----- RAM_ORG + $200
287 SD_BUF_LEN .equ 200h ; 512 bytes buffer
289 ; SD_BUF_END ; ----- RAM_ORG + $400
293 LEAVEPTR .equ LSTACK ; Leave-stack pointer
294 PSTACK .equ LSTACK+(LSTACK_LEN*2)+(PSTACK_LEN*2)
295 RSTACK .equ PSTACK+(RSTACK_LEN*2)
296 PAD_I2CADR .equ PAD_ORG-4
297 PAD_I2CCNT .equ PAD_ORG-2
298 PAD_ORG .equ RSTACK+4
299 TIB_I2CADR .equ TIB_ORG-4
300 TIB_I2CCNT .equ TIB_ORG-2
301 TIB_ORG .equ PAD_ORG+PAD_LEN+4
302 HOLDS_ORG .equ TIB_ORG+TIB_LEN
304 HOLD_BASE .equ HOLDS_ORG+HOLD_LEN
306 ; ----------------------------------------------------
307 ; RAM_ORG + $1B2 : RAM VARIABLES
308 ; ----------------------------------------------------
309 HP .equ HOLD_BASE ; HOLD ptr
310 CAPS .equ HOLD_BASE+2 ; CAPS ON = 32, CAPS OFF = 0
311 LAST_NFA .equ HOLD_BASE+4 ; NFA, VOC_PFA, CFA, PSP of last created word
312 LAST_THREAD .equ HOLD_BASE+6 ; used by QREVEAL
313 LAST_CFA .equ HOLD_BASE+8
314 LAST_PSP .equ HOLD_BASE+10
315 STATE .equ HOLD_BASE+12 ; Interpreter state
316 SOURCE .equ HOLD_BASE+14 ; len, org of input stream
317 SOURCE_LEN .equ HOLD_BASE+14
318 SOURCE_ORG .equ HOLD_BASE+16
319 TOIN .equ HOLD_BASE+18 ; CurrentInputBuffer pointer
320 DDP .equ HOLD_BASE+20 ; dictionnary pointer
321 LASTVOC .equ HOLD_BASE+22 ; keep VOC-LINK
322 CONTEXT .equ HOLD_BASE+24 ; CONTEXT dictionnary space (8 CELLS)
323 CURRENT .equ HOLD_BASE+40 ; CURRENT dictionnary ptr
324 BASE .equ HOLD_BASE+42
325 LINE .equ HOLD_BASE+44 ; line in interpretation (initialized by NOECHO)
327 ; --------------------------------------------------------------;
328 ; RAM_ORG + $1E0 : free for user after source file compilation ;
329 ; --------------------------------------------------------------;
330 RAM_ASM_ORG .equ HOLD_BASE+46
331 ASMBW1 .equ HOLD_BASE+46
332 ASMBW2 .equ HOLD_BASE+48
333 ASMBW3 .equ HOLD_BASE+50
334 ASMFW1 .equ HOLD_BASE+52
335 ASMFW2 .equ HOLD_BASE+54
336 ASMFW3 .equ HOLD_BASE+56
337 SAV_CURRENT .equ HOLD_BASE+58 ; save current CURRENT during create assembler words
338 RPT_WORD .equ HOLD_BASE+60 ; for extended assembler
339 RAM_ASM_END .equ HOLD_BASE+62 ;
340 RAM_ASM_LEN .equ RAM_ASM_END-RAM_ASM_ORG
341 ; ----------------------------------;
342 ; RAM_ORG + $1F0 : free for user ;
343 ; ----------------------------------;
345 ; --------------------------------------------------
346 ; RAM_ORG + $1FC : RAM SD_CARD SD_BUF 4 + 512 bytes
347 ; --------------------------------------------------
348 SD_BUF_I2CADR .equ SD_BUF-4
349 SD_BUF_I2CCNT .equ SD_BUF-2
350 SD_BUF .equ HOLD_BASE+78
351 SD_BUF_END .equ SD_BUF + 200h ; 512bytes
353 ;-------------------------------------------------------------------------------
354 ; INFO(DCBA) >= 256 bytes memory map (FRAM) :
355 ;-------------------------------------------------------------------------------
359 ; --------------------------
360 ; FRAM INFO KERNEL CONSTANTS
361 ; --------------------------
362 INI_THREAD .word THREADS ; used by ADDON_UTILITY.f
363 TERMBRW_RST .word TERMBRW_INI ; set by TERMINALBAUDRATE.inc
364 TERMMCTLW_RST .word TERMMCTLW_INI ; set by TERMINALBAUDRATE.inc
367 .ELSEIF FREQUENCY = 0.5
370 FREQ_KHZ .word FREQUENCY*1000 ; user use
372 SAVE_SYSRSTIV .word 5 ;
373 LPM_MODE .word CPUOFF+GIE ; LPM0 is the default mode
374 ;LPM_MODE .word CPUOFF+GIE+SCG0 ; LPM1 is the default mode (disable FLL)
375 INIDP .word ROMDICT ; define RST_STATE
376 INIVOC .word lastvoclink ; define RST_STATE
377 FORTHVERSION .word VERSIO ;
378 FORTHADDON .word FADDON ;
379 .word RXON ; 1814h for user use: CALL &RXON
380 .word RXOFF ; 1816h for user use: CALL &RXOFF
381 .IFDEF SD_CARD_LOADER
382 .word ReadSectorWX ; 1818h used by ADDON_SD_TOOLS.f
383 .IFDEF SD_CARD_READ_WRITE
384 .word WriteSectorWX ; 181Ah used by ADDON_SD_TOOLS.f
385 .ENDIF ; SD_CARD_READ_WRITE
386 .ENDIF ; SD_CARD_LOADER
388 ; -------------------------------
389 ; VARIABLES that should be in RAM
390 ; -------------------------------
392 .IFDEF SD_CARD_LOADER
393 .IF RAM_LEN < 2048 ; if RAM < 2K (FR57xx) the variables below are in INFO space (FRAM)
394 SD_ORG .equ INFO_ORG+2Ch ;
395 .ELSE ; if RAM >= 2k the variables below are in RAM
396 SD_ORG .equ SD_BUF_END+2 ; 1 word guard
401 ; ---------------------------------------
402 ; FAT FileSystemInfos
403 ; ---------------------------------------
404 FATtype .equ SD_ORG+0
405 BS_FirstSectorL .equ SD_ORG+2 ; init by SD_Init, used by RW_Sector_CMD
406 BS_FirstSectorH .equ SD_ORG+4 ; init by SD_Init, used by RW_Sector_CMD
407 OrgFAT1 .equ SD_ORG+6 ; init by SD_Init,
408 FATSize .equ SD_ORG+8 ; init by SD_Init,
409 OrgFAT2 .equ SD_ORG+10 ; init by SD_Init,
410 OrgRootDIR .equ SD_ORG+12 ; init by SD_Init, (FAT16 specific)
411 OrgClusters .equ SD_ORG+14 ; init by SD_Init, Sector of Cluster 0
412 SecPerClus .equ SD_ORG+16 ; init by SD_Init, byte size
414 SD_LOW_LEVEL .equ SD_ORG+18
415 ; ---------------------------------------
417 ; ---------------------------------------
418 SD_CMD_FRM .equ SD_LOW_LEVEL ; SD_CMDx inverted frame ${CRC7,ll,LL,hh,HH,CMD}
419 SectorL .equ SD_LOW_LEVEL+6
420 SectorH .equ SD_LOW_LEVEL+8
422 ; ---------------------------------------
424 ; ---------------------------------------
425 BufferPtr .equ SD_LOW_LEVEL+10
426 BufferLen .equ SD_LOW_LEVEL+12
428 SD_FAT_LEVEL .equ SD_LOW_LEVEL+14
429 ; ---------------------------------------
431 ; ---------------------------------------
432 ClusterL .equ SD_FAT_LEVEL ;
433 ClusterH .equ SD_FAT_LEVEL+2 ;
434 NewClusterL .equ SD_FAT_LEVEL+4 ;
435 NewClusterH .equ SD_FAT_LEVEL+6 ;
436 CurFATsector .equ SD_FAT_LEVEL+8 ; current FATSector of last free cluster
438 ; ---------------------------------------
440 ; ---------------------------------------
441 DIRClusterL .equ SD_FAT_LEVEL+10 ; contains the Cluster of current directory ; = 1 as FAT16 root directory
442 DIRClusterH .equ SD_FAT_LEVEL+12 ; contains the Cluster of current directory ; = 1 as FAT16 root directory
443 EntryOfst .equ SD_FAT_LEVEL+14
445 ; ---------------------------------------
447 ; ---------------------------------------
448 CurrentHdl .equ SD_FAT_LEVEL+16 ; contains the address of the last opened file structure, or 0
450 ; ---------------------------------------
451 ; Load file operation
452 ; ---------------------------------------
453 pathname .equ SD_FAT_LEVEL+18 ; start address
454 EndOfPath .equ SD_FAT_LEVEL+20 ; end address
456 ; ---------------------------------------
458 FirstHandle .equ SD_FAT_LEVEL+22
459 ; ---------------------------------------
461 ; ---------------------------------------
462 ; three handle tokens :
463 ; HDLB_Token= 0 : free handle
465 ; = 2 : file updated (write)
466 ; =-1 : LOAD"ed file (source file)
469 HDLW_PrevHDL .equ 0 ; previous handle
470 HDLB_Token .equ 2 ; token
471 HDLB_ClustOfst .equ 3 ; Current sector offset in current cluster (Byte)
472 HDLL_DIRsect .equ 4 ; Dir SectorL
473 HDLH_DIRsect .equ 6 ; Dir SectorH
474 HDLW_DIRofst .equ 8 ; SD_BUF offset of Dir entry
475 HDLL_FirstClus .equ 10 ; File First ClusterLo (identify the file)
476 HDLH_FirstClus .equ 12 ; File First ClusterHi (identify the file)
477 HDLL_CurClust .equ 14 ; Current ClusterLo
478 HDLH_CurClust .equ 16 ; Current ClusterHi
479 HDLL_CurSize .equ 18 ; written size / not yet read size (Long)
480 HDLH_CurSize .equ 20 ; written size / not yet read size (Long)
481 HDLW_BUFofst .equ 22 ; SD_BUF offset ; used by LOAD"
482 HDLW_PrevLEN .equ 24 ; previous LEN
483 HDLW_PrevORG .equ 26 ; previous ORG
485 .IF RAM_LEN < 2048 ; due to the lack of RAM, only 5 handles and PAD replaces SDIB
487 HandleMax .equ 5 ; and not 8 to respect INFO size (FRAM)
489 HandleEnd .equ FirstHandle+handleMax*HandleLenght
491 SD_END .equ HandleEnd
493 SDIB_I2CADR .equ PAD_ORG-4
494 SDIB_I2CCNT .equ PAD_ORG-2
495 SDIB_ORG .equ PAD_ORG
497 .ELSE ; RAM_Size >= 2k all is in RAM
501 HandleEnd .equ FirstHandle+handleMax*HandleLenght
503 SDIB_I2CADR .equ SDIB_ORG-4
504 SDIB_I2CCNT .equ SDIB_ORG-2
505 SDIB_ORG .equ HandleEnd+4
506 SDIB_LEN .equ 84 ; = TIB_LEN = PAD_LEN
508 SD_END .equ SDIB_ORG+SDIB_LEN
512 SD_LEN .equ SD_END-SD_ORG
514 .ENDIF ; SD_CARD_LOADER
516 ;-------------------------------------------------------------------------------
517 ; DTCforthMSP430FR5xxx program (FRAM) memory
518 ;-------------------------------------------------------------------------------
522 ;-------------------------------------------------------------------------------
523 ; DEFINING EXECUTIVE WORDS - DTC model
524 ;-------------------------------------------------------------------------------
525 ; very nice FAST FORTH added feature:
526 ;-------------------------------------------------------------------------------
527 ; as IP is always computed from the PC value, we can place low level to high level
528 ; switches "COLON" or "LO2HI" anywhere in a word, i.e. not only at its beginning
529 ; as ITC competitors.
530 ;-------------------------------------------------------------------------------
532 RSP .reg R1 ; RSP = Return Stack Pointer (return stack)
534 ; DOxxx registers ; must be saved before use and restored after use
540 R .reg r4 ; rDODOES alias
541 Q .reg r5 ; rDOCON alias
542 P .reg r6 ; rDOVAR alias
543 M .reg R7 ; rDOCOL alias
552 ; Forth virtual machine
553 IP .reg R13 ; interpretative pointer
554 TOS .reg R14 ; first PSP cell
555 PSP .reg R15 ; PSP = Parameters Stack Pointer (stack data)
558 mNEXT .MACRO ; return for low level words (written in assembler)
559 MOV @IP+,PC ; 4 fetch code address into PC, IP=PFA
560 .ENDM ; 4 cycles,1word = ITC -2cycles -1 word
562 NEXT .equ 4D30h ; 4 MOV @IP+,PC
564 FORTHtoASM .MACRO ; compiled by HI2LO
566 .ENDM ; 0 cycle, 1 word
573 ;-------------------------------------------------------------------------------
574 ; mDODOES leave on parameter stack the PFA of a CREATE definition and execute Master word
575 ;-------------------------------------------------------------------------------
577 mDODOES .MACRO ; compiled by DOES>
578 CALL rDODOES ; CALL xdodoes
579 .ENDM ; 1 word, 19 cycles (ITC-2)
581 DODOES .equ 1284h ; 4 CALL rDODOES ; [rDODOES] is defind as xdodoes by COLD
583 xdodoes ; -- a-addr ; 4 for CALL rDODOES
585 MOV TOS,0(PSP) ; 3 save TOS on parameters stack
586 MOV @RSP+,TOS ; 2 TOS = CFA address of master word, i.e. address of its first cell after DOES>
587 PUSH IP ; 3 save IP on return stack
588 MOV @TOS+,IP ; 2 IP = CFA of Master word, TOS = BODY address of created word
589 MOV @IP+,PC ; 4 Execute Master word
591 ;-------------------------------------------------------------------------------
592 ; mDOCON leave on parameter stack the [PFA] of a CONSTANT definition
593 ;-------------------------------------------------------------------------------
595 mDOCON .MACRO ; compiled by CONSTANT
596 CALL rDOCON ; 1 word, 16 cycles (ITC+3)
599 DOCON .equ 1285h ; 4 CALL rDOCON ; [rDOCON] is defined as xdocon by COLD
601 xdocon ; -- constant ; 4 for CALL rDOCON
603 MOV TOS,0(PSP) ; 3 save TOS on parameters stack
604 MOV @RSP+,TOS ; 2 TOS = CFA address of master word CONSTANT
605 MOV @TOS,TOS ; 2 TOS = CONSTANT value
606 MOV @IP+,PC ; 4 execute next word
609 ;-------------------------------------------------------------------------------
610 ; mDOVAR leave on parameter stack the PFA of a VARIABLE definition
611 ;-------------------------------------------------------------------------------
613 mDOVAR .MACRO ; compiled by VARIABLE
614 CALL rDOVAR ; 1 word, 14 cycles (ITC+2)
617 DOVAR .equ 1286h ; CALL rDOVAR ; [rDOVAR] is defined as RFROM by COLD
620 ;-------------------------------------------------------------------------------
621 .CASE 1 ; DOCOL = CALL rDOCOL
622 ;-------------------------------------------------------------------------------
624 xdocol MOV @RSP+,W ; 2
625 PUSH IP ; 3 save old IP on return stack
626 MOV W,IP ; 1 set new IP to PFA
627 MOV @IP+,PC ; 4 = NEXT
630 ASMtoFORTH .MACRO ; compiled by LO2HI
631 CALL #EXIT ; 10 cycles
632 .ENDM ; 2 words, 10 cycles
634 mDOCOL .MACRO ; compiled by : and by colon
635 CALL rDOCOL ; 10 [rDOCOL] = xdocol
636 .ENDM ; 1 word, 14 cycles (CALL included) = ITC+4
638 DOCOL1 .equ 1287h ; 4 CALL rDOCOL
640 ;-------------------------------------------------------------------------------
641 .CASE 2 ; DOCOL = PUSH IP + CALL rDOCOL
642 ;-------------------------------------------------------------------------------
644 ASMtoFORTH .MACRO ; compiled by LO2HI
645 CALL rDOCOL ; 10 [rDOCOL] = EXIT
646 .ENDM ; 1 word, 10 cycles
648 mDOCOL .MACRO ; compiled by : and by COLON
650 CALL rDOCOL ; 10 [rDOCOL] = EXIT
651 .ENDM ; 2 words, 13 cycles = ITC+3
653 DOCOL1 .equ 120Dh ; 3 PUSH IP
654 DOCOL2 .equ 1287h ; 4 CALL rDOCOL
656 ;-------------------------------------------------------------------------------
657 .CASE 3 ; inlined DOCOL
658 ;-------------------------------------------------------------------------------
660 ASMtoFORTH .MACRO ; compiled by LO2HI
664 .ENDM ; 6 cycles, 3 words
666 mDOCOL .MACRO ; compiled by : and by COLON
671 .ENDM ; 4 words, 9 cycles (ITC-1)
673 DOCOL1 .equ 120Dh ; 3 PUSH IP
674 DOCOL2 .equ 400Dh ; 1 MOV PC,IP
675 DOCOL3 .equ 522Dh ; 1 ADD #4,IP
679 ;-------------------------------------------------------------------------------
681 ;-------------------------------------------------------------------------------
683 ;https://forth-standard.org/standard/core/EXIT
684 ;C EXIT -- exit a colon definition; CALL #EXIT performs ASMtoFORTH (10 cycles)
685 ; JMP #EXIT performs EXIT
687 EXIT MOV @RSP+,IP ; 2 pop previous IP (or next PC) from return stack
688 MOV @IP+,PC ; 4 = NEXT
691 ;Z lit -- x fetch inline literal to stack
692 ; This is the execution part of LITERAL.
694 lit SUB #2,PSP ; 2 push old TOS..
695 MOV TOS,0(PSP) ; 3 ..onto stack
696 MOV @IP+,TOS ; 2 fetch new TOS value
700 ;-------------------------------------------------------------------------------
702 ;-------------------------------------------------------------------------------
704 ;https://forth-standard.org/standard/core/DUP
705 ;C DUP x -- x x duplicate top of stack
707 DUP SUB #2,PSP ; 2 push old TOS..
708 MOV TOS,0(PSP) ; 3 ..onto stack
711 ;https://forth-standard.org/standard/core/qDUP
712 ;C ?DUP x -- 0 | x x DUP if nonzero
714 QDUP CMP #0,TOS ; 2 test for TOS nonzero
718 ;https://forth-standard.org/standard/core/DROP
719 ;C DROP x -- drop top of stack
721 DROP MOV @PSP+,TOS ; 2
724 ;https://forth-standard.org/standard/core/NIP
725 ;C NIP x1 x2 -- x2 Drop the first item below the top of stack
730 ;https://forth-standard.org/standard/core/SWAP
731 ;C SWAP x1 x2 -- x2 x1 swap top two items
738 ;https://forth-standard.org/standard/core/OVER
739 ;C OVER x1 x2 -- x1 x2 x1
741 OVER MOV TOS,-2(PSP) ; 3 -- x1 (x2) x2
742 MOV @PSP,TOS ; 2 -- x1 (x2) x1
743 SUB #2,PSP ; 1 -- x1 x2 x1
746 ;https://forth-standard.org/standard/core/ROT
747 ;C ROT x1 x2 x3 -- x2 x3 x1
749 ROT MOV @PSP,W ; 2 fetch x2
750 MOV TOS,0(PSP) ; 3 store x3
751 MOV 2(PSP),TOS ; 3 fetch x1
752 MOV W,2(PSP) ; 3 store x2
755 ;https://forth-standard.org/standard/core/toR
756 ;C >R x -- R: -- x push to return stack
762 ;https://forth-standard.org/standard/core/Rfrom
763 ;C R> -- x R: x -- pop from return stack ; CALL #RFROM performs DOVAR
770 ;https://forth-standard.org/standard/core/RFetch
771 ;C R@ -- x R: x -- x fetch from rtn stk
778 ;https://forth-standard.org/standard/core/DEPTH
779 ;C DEPTH -- +n number of items on stack, must leave 0 if stack empty
781 DEPTH MOV TOS,-2(PSP)
783 SUB PSP,TOS ; PSP-S0--> TOS
784 RRA TOS ; TOS/2 --> TOS
785 DECPSP SUB #2,PSP ; post decrement stack...
788 ;-------------------------------------------------------------------------------
790 ;-------------------------------------------------------------------------------
792 ;https://forth-standard.org/standard/core/Fetch
793 ;C @ a-addr -- x fetch cell from memory
798 ;https://forth-standard.org/standard/core/Store
799 ;C ! x a-addr -- store cell in memory
801 STORE MOV @PSP+,0(TOS) ;4
805 ;https://forth-standard.org/standard/core/CFetch
806 ;C C@ c-addr -- char fetch char from memory
808 CFETCH MOV.B @TOS,TOS ;2
811 ;https://forth-standard.org/standard/core/CStore
812 ;C C! char c-addr -- store char in memory
814 CSTORE MOV.B @PSP+,0(TOS) ;4
819 ;-------------------------------------------------------------------------------
820 ; ARITHMETIC OPERATIONS
821 ;-------------------------------------------------------------------------------
823 ;https://forth-standard.org/standard/core/Plus
824 ;C + n1/u1 n2/u2 -- n3/u3 add n1+n2
829 ;https://forth-standard.org/standard/core/Minus
830 ;C - n1/u1 n2/u2 -- n3/u3 n3 = n1-n2
832 MINUS SUB @PSP+,TOS ;2 -- n2-n1
833 NEGATE XOR #-1,TOS ;1
834 ADD #1,TOS ;1 -- n3 = -(n2-n1) = n1-n2
837 ;https://forth-standard.org/standard/core/OnePlus
838 ;C 1+ n1/u1 -- n2/u2 add 1 to TOS
843 ;https://forth-standard.org/standard/core/OneMinus
844 ;C 1- n1/u1 -- n2/u2 subtract 1 from TOS
849 ;https://forth-standard.org/standard/double/DABS
850 ;C DABS d1 -- |d1| absolute value
852 DABBS AND #-1,TOS ; clear V, set N
853 JGE DABBSEND ; if positive
854 DNEGATE XOR #-1,0(PSP)
860 ;-------------------------------------------------------------------------------
861 ; COMPARAISON OPERATIONS
862 ;-------------------------------------------------------------------------------
864 ;https://forth-standard.org/standard/core/ZeroEqual
865 ;C 0= n/u -- flag return true if TOS=0
867 ZEROEQUAL SUB #1,TOS ; borrow (clear cy) if TOS was 0
868 SUBC TOS,TOS ; TOS=-1 if borrow was set
871 ;https://forth-standard.org/standard/core/Zeroless
872 ;C 0< n -- flag true if TOS negative
874 ZEROLESS ADD TOS,TOS ;1 set carry if TOS negative
875 SUBC TOS,TOS ;1 TOS=-1 if carry was clear
876 XOR #-1,TOS ;1 TOS=-1 if carry was set
879 ;https://forth-standard.org/standard/core/Equal
880 ;C = x1 x2 -- flag test x1=x2
882 EQUAL SUB @PSP+,TOS ;2
884 TOSFALSE MOV #0,TOS ;1
887 ;https://forth-standard.org/standard/core/Uless
888 ;C U< u1 u2 -- flag test u1<u2, unsigned
891 SUB TOS,W ;1 u1-u2 in W, carry clear if borrow
892 JC TOSFALSE ; unsigned
893 TOSTRUE MOV #-1,TOS ;1
896 ;https://forth-standard.org/standard/core/less
897 ;C < n1 n2 -- flag test n1<n2, signed
899 LESS MOV @PSP+,W ;2 W=n1
900 SUB TOS,W ;1 W=n1-n2 flags set
902 JGE TOSFALSE ;2 --> +5
904 ;https://forth-standard.org/standard/core/more
905 ;C > n1 n2 -- flag test n1>n2, signed
907 GREATER SUB @PSP+,TOS ;2 TOS=n2-n1
909 JGE TOSFALSE ;2 --> +5
911 ;-------------------------------------------------------------------------------
913 ;-------------------------------------------------------------------------------
915 ;https://forth-standard.org/standard/core/BL
916 ;C BL -- char an ASCII space
921 ;-------------------------------------------------------------------------------
923 ;-------------------------------------------------------------------------------
925 ;https://forth-standard.org/standard/core/BASE
926 ;C BASE -- a-addr holds conversion radix
929 .word BASE ; VARIABLE address in RAM space
931 ;https://forth-standard.org/standard/core/STATE
932 ;C STATE -- a-addr holds compiler state
935 .word STATE ; VARIABLE address in RAM space
937 ;-------------------------------------------------------------------------------
938 ; ANS complement OPTION
939 ;-------------------------------------------------------------------------------
940 .IFDEF ANS_CORE_COMPLEMENT
941 .include "ADDON/ANS_COMPLEMENT.asm"
942 .ENDIF ; ANS_COMPLEMENT
944 ;-------------------------------------------------------------------------------
946 ;-------------------------------------------------------------------------------
948 ; Numeric conversion is done last digit first, so
949 ; the output buffer is built backwards in memory.
951 ;https://forth-standard.org/standard/core/num-start
952 ;C <# -- begin numeric conversion (initialize Hold Pointer)
954 LESSNUM MOV #HOLD_BASE,&HP
957 ;https://forth-standard.org/standard/core/UMDivMOD
958 ; UM/MOD udlo|udhi u1 -- r q unsigned 32/16->r16 q16
960 UMSLASHMOD PUSH #DROP ;3 as return address for MU/MOD
962 ; unsigned 32-BIT DiViDend : 16-BIT DIVisor --> 32-BIT QUOTient, 16-BIT REMainder
963 ; 2 times faster if DVDhi = 0 (it's the general case)
965 ; reg division MU/MOD NUM
966 ; -----------------------------------------
967 ; S = DVDlo (15-0) = ud1lo = ud1lo
968 ; TOS = DVDhi (31-16) = ud1hi = ud1hi
970 ; W = REMlo = REMlo = digit --> char --> -[HP]
971 ; X = QUOTlo = ud2lo = ud2lo
972 ; Y = QUOThi = ud2hi = ud2hi
975 ; MU/MOD DVDlo DVDhi DIVlo -- REMlo QUOTlo QUOThi, also used by fixpoint and #
976 MUSMOD MOV TOS,T ;1 T = DIVlo
977 MOV 2(PSP),S ;3 S = DVDlo
978 MOV @PSP,TOS ;2 TOS = DVDhi
979 MUSMOD1 MOV #0,W ;1 W = REMlo = 0
980 MUSMOD2 MOV #32,rDODOES ;2 init loop count
981 ; -----------------------------------------
982 CMP #0,TOS ;1 DVDhi=0 ?
984 RRA rDODOES ;1 yes:loop count / 2
985 MOV S,TOS ;1 DVDhi <-- DVDlo
986 MOV #0,S ;1 DVDlo <-- 0
987 MOV #0,X ;1 QUOTlo <-- 0 (to do QUOThi = 0 at the end of division)
988 ; -----------------------------------------
989 MDIV1 CMP T,W ;1 REMlo U>= DIV ?
990 JNC MDIV2 ;2 no : carry is reset
991 SUB T,W ;1 yes: REMlo - DIV ; carry is set
992 MDIV2 ADDC X,X ;1 RLC quotLO
993 ADDC Y,Y ;1 RLC quotHI
994 SUB #1,rDODOES ;1 Decrement loop counter
997 ADDC TOS,TOS ;1 RLC DVDhi
998 ADDC W,W ;1 RLC REMlo
1000 SUB T,W ;1 REMlo - DIV
1003 ENDMDIV MOV #xdodoes,rDODOES;2 restore rDODOES
1004 MOV W,2(PSP) ;3 REMlo in 2(PSP)
1005 MOV X,0(PSP) ;3 QUOTlo in 0(PSP)
1006 MOV Y,TOS ;1 QUOThi in TOS
1007 RET ;4 35 words, about 473 cycles, not FORTH executable !
1009 ;https://forth-standard.org/standard/core/num
1010 ;C # ud1lo ud1hi -- ud2lo ud2hi convert 1 digit of output
1012 NUM MOV &BASE,T ;3 T = Divisor
1013 NUM1 MOV @PSP,S ;2 -- DVDlo DVDhi S = DVDlo
1014 SUB #2,PSP ;1 -- DVDlo x DVDhi TOS = DVDhi
1015 CALL #MUSMOD1 ;4 -- REMlo QUOTlo QUOThi
1016 MOV @PSP+,0(PSP) ;4 -- QUOTlo QUOThi
1017 TODIGIT CMP.B #10,W ;2 W = REMlo
1020 TODIGIT1 ADD.B #30h,W ;2
1021 HOLDW SUB #1,&HP ;4 store W=char --> -[HP]
1026 ;https://forth-standard.org/standard/core/numS
1027 ;C #S udlo udhi -- 0 0 convert remaining digits
1030 .word NUM ; X=QUOTlo
1032 SUB #2,IP ;1 restore NUM return
1033 CMP #0,X ;1 test ud2lo first (result generally false)
1035 CMP #0,TOS ;1 then test ud2hi (result generally true)
1037 mSEMI ;6 10 words, about 241/417 cycles/char
1039 ;https://forth-standard.org/standard/core/num-end
1040 ;C #> udlo:udhi -- c-addr u end conversion, get string
1042 NUMGREATER MOV &HP,0(PSP)
1047 ;https://forth-standard.org/standard/core/HOLD
1048 ;C HOLD char -- add char to output string
1054 ;https://forth-standard.org/standard/core/SIGN
1055 ;C SIGN n -- add minus sign if n<0
1063 ;https://forth-standard.org/standard/double/Dd
1064 ;C D. dlo dhi -- display d (signed)
1067 .word LESSNUM,DUP,TOR,DABBS,NUMS
1068 .word RFROM,SIGN,NUMGREATER,TYPE,SPACE,EXIT
1070 ;https://forth-standard.org/standard/core/Ud
1071 ;C U. u -- display u (unsigned)
1074 UDOT1 SUB #2,PSP ; convert n|u to d|ud
1079 ;https://forth-standard.org/standard/core/d
1080 ;C . n -- display n (signed)
1087 ;-------------------------------------------------------------------------------
1088 ; DICTIONARY MANAGEMENT
1089 ;-------------------------------------------------------------------------------
1091 ;https://forth-standard.org/standard/core/HERE
1092 ;C HERE -- addr returns memory ptr
1099 ;https://forth-standard.org/standard/core/ALLOT
1100 ;C ALLOT n -- allocate n bytes
1106 ;https://forth-standard.org/standard/core/CComma
1107 ;C C, char -- append char
1115 ;-------------------------------------------------------------------------------
1116 ; BRANCH and LOOP OPERATORS
1117 ;-------------------------------------------------------------------------------
1119 ;Z branch -- branch always
1123 ;Z ?FalseBranch x -- ; branch if TOS is FALSE (=zero)
1124 QFBRAN CMP #0,TOS ; 1 test TOS value
1125 MOV @PSP+,TOS ; 2 pop new TOS value (doesn't change flags)
1126 JZ BRAN ; 2 if TOS was = 0, take the branch = 11 cycles
1127 ADD #2,IP ; 1 else skip the branch destination
1128 mNEXT ; 4 ==> branch not taken = 10 cycles
1130 ;Z ?TrueBranch x -- ; branch if TOS is true (<> zero)
1131 QTBRAN CMP #0,TOS ; 1 test TOS value
1132 MOV @PSP+,TOS ; 2 pop new TOS value (doesn't change flags)
1133 JNZ BRAN ; 2 if TOS was <> 0, take the branch = 11 cycles
1134 ADD #2,IP ; 1 else skip the branch destination
1135 mNEXT ; 4 ==> branch not taken = 10 cycles
1137 ;Z (do) n1|u1 n2|u2 -- R: -- sys1 sys2 run-time code for DO
1138 ; n1|u1=limit, n2|u2=index
1139 xdo MOV #8000h,X ;2 compute 8000h-limit "fudge factor"
1141 MOV TOS,Y ;1 loop ctr = index+fudge
1142 MOV @PSP+,TOS ;2 pop new TOS
1144 PUSHM #2,X ;4 PUSHM X,Y, i.e. PUSHM LIMIT, INDEX
1147 ;Z (+loop) n -- R: sys1 sys2 -- | sys1 sys2
1148 ; run-time code for +LOOP
1149 ; Add n to the loop index. If loop terminates, clean up the
1150 ; return stack and skip the branch. Else take the inline branch.
1151 xploop ADD TOS,0(RSP) ;4 increment INDEX by TOS value
1152 MOV @PSP+,TOS ;2 get new TOS, doesn't change flags
1153 xloopnext BIT #100h,SR ;2 is overflow bit set?
1154 JZ BRAN ;2 no overflow = loop
1155 ADD #2,IP ;1 overflow = loop done, skip branch ofs
1156 UNXLOOP ADD #4,RSP ;1 empty RSP
1157 mNEXT ;4 16~ taken or not taken xloop/loop
1160 ;Z (loop) R: sys1 sys2 -- | sys1 sys2
1161 ; run-time code for LOOP
1162 ; Add 1 to the loop index. If loop terminates, clean up the
1163 ; return stack and skip the branch. Else take the inline branch.
1164 ; Note that LOOP terminates when index=8000h.
1165 xloop ADD #1,0(RSP) ;4 increment INDEX
1168 ;https://forth-standard.org/standard/core/UNLOOP
1169 ;C UNLOOP -- R: sys1 sys2 -- drop loop parms
1173 ;https://forth-standard.org/standard/core/I
1174 ;C I -- n R: sys1 sys2 -- sys1 sys2
1175 ;C get the innermost loop index
1177 II SUB #2,PSP ;1 make room in TOS
1179 MOV @RSP,TOS ;2 index = loopctr - fudge
1183 ;https://forth-standard.org/standard/core/J
1184 ;C J -- n R: 4*sys -- 4*sys
1185 ;C get the second loop index
1187 JJ SUB #2,PSP ; make room in TOS
1189 MOV 4(RSP),TOS ; index = loopctr - fudge
1193 ; ------------------------------------------------------------------------------
1194 ; TERMINAL I/O, input part
1195 ; ------------------------------------------------------------------------------
1197 ;https://forth-standard.org/standard/core/KEY
1198 ;C KEY -- c wait character from input device ; primary DEFERred word
1200 KEY MOV @PC+,PC ;3 Code Field Address (CFA) of KEY
1201 PFAKEY .word BODYKEY ; Parameter Field Address (PFA) of KEY, with default value
1202 BODYKEY MOV &TERM_RXBUF,Y ; empty buffer
1203 SUB #2,PSP ; 1 push old TOS..
1204 MOV TOS,0(PSP) ; 3 ..onto stack
1206 KEYLOOP BIT #UCRXIFG,&TERM_IFG ; loop if bit0 = 0 in interupt flag register
1208 MOV &TERM_RXBUF,TOS ;
1212 ;-------------------------------------------------------------------------------
1213 ; INTERPRETER INPUT, the kernel of kernel !
1214 ;-------------------------------------------------------------------------------
1216 .IFDEF SD_CARD_LOADER
1217 .include "forthMSP430FR_SD_ACCEPT.asm"
1222 ;https://forth-standard.org/standard/core/ACCEPT
1223 ;C ACCEPT addr addr len -- addr len' get line at addr to interpret len' chars
1225 ACCEPT MOV @PC+,PC ;3 Code Field Address (CFA) of ACCEPT
1226 PFAACCEPT .word BODYACCEPT ; Parameter Field Address (PFA) of ACCEPT
1227 BODYACCEPT ; BODY of ACCEPT = default execution of ACCEPT
1231 ;https://forth-standard.org/standard/core/ACCEPT
1232 ;C ACCEPT addr addr len -- addr len' get line at addr to interpret len' chars
1238 .IFDEF HALFDUPLEX ; to use FAST FORTH with half duplex input terminal (bluetooth or wifi connexion)
1240 .include "forthMSP430FR_HALFDUPLEX.asm"
1242 .ELSE ; to use FAST FORTH with full duplex terminal (USBtoUART bridge)
1244 ; con speed of TERMINAL link, there are three bottlenecks :
1245 ; 1- time to send XOFF/RTS_high on CR (CR+LF=EOL), first emergency.
1246 ; 2- the char loop time,
1247 ; 3- the time between sending XON/RTS_low and clearing UCRXIFG on first received char,
1248 ; everything must be done to reduce these times, taking into account the necessity of switching to SLEEP (LPMx mode).
1249 ; ----------------------------------;
1250 ; ACCEPT part I prepare TERMINAL_INT;
1251 ; ----------------------------------;
1252 MOV #ENDACCEPT,S ;2 S = XOFF_ret
1253 MOV #AKEYREAD1,T ;2 T = XON_ret
1254 PUSHM #3,IP ;5 PUSHM IP,S,T r-- ACCEPT_ret XOFF_ret XON_ret
1255 MOV TOS,W ;1 -- addr len
1256 MOV @PSP,TOS ;2 -- org ptr )
1257 ADD TOS,W ;1 -- org ptr W=Bound )
1258 MOV #0Dh,T ;2 T = 'CR' to speed up char loop in part II > prepare stack and registers for TERMINAL_INT use
1259 MOV #20h,S ;2 S = 'BL' to speed up char loop in part II )
1260 MOV #AYEMIT_RET,IP ;2 IP = return for YEMIT )
1261 BIT #UCRXIFG,&TERM_IFG ;3 RX_Int ?
1262 JZ ACCEPTNEXT ;2 no : case of quiet input terminal
1263 MOV &TERM_RXBUF,Y ;3 yes: clear RX_Int
1264 CMP #0Ah,Y ;2 received char = LF ? (end of downloading ?)
1265 JNZ RXON ;2 no : send XON then RET to AKEYREAD1 to process first char of new line.
1266 ACCEPTNEXT ADD #2,RSP ;1 replace XON_ret = AKEYREAD1 by XON_ret = SLEEP
1268 PUSHM #5,IP ;7 PUSH IP,S,T,W,X r-- ACCEPT_ret XOFF_ret YEMIT_ret 'BL' 'CR' bound XON_ret
1269 ; ----------------------------------;
1271 ; ----------------------------------;
1273 ; ----------------------------------;
1274 .IFDEF TERMINAL3WIRES ;
1275 RXON_LOOP BIT #UCTXIFG,&TERM_IFG ;3 wait the sending of last char, useless at high baudrates
1277 MOV #17,&TERM_TXBUF ;4 move char XON into TX_buf
1279 .IFDEF TERMINAL4WIRES ;
1280 BIC.B #RTS,&HANDSHAKOUT ;4 set RTS low
1282 ; vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv;
1283 ; starts first and 3th stopwatches ;
1284 ; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^;
1285 RET ;4 to BACKGND (End of file download or quiet input) or AKEYREAD1 (get next line of file downloading)
1286 ; ----------------------------------; ...or user defined
1288 ; ----------------------------------;
1290 ; ----------------------------------;
1291 .IFDEF TERMINAL3WIRES ;
1292 MOV #19,&TERM_TXBUF ;4 move XOFF char into TX_buf
1294 .IFDEF TERMINAL4WIRES ;
1295 BIS.B #RTS,&HANDSHAKOUT ;4 set RTS high
1297 RET ;4 to ENDACCEPT, ...or user defined
1298 ; ----------------------------------;
1300 ; ----------------------------------;
1301 ASMWORD "SLEEP" ; may be redirected
1302 SLEEP MOV @PC+,PC ;3 Code Field Address (CFA) of SLEEP
1303 PFASLEEP .word BODYSLEEP ; Parameter Field Address (PFA) of SLEEP, with default value
1304 BODYSLEEP BIS &LPM_MODE,SR ;3 enter in LPMx sleep mode with GIE=1
1306 ; ----------------------------------; default FAST FORTH mode (for its input terminal use) : LPM0.
1308 ;###############################################################################################################
1309 ;###############################################################################################################
1311 ; ### # # ####### ####### ###### ###### # # ###### ####### ##### # # ####### ###### #######
1312 ; # ## # # # # # # # # # # # # # # # # # # # #
1313 ; # # # # # # # # # # # # # # # # # # # # # #
1314 ; # # # # # ##### ###### ###### # # ###### # ##### ####### ##### ###### #####
1315 ; # # # # # # # # # # # # # # # # # # # # #
1316 ; # # ## # # # # # # # # # # # # # # # # # #
1317 ; ### # # # ####### # # # # ##### # # ##### # # ####### # # #######
1319 ;###############################################################################################################
1320 ;###############################################################################################################
1323 ; here, Fast FORTH sleeps, waiting any interrupt.
1324 ; IP,S,T,W,X,Y registers (R13 to R8) are free for any interrupt routine...
1325 ; ...and so PSP and RSP stacks with their rules of use.
1326 ; remember: in any interrupt routine you must include : BIC #0x78,0(RSP) before RETI
1327 ; to force return to SLEEP.
1328 ; or (bad idea ? previous SR flags are lost) simply : ADD #2 RSP, then RET instead of RETI
1331 ; ==================================;
1332 JMP SLEEP ;2 here is the return for any interrupts, else TERMINAL_INT :-)
1333 ; ==================================;
1335 ; **********************************;
1336 TERMINAL_INT ; <--- TEMR RX interrupt vector, delayed by the LPMx wake up time
1337 ; **********************************; if wake up time increases, max bauds rate decreases...
1338 ; (ACCEPT) part II under interrupt ; Org Ptr --
1339 ; ----------------------------------;
1340 ADD #4,RSP ;1 remove SR and PC from stack, SR flags are lost (unused by FORTH interpreter)
1341 POPM #4,IP ;6 POPM W=buffer_bound, T=0Dh, S=20h, IP=AYEMIT_RET r-- ACCEPT_ret XOFF_ret
1342 ; vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv;
1343 ; starts the 2th stopwatch ;
1344 ; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^;
1345 AKEYREAD MOV.B &TERM_RXBUF,Y ;3 read character into Y, UCRXIFG is cleared
1346 ; vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv;
1347 ; stops the 3th stopwatch ; 3th bottleneck result : 17~ + LPMx wake_up time ( + 5~ XON loop if F/Bds<230400 )
1348 ; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^;
1349 AKEYREAD1 CMP.B S,Y ;1 printable char ?
1350 JHS ASTORETEST ;2 yes
1352 JZ RXOFF ;2 then RET to ENDACCEPT
1353 ; vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv;+ 4 to send RXOFF
1354 ; stops the first stopwatch ;= first bottleneck, best case result: 27~ + LPMx wake_up time..
1355 ; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^; ...or 14~ in case of empty line
1356 CMP.B #8,Y ;1 char = BS ?
1357 JNE WAITaKEY ;2 case of other control chars
1358 ; ----------------------------------;
1359 ; start of backspace ; made only by an human
1360 ; ----------------------------------;
1361 CMP @PSP,TOS ; Ptr = Org ?
1362 JZ WAITaKEY ; yes: do nothing
1363 SUB #1,TOS ; no : dec Ptr
1364 JMP YEMIT1 ; send BS
1365 ; ----------------------------------;
1366 ; end of backspace ;
1367 ; ----------------------------------;
1368 ASTORETEST CMP W,TOS ; 1 Bound is reached ?
1369 JZ YEMIT1 ; 2 yes: send echo then loopback
1370 MOV.B Y,0(TOS) ; 3 no: store char @ Ptr, send echo then loopback
1371 ADD #1,TOS ; 1 increment Ptr
1373 BIT #UCTXIFG,&TERM_IFG ; 3 wait the sending end of previous char, useless at high baudrates
1374 JZ YEMIT1 ; 2 but there's no point in wanting to save time here:
1376 .IFDEF TERMINAL5WIRES ;
1377 BIT.B #CTS,&HANDSHAKIN ; 3
1380 YEMIT ; hi7/4~ lo:12/9~ send/send_not echo to terminal
1381 .word 4882h ; 4882h = MOV Y,&<next_adr>
1382 .word TERM_TXBUF ; 3
1384 ; ----------------------------------;
1385 AYEMIT_RET FORTHtoASM ; 0 YEMII NEXT address
1386 SUB #2,IP ; 1 reset YEMIT NEXT address to AYEMIT_RET
1387 WAITaKEY BIT #UCRXIFG,&TERM_IFG ; 3 new char in TERMRXBUF ?
1388 JNZ AKEYREAD ; 2 yes
1390 ; vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv;
1391 ; stops the 2th stopwatch ; best case result: 26~/22~ (with/without echo) ==> 385/455 kBds/MHz
1392 ; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^;
1394 ; ----------------------------------;
1395 ENDACCEPT ; --- Org Ptr r-- ACCEPT_ret
1396 ; ----------------------------------;
1397 CMP #0,&LINE ; if LINE <> 0...
1399 ADD #1,&LINE ; ...increment LINE
1400 ACCEPTEND SUB @PSP+,TOS ; -- len'
1401 MOV @RSP+,IP ; 2 return to INTERPRET with GIE=0: FORTH is protected against any interrupt...
1402 ; ----------------------------------;
1403 MOV #LPM0+GIE,&LPM_MODE ; reset LPM_MODE to default mode LPM0 for next line of input stream
1404 ; ----------------------------------;
1405 mNEXT ; ...until next falling down to LPMx mode of (ACCEPT) part1,
1406 ; **********************************; i.e. when the FORTH interpreter has no more to do.
1408 ; ------------------------------------------------------------------------------
1409 ; TERMINAL I/O, output part
1410 ; ------------------------------------------------------------------------------
1412 ;https://forth-standard.org/standard/core/EMIT
1413 ;C EMIT c -- output character to the selected output device ; primary DEFERred word
1415 EMIT MOV @PC+,PC ;3 Code Field Address (CFA) of EMIT
1416 PFAEMIT .word BODYEMIT ; Parameter Field Address (PFA) of EMIT, with its default value
1417 BODYEMIT MOV TOS,Y ; output character to the default output: TERMINAL
1425 ; CIB -- addr of Current Input Buffer
1426 FORTHWORD "CIB" ; constant, may be redirected as SDIB_ORG by OPEN.
1427 FCIB mDOCON ; Code Field Address (CFA) of FCIB
1428 PFACIB .WORD TIB_ORG ; Parameter Field Address (PFA) of FCIB
1430 ; REFILL accept one line from input and leave org len of input buffer
1431 ; : REFILL CIB DUP TIB_LEN ACCEPT ; -- CIB len shared by QUIT and [ELSE]
1432 REFILL SUB #6,PSP ;2
1435 MOV &PFACIB,0(PSP) ;5
1441 ; REFILL accept one line from input and leave org len of input buffer
1442 ; : REFILL TIB DUP TIB_LEN ACCEPT ; -- TIB len shared by QUIT and [ELSE]
1443 REFILL SUB #6,PSP ;2
1446 MOV #TIB_ORG,0(PSP) ;4
1452 ;Z ECHO -- connect terminal output (default)
1454 ECHO MOV #4882h,&YEMIT ; 4882h = MOV Y,&<next_adr>
1458 ;Z NOECHO -- disconnect terminal output
1460 NOECHO MOV #NEXT,&YEMIT ; NEXT = 4030h = MOV @IP+,PC
1464 ;https://forth-standard.org/standard/core/SPACE
1465 ;C SPACE -- output a space
1472 ;https://forth-standard.org/standard/core/SPACES
1473 ;C SPACES n -- output n spaces
1480 SPACESNEXT FORTHtoASM
1483 JNZ SPACE ;25~ ==> 27~ by space ==> 2.963 MBds @ 8 MHz
1484 DROPEXIT MOV @RSP+,IP ;
1485 ONEDROP MOV @PSP+,TOS ; -- drop n
1488 ;https://forth-standard.org/standard/core/TYPE
1489 ;C TYPE adr len -- type line to terminal
1492 JZ TWODROP ; abort fonction
1493 PUSHM #2,TOS ;4 R-- len,IP
1495 TYPELOOP MOV @PSP,Y ;2 -- adr x ; 30~ char loop
1497 MOV Y,0(PSP) ;3 -- adr+1 char
1498 SUB #2,PSP ;1 emit consumes one cell
1500 TYPE_NEXT FORTHtoASM
1502 SUB #1,2(RSP) ;4 len-1
1504 POPM #2,TOS ;4 POPM IP,TOS
1505 TWODROP ADD #2,PSP ;
1509 ;https://forth-standard.org/standard/core/CR
1510 ;C CR -- send CR to the output device
1512 CR MOV @PC+,PC ;3 Code Field Address (CFA) of CR
1513 PFACR .word BODYCR ; Parameter Field Address (PFA) of CR, with its default value
1514 BODYCR mDOCOL ; send CR to the default output device
1519 ; ------------------------------------------------------------------------------
1520 ; STRINGS PROCESSING
1521 ; ------------------------------------------------------------------------------
1523 ;Z (S") -- addr u run-time code for S"
1524 ; get address and length of string.
1525 XSQUOTE SUB #4,PSP ; 1 -- x x TOS ; push old TOS on stack
1526 MOV TOS,2(PSP) ; 3 -- TOS x x ; and reserve one cell on stack
1527 MOV.B @IP+,TOS ; 2 -- x u ; u = lenght of string
1528 MOV IP,0(PSP) ; 3 -- addr u
1529 ADD TOS,IP ; 1 -- addr u IP=addr+u=addr(end_of_string)
1530 BIT #1,IP ; 1 -- addr u IP=addr+u Carry set/clear if odd/even
1531 ADDC #0,IP ; 1 -- addr u IP=addr+u aligned
1534 ;https://forth-standard.org/standard/core/Sq
1535 ;C S" -- compile in-line string
1536 FORTHWORDIMM "S\34" ; immediate
1537 SQUOTE MOV #0,&CAPS ; CAPS OFF
1539 .word lit,XSQUOTE,COMMA
1540 SQUOTE1 .word lit,'"',WORDD ; -- c-addr (= HERE)
1543 MOV #32,&CAPS ; CAPS ON
1544 MOV.B @TOS,TOS ; -- u
1545 SUB #1,TOS ; -- u-1 bytes
1549 BIT #1,&DDP ;3 carry set if odd
1550 ADDC #2,&DDP ;4 +2/+3 bytes
1553 ;https://forth-standard.org/standard/core/Dotq
1554 ;C ." -- compile string to print
1555 FORTHWORDIMM ".\34" ; immediate
1558 .word lit,TYPE,COMMA,EXIT
1560 ;-------------------------------------------------------------------------------
1562 ;-------------------------------------------------------------------------------
1564 ;https://forth-standard.org/standard/core/WORD
1565 ;C WORD char -- addr Z=1 if len=0
1566 ; parse a word delimited by char separator, by default "word" is capitalized ([CAPS]=32)
1568 WORDD MOV #SOURCE_LEN,S ;2 -- separator
1569 MOV @S+,X ;2 X = str_len
1570 MOV @S+,W ;2 W = str_org
1571 ADD W,X ;1 W = str_org X = str_org + str_len = str_end
1572 ADD @S+,W ;2 W = str_org + >IN = str_ptr X = str_end
1573 MOV @S,Y ;2 -- separator W = str_ptr X = str_end Y = HERE, as dst_ptr
1574 SKIPCHARLOO CMP W,X ;1 str_ptr = str_end ?
1575 JZ EOL_END ;2 -- separator if yes : End Of Line !
1576 CMP.B @W+,TOS ;2 does char = separator ?
1577 JZ SKIPCHARLOO ;2 -- separator if yes
1578 SCANWORD SUB #1,W ;1
1579 MOV #96,T ;2 T = 96 = ascii(a)-1 (test value set in a register before SCANWORD loop)
1580 SCANWORDLOO ; -- separator 15/24 cycles loop for upper/lower case char... write words in upper case !
1581 MOV.B S,0(Y) ;3 first time make room in dst for word length, then put char @ dst.
1582 CMP W,X ;1 str_ptr = str_end ?
1583 JZ SCANWORDEND ;2 if yes
1585 CMP.B S,TOS ;1 does char = separator ?
1586 JZ SCANWORDEND ;2 if yes
1587 ADD #1,Y ;1 increment dst just before test loop
1588 CMP.B S,T ;1 char U< 'a' ? ('a'-1 U>= char) this condition is tested at each loop
1589 JC SCANWORDLOO ;2 15~ upper case char loop
1590 CMP.B #123,S ;2 char U>= 'z'+1 ?
1591 JC SCANWORDLOO ;2 if yes
1592 SUB.B &CAPS,S ;3 convert lowercase char to uppercase if CAPS ON (CAPS=32)
1593 JMP SCANWORDLOO ;2 24~ lower case char loop
1594 SCANWORDEND SUB &SOURCE_ORG,W ;3 -- separator W=str_ptr - str_org = new >IN (first char separator next)
1595 MOV W,&TOIN ;3 update >IN
1596 EOL_END MOV &DDP,TOS ;3 -- c-addr
1597 SUB TOS,Y ;1 Y=Word_Length
1599 mNEXT ;4 -- c-addr 40 words Z=1 <==> lenght=0 <==> EOL
1601 ;https://forth-standard.org/standard/core/FIND
1602 ;C FIND c-addr -- c-addr 0 if not found ; flag Z=1
1603 ;C CFA -1 if found ; flag Z=0
1604 ;C CFA 1 if immediate ; flag Z=0
1605 ; compare WORD at c-addr (HERE) with each of words in each of listed vocabularies in CONTEXT
1606 ; FIND to WORDLOOP : 14/20 cycles,
1607 ; mismatch word loop: 13 cycles on len, +7 cycles on first char,
1608 ; +10 cycles char loop,
1609 ; VOCLOOP : 12/18 cycles,
1610 ; WORDFOUND to end : 21 cycles.
1611 ; note: with 16 threads vocabularies, FIND takes about 75% of CORETEST.4th processing time
1612 FORTHWORD "FIND" ; -- c-addr
1613 FIND SUB #2,PSP ;1 -- ???? c-addr reserve one cell here, not at FINDEND because interacts with flag Z
1614 MOV TOS,S ;1 S=c-addr
1615 MOV.B @S,rDOCON ;2 R5= string count
1616 MOV.B #80h,rDODOES ;2 R4= immediate mask
1618 VOCLOOP MOV @T+,TOS ;2 -- ???? VOC_PFA T=CTXT+2
1619 CMP #0,TOS ;1 no more vocabulary in CONTEXT ?
1620 JZ FINDEND ;2 -- ???? 0 yes ==> exit; Z=1
1623 .ELSECASE ; search thread add 6cycles 5words
1624 MAKETHREAD MOV.B 1(S),Y ;3 -- ???? VOC_PFA0 S=c-addr Y=CHAR0
1625 AND.B #(THREADS-1)*2,Y ;2 -- ???? VOC_PFA0 Y=thread offset
1626 ADD Y,TOS ;1 -- ???? VOC_PFAx
1628 ADD #2,TOS ;1 -- ???? VOC_PFA+2
1629 WORDLOOP MOV -2(TOS),TOS ;3 -- ???? [VOC_PFA] [VOC_PFA] first, then [LFA]
1630 CMP #0,TOS ;1 -- ???? NFA no more word in the thread ?
1631 JZ VOCLOOP ;2 -- ???? NFA yes ==> search next voc in context
1633 MOV.B @X+,Y ;2 TOS=NFA,X=NFA+1,Y=NFA_char
1634 BIC.B rDODOES,Y ;1 hide Immediate bit
1635 LENCOMP CMP.B rDOCON,Y ;1 compare lenght
1636 JNZ WORDLOOP ;2 -- ???? NFA 13~ word loop on lenght mismatch
1638 CHARCOMP CMP.B @X+,1(W) ;4 compare chars
1639 JNZ WORDLOOP ;2 -- ???? NFA 20~ word loop on first char mismatch
1641 SUB.B #1,Y ;1 decr count
1642 JNZ CHARCOMP ;2 -- ???? NFA 10~ char loop
1644 WORDFOUND BIT #1,X ;1
1646 MOV X,S ;1 S=aligned CFA
1647 MOV.B @TOS,W ;2 -- ???? NFA W=NFA_first_char
1648 MOV #1,TOS ;1 -- ???? 1 preset immediate flag
1649 CMP.B #0,W ;1 W is negative if immediate flag
1650 JN FINDEND ;2 -- ???? 1
1651 SUB #2,TOS ;1 -- ???? -1
1652 FINDEND MOV S,0(PSP) ;3 not found: -- c-addr 0 flag Z=1
1653 MOV #xdocon,rDOCON ;2 found: -- xt -1|+1 (not immediate|immediate) flag Z=0
1654 MOV #xdodoes,rDODOES ;2
1655 mNEXT ;4 42/47 words
1659 ;https://forth-standard.org/standard/core/toNUMBER
1660 ; ud2 is the unsigned result of converting the characters within the string specified by c-addr1 u1 into digits,
1661 ; using the number in BASE, and adding each into ud1 after multiplying ud1 by the number in BASE.
1662 ; Conversion continues left-to-right until a character that is not convertible, including '.', ',' or '_',
1663 ; is encountered or the string is entirely converted. c-addr2 is the location of the first unconverted character
1664 ; or the first character past the end of the string if the string was entirely converted.
1665 ; u2 is the number of unconverted characters in the string.
1666 ; An ambiguous condition exists if ud2 overflows during the conversion.
1667 ;C >NUMBER ud1lo ud1hi addr1 cnt1 -- ud2lo ud2hi addr2 cnt2
1668 FORTHWORD ">NUMBER" ; 23 cycles + 32/34 cycles DEC/HEX char loop
1669 TONUMBER MOV @PSP+,S ;2 -- ud1lo ud1hi cnt1 S = addr1
1670 MOV @PSP+,Y ;2 -- ud1lo cnt1 Y = ud1hi
1671 MOV @PSP,X ;2 -- x cnt1 X = ud1lo
1672 SUB #4,PSP ;1 -- x x x cnt
1674 TONUMLOOP MOV.B @S,W ;2 -- x x x cnt S=adr, T=base, W=char, X=udlo, Y=udhi
1675 DDIGITQ SUB.B #30h,W ;2 skip all chars < '0'
1676 CMP.B #10,W ;2 char was U< 10 (U< ':') ?
1677 JLO DDIGITQNEXT ;2 no
1680 JLO TONUMEND ;2 -- x x x cnt exit if '9' < char < 'A'
1681 DDIGITQNEXT CMP T,W ;1 digit-base
1682 BIC #Z,SR ;1 reset Z before jmp TONUMEND because...
1683 JHS TONUMEND ;2 ...QNUMBER conversion will be true if Z = 1 :-(
1684 UDSTAR MOV X,&MPY32L ;3 Load 1st operand (ud1lo)
1685 MOV Y,&MPY32H ;3 Load 1st operand (ud1hi)
1686 MOV T,&OP2 ;3 Load 2nd operand with BASE
1687 MOV &RES0,X ;3 lo result in X (ud2lo)
1688 MOV &RES1,Y ;3 hi result in Y (ud2hi)
1689 MPLUS ADD W,X ;1 ud2lo + digit
1690 ADDC #0,Y ;1 ud2hi + carry
1691 TONUMPLUS ADD #1,S ;1 adr+1
1692 SUB #1,TOS ;1 -- x x x cnt cnt-1
1693 JNZ TONUMLOOP ;2 if count <>0
1694 TONUMEND MOV S,0(PSP) ;3 -- x x addr2 cnt2
1695 MOV Y,2(PSP) ;3 -- x ud2hi addr2 cnt2
1696 MOV X,4(PSP) ;3 -- ud2lo ud2hi addr2 cnt2
1699 ; ?NUMBER makes the interface between INTERPRET and >NUMBER; it's a subset of INTERPRET.
1700 ; convert a string to a signed number; FORTH 2012 prefixes $, %, # are recognized
1701 ; digits separator '_' is recognized
1702 ; with DOUBLE_INPUT switched ON, 32 bits numbers (with decimal point) are recognized
1703 ; with FIXPOINT_INPUT switched ON, Q15.16 signed numbers are recognized.
1704 ; prefixed chars - # % $ are processed before calling >NUMBER
1705 ; other (anywhere) chars . , and _ are processed as >NUMBER exits
1706 ;Z ?NUMBER addr -- n|d -1 if convert ok ; flag Z=0, UF9=1 if double
1707 ;Z addr -- addr 0 if convert ko ; flag Z=1
1709 MOV &BASE,T ;3 T=BASE
1710 MOV #0,S ;1 S=sign of result
1711 PUSHM #3,IP ;5 R-- IP sign base PUSH IP,S,T
1712 MOV #TONUMEXIT,IP ;2 set TONUMEXIT as return from >NUMBER
1715 SUB #8,PSP ;1 -- x x x x addr save TOS and make room for >NUMBER
1716 MOV TOS,6(PSP) ;3 -- addr x x x addr
1717 MOV TOS,S ;1 S=addrr
1718 MOV.B @S+,TOS ;2 -- addr x x x cnt TOS=count
1719 QNUMLDCHAR MOV.B @S,W ;2 W=char
1721 JLO QBINARY ;2 jump if char < '-'
1722 JNZ DDIGITQ ;2 -- addr x x x cnt jump if char > '-'
1723 MOV #-1,2(RSP) ;3 R-- IP sign base set sign flag
1725 QBINARY MOV #2,T ;1 preset base 2
1726 SUB.B #'%',W ;2 binary number ?
1728 QDECIMAL ADD #8,T ;1
1729 ADD.B #2,W ;1 decimal number ?
1732 SUB.B #1,W ;1 hex number ?
1733 JNZ TONUMLOOP ;2 -- addr x x x cnt other cases will cause >NUMBER exit
1734 PREFIXED ADD #1,S ;1
1735 SUB #1,TOS ;1 -- addr x x x cnt-1 S=adr+1 TOS=count-1
1737 ; ----------------------------------;
1738 TONUMEXIT FORTHtoASM ; -- addr ud2lo-hi addr2 cnt2 R-- IP sign BASE S=addr2
1739 ; ----------------------------------;
1740 JZ QNUMNEXT ;2 if conversion is ok
1741 ; ----------------------------------;
1742 SUB #2,IP ; redefines TONUMEXIT as >NUMBER return
1743 CMP.B #28h,W ; rejected char by >NUMBER is a underscore ?
1744 JZ TONUMPLUS ; yes, skip it
1745 ; ----------------------------------;
1746 .IFDEF DOUBLE_NUMBERS ; DOUBLE_NUMBERS = DOUBLE_INPUT | FIXPOINT_INPUT
1747 BIS #UF9,SR ;2 set double number flag
1749 .IFDEF DOUBLE_INPUT ;
1750 CMP.B #0F7h,W ;2 rejected char by >NUMBER is a decimal point ?
1751 JZ TONUMPLUS ;2 yes, skip it
1753 ; ----------------------------------;
1754 .IFDEF FIXPOINT_INPUT ;
1755 CMP.B #0F5h,W ;2 rejected char by >NUMBER is a comma ?
1756 JNZ QNUMNEXT ;2 no, that will be followed by abort on conversion error
1757 ; ----------------------------------;
1758 S15Q16 MOV TOS,W ;1 -- addr ud2lo x x x W=cnt2
1759 MOV #0,X ;1 -- addr ud2lo x 0 x init X = ud2lo' = 0
1760 S15Q16LOOP MOV X,2(PSP) ;3 -- addr ud2lo ud2lo' ud2lo' x 0(PSP) = ud2lo'
1761 SUB.B #1,W ;1 decrement cnt2
1762 MOV W,X ;1 X = cnt2-1
1763 ADD S,X ;1 X = end_of_string-1, first...
1764 MOV.B @X,X ;2 X = last char of string first (keep in mind: reverse conversion)
1765 SUB.B #30h,X ;2 char --> digit conversion
1769 CMP.B #10,X ;2 to skip all chars between "9" and "A"
1770 JLO S15Q16EOC ;2 end of conversion on first rejected char (normally: ',')
1771 QS15Q16DIGI CMP T,X ;1 R-- IP sign BASE is X a digit ?
1772 JHS S15Q16EOC ;2 -- addr ud2lo ud2lo' x ud2lo' if no goto QNUMNEXT (abort then)
1773 MOV X,0(PSP) ;3 -- addr ud2lo ud2lo' digit x
1774 MOV T,TOS ;1 -- addr ud2lo ud2lo' digit base R-- IP sign base
1775 PUSHM #3,S ;6 PUSH S,T,W: R-- IP sign base addr2 base cnt2
1776 CALL #MUSMOD ;4 -- addr ud2lo ur uqlo uqhi
1777 POPM #3,S ;6 restore W,T,S: R-- IP sign BASE
1778 JMP S15Q16LOOP ;2 W=cnt
1779 S15Q16EOC MOV 4(PSP),2(PSP) ;5 -- addr ud2lo ud2hi uqlo x ud2lo from >NUMBER part1 becomes here ud2hi part of Q15.16
1780 MOV @PSP,4(PSP) ;4 -- addr ud2lo ud2hi x x uqlo becomes ud2lo part of Q15.16
1781 MOV W,TOS ;1 -- addr ud2lo ud2hi x cnt2
1782 CMP.B #0,TOS ;1 TOS = 0 if end of conversion (happy end)
1784 ; ----------------------------------;
1785 QNUMNEXT POPM #3,IP ;4 -- addr ud2lo-hi x cnt2 POPM T,S,IP S = sign flag = {-1;0}
1786 MOV S,TOS ;1 -- addr ud2lo-hi x sign
1788 JZ QNUMOK ;2 -- addr ud2lo-hi x sign conversion OK
1790 .IFDEF DOUBLE_NUMBERS ;
1791 BIC #UF9,SR ;2 reset flag UF9, before use as double number flag
1793 ADD #6,PSP ;1 -- addr sign
1794 AND #0,TOS ;1 -- addr ff TOS=0 and Z=1 ==> conversion ko
1796 ; ----------------------------------;
1797 .IFDEF DOUBLE_NUMBERS
1798 QNUMOK ADD #2,PSP ;1 -- addr ud2lo-hi cnt2
1799 MOV 2(PSP),4(PSP) ; -- udlo udlo udhi sign
1800 MOV @PSP+,0(PSP) ;4 -- udlo udhi sign note : PSP is incremented before write back.
1801 XOR #-1,TOS ;1 -- udlo udhi inv(sign)
1802 JNZ QDOUBLE ;2 if jump : TOS=-1 and Z=0 ==> conversion ok
1803 QDNEGATE XOR #-1,TOS ;1 -- udlo udhi tf
1805 XOR #-1,0(PSP) ;3 -- (dlo dhi)-1 tf
1807 ADDC #0,0(PSP) ;3 -- dlo dhi tf
1808 QDOUBLE BIT #UF9,SR ;2 decimal point added ?
1809 JNZ QNUMEND ;2 leave double
1810 ADD #2,PSP ;1 leave number
1811 QNUMEND mNEXT ;4 TOS<>0 and Z=0 ==> conversion ok
1813 QNUMOK ADD #4,PSP ;1 -- addr ud2lo sign
1814 MOV @PSP+,0(PSP) ;4 -- udlo sign note : PSP is incremented before write back !!!
1815 XOR #-1,TOS ;1 -- udlo inv(sign)
1816 JNZ QNUMEND ;2 if jump : TOS=-1 and Z=0 ==> conversion ok
1817 QNEGATE XOR #-1,0(PSP) ;3
1818 ADD #1,0(PSP) ;3 -- n tf
1819 XOR #-1,TOS ;1 -- udlo udhi tf TOS=-1 and Z=0
1820 QNUMEND mNEXT ;4 TOS=-1 and Z=0 ==> conversion ok
1821 .ENDIF ; DOUBLE_NUMBERS
1822 ; ----------------------------------;128 words
1824 .ELSE ; no hardware MPY
1826 ; T.I. SIGNED MULTIPLY SUBROUTINE: U1 x U2 -> Ud
1827 ;https://forth-standard.org/standard/core/UMTimes
1828 ;C UM* u1 u2 -- ud unsigned 16x16->32 mult.
1830 UMSTAR MOV @PSP,S ;2 MDlo
1831 UMSTAR1 MOV #0,T ;1 MDhi=0
1834 MOV #1,W ;1 BIT TEST REGISTER
1835 UMSTARLOOP BIT W,TOS ;1 TEST ACTUAL BIT MRlo
1836 JZ UMSTARNEXT ;2 IF 0: DO NOTHING
1837 ADD S,X ;1 IF 1: ADD MDlo TO RES0
1838 ADDC T,Y ;1 ADDC MDhi TO RES1
1839 UMSTARNEXT ADD S,S ;1 (RLA LSBs) MDlo x 2
1840 ADDC T,T ;1 (RLC MSBs) MDhi x 2
1841 ADD W,W ;1 (RLA) NEXT BIT TO TEST
1842 JNC UMSTARLOOP ;2 IF BIT IN CARRY: FINISHED 10~ loop
1843 MOV X,0(PSP) ;3 low result on stack
1844 MOV Y,TOS ;1 high result in TOS
1847 ;https://forth-standard.org/standard/core/toNUMBER
1848 ; ud2 is the unsigned result of converting the characters within the string specified by c-addr1 u1 into digits,
1849 ; using the number in BASE, and adding each into ud1 after multiplying ud1 by the number in BASE.
1850 ; Conversion continues left-to-right until a character that is not convertible, including '.', ',' or '_',
1851 ; is encountered or the string is entirely converted. c-addr2 is the location of the first unconverted character
1852 ; or the first character past the end of the string if the string was entirely converted.
1853 ; u2 is the number of unconverted characters in the string.
1854 ; An ambiguous condition exists if ud2 overflows during the conversion.
1855 ;C >NUMBER ud1lo|ud1hi addr1 count1 -- ud2lo|ud2hi addr2 count2
1857 TONUMBER MOV @PSP,S ;2 S=adr
1858 MOV TOS,T ;1 T=count
1860 TONUMLOOP MOV.B @S,Y ;2 -- ud1lo ud1hi x x S=adr, T=count, W=BASE, Y=char
1861 DDIGITQ SUB.B #30h,Y ;2 skip all chars < '0'
1862 CMP.B #10,Y ;2 char was > "9" ?
1863 JLO DDIGITQNEXT ;2 -- ud1lo ud1hi x x no: good end
1864 SUB.B #07,Y ;2 skip all chars between "9" and "A"
1865 CMP.B #10,Y ;2 char was < "A" ?
1866 JLO TONUMEND ;2 yes: for bad end
1867 DDIGITQNEXT CMP W,Y ;1 -- ud1lo ud1hi x x digit-base
1868 BIC #Z,SR ;1 reset Z before jmp TONUMEND because...
1869 JHS TONUMEND ;2 ...QNUMBER conversion will be true if Z = 1 :-(
1870 UDSTAR PUSHM #6,IP ;8 -- ud1lo ud1hi x x r-- IP adr count base x digit
1871 MOV 2(PSP),S ;3 -- ud1lo ud1hi x x S=ud1hi
1872 MOV W,TOS ;1 -- ud1lo ud1hi x base
1873 MOV #UMSTARNEXT1,IP ;2
1874 UMSTARONE JMP UMSTAR1 ;2 ud1hi * base -- x ud3hi X=ud3lo
1875 UMSTARNEXT1 FORTHtoASM ; -- ud1lo ud1hi x ud3hi
1876 MOV X,2(RSP) ;3 r-- IP adr count base ud3lo digit
1877 MOV 4(PSP),S ;3 -- ud1lo ud1hi x ud3hi S=ud1lo
1878 MOV 4(RSP),TOS ;3 -- ud1lo ud1hi x base
1879 MOV #UMSTARNEXT2,IP ;2
1880 UMSTARTWO JMP UMSTAR1 ;2 -- ud1lo ud1hi x ud4hi X=ud4lo
1881 UMSTARNEXT2 FORTHtoASM ; -- ud1lo ud1hi x ud4hi
1882 MPLUS ADD @RSP+,X ;2 -- ud1lo ud1hi x ud4hi X=ud4lo+digit=ud2lo r-- IP adr count base ud3lo
1883 ADDC @RSP+,TOS ;2 -- ud1lo ud1hi x ud2hi TOS=ud4hi+ud3lo+carry=ud2hi r-- IP adr count base
1884 MOV X,4(PSP) ;3 -- ud2lo ud1hi x ud2hi
1885 MOV TOS,2(PSP) ;3 -- ud2lo ud2hi x x r-- IP adr count base
1886 POPM #4,IP ;6 -- ud2lo ud2hi x x W=base, T=count, S=adr, IP=prevIP r--
1887 TONUMPLUS ADD #1,S ;1
1889 JNZ TONUMLOOP ;2 -- ud2lo ud2hi x x S=adr+1, T=count-1, W=base 68 cycles char loop
1890 TONUMEND MOV S,0(PSP) ;3 -- ud2lo ud2hi adr2 count2
1891 MOV T,TOS ;1 -- ud2lo ud2hi adr2 count2
1892 mNEXT ;4 50/82 words/cycles, W = BASE
1894 ; ?NUMBER makes the interface between >NUMBER and INTERPRET; it's a subset of INTERPRET.
1895 ; convert a string to a signed number; FORTH 2012 prefixes $, %, # are recognized
1896 ; digits separator '_' is recognized
1897 ; with DOUBLE_INPUT switched ON, 32 bits numbers (with decimal point) are recognized
1898 ; with FIXPOINT_INPUT switched ON, Q15.16 signed numbers are recognized.
1899 ; prefixes # % $ and - are processed before calling >NUMBER
1900 ; not convertible chars '.' , ',' and '_' are processed as >NUMBER exits
1901 ;Z ?NUMBER addr -- n|d -1 if convert ok ; flag Z=0, UF9=1 if double
1902 ;Z addr -- addr 0 if convert ko ; flag Z=1
1903 ; FORTHWORD "?NUMBER"
1905 MOV &BASE,T ;3 T=BASE
1907 PUSHM #3,IP ;5 R-- IP sign base (push IP,S,T)
1908 MOV #TONUMEXIT,IP ;2 define >NUMBER return
1910 SUB #8,PSP ;1 -- x x x x addr
1911 MOV TOS,6(PSP) ;3 -- addr x x x addr
1913 MOV #0,2(PSP) ;3 -- addr ud=0 x addr
1915 MOV.B @S+,T ;2 -- addr ud=0 x x S=adr, T=count
1916 QNUMLDCHAR MOV.B @S,Y ;2 Y=char
1918 JLO QBINARY ;2 if char < '-'
1919 JNZ DDIGITQ ;2 if char > '-'
1920 MOV #-1,2(RSP) ;3 R-- IP sign base
1922 QBINARY MOV #2,W ;1 preset base 2
1923 SUB.B #'%',Y ;2 binary number ?
1925 QDECIMAL ADD #8,W ;1
1926 ADD.B #2,Y ;1 decimal number ?
1929 SUB.B #1,Y ;2 hex number ?
1930 JNZ TONUMLOOP ;2 -- addr ud=0 x x other cases will cause >NUMBER exit
1931 PREFIXED ADD #1,S ;1
1932 SUB #1,T ;1 -- addr ud=0 x x S=adr+1 T=count-1
1934 ; ----------------------------------;42
1935 TONUMEXIT FORTHtoASM ; -- addr ud2lo-hi addr2 cnt2 R-- IP sign BASE S=addr2,T=cnt2
1936 ; ----------------------------------;
1937 JZ QNUMNEXT ;2 if conversion is ok
1939 CMP.B #28h,Y ; rejected char by >NUMBER is a underscore ?
1940 JZ TONUMPLUS ; skip it
1941 .IFDEF DOUBLE_NUMBERS ; DOUBLE_NUMBERS = DOUBLE_INPUT | FIXPOINT_INPUT
1942 BIS #UF9,SR ;2 set double number flag
1945 CMP.B #0F7h,Y ;2 rejected char by >NUMBER is a decimal point ?
1946 JZ TONUMPLUS ;2 to terminate conversion
1948 .IFDEF FIXPOINT_INPUT ;
1949 CMP.B #0F5h,Y ;2 rejected char by >NUMBER is a comma ?
1950 JNZ QNUMNEXT ;2 no, that will be followed by abort on conversion error
1951 S15Q16 MOV #0,X ;1 -- addr ud2lo x 0 x init ud2lo' = 0
1952 S15Q16LOOP MOV X,2(PSP) ;3 -- addr ud2lo ud2lo' ud2lo' x X = 0(PSP) = ud2lo'
1953 SUB.B #1,T ;1 decrement cnt2
1954 MOV T,X ;1 X = cnt2-1
1955 ADD S,X ;1 X = end_of_string-1, first...
1956 MOV.B @X,X ;2 X = last char of string, first...
1957 SUB.B #30h,X ;2 char --> digit conversion
1963 QS15Q16DIGI CMP W,X ;1 R-- IP sign BASE, W=BASE, is X a digit ?
1964 JHS S15Q16EOC ;2 -- addr ud2lo ud2lo' x ud2lo' if no
1965 MOV X,0(PSP) ;3 -- addr ud2lo ud2lo' digit x
1966 MOV W,TOS ;1 -- addr ud2lo ud2lo' digit base R-- IP sign base
1967 PUSHM #3,S ;5 PUSH S,T,W: R-- IP sign base addr2 cnt2 base
1968 CALL #MUSMOD ;4 -- addr ud2lo ur uqlo uqhi
1969 POPM #3,S ;5 restore W,T,S: R-- IP sign BASE
1970 JMP S15Q16LOOP ;2 W=cnt
1971 S15Q16EOC MOV 4(PSP),2(PSP) ;5 -- addr ud2lo ud2lo uqlo x ud2lo from >NUMBER part1 becomes here ud2hi=S15 part2
1972 MOV @PSP,4(PSP) ;4 -- addr ud2lo ud2hi x x uqlo becomes ud2lo
1973 MOV T,TOS ;1 -- addr ud2lo ud2hi x cnt2
1974 CMP.B #0,TOS ;1 TOS = 0 if end of conversion char = ',' (happy end)
1976 ; ----------------------------------;97
1977 QNUMNEXT POPM #3,IP ;4 -- addr ud2lo-hi x cnt2 POPM T,S,IP S = sign flag = {-1;0}
1978 MOV S,TOS ;1 -- addr ud2lo-hi x sign
1980 JZ QNUMOK ;2 -- addr ud2lo-hi x sign conversion OK
1982 .IFDEF DOUBLE_NUMBERS
1985 ADD #6,PSP ;1 -- addr sign
1986 AND #0,TOS ;1 -- addr ff TOS=0 and Z=1 ==> conversion ko
1988 ; ----------------------------------;
1989 .IFDEF DOUBLE_NUMBERS
1990 QNUMOK ADD #2,PSP ;1 -- addr ud2lo ud2hi sign
1991 MOV 2(PSP),4(PSP) ; -- udlo udlo udhi sign
1992 MOV @PSP+,0(PSP) ;4 -- udlo udhi sign note : PSP is incremented before write back !!!
1993 XOR #-1,TOS ;1 -- udlo udhi inv(sign)
1994 JNZ QDOUBLE ;2 if jump : TOS=-1 and Z=0 ==> conversion ok
1995 Q2NEGATE XOR #-1,TOS ;1 -- udlo udhi tf
1999 ADDC #0,0(PSP) ;3 -- dlo dhi tf
2000 QDOUBLE BIT #UF9,SR ;2 -- dlo dhi tf decimal point added ?
2001 JNZ QNUMEND ;2 -- dlo dhi tf leave double
2002 ADD #2,PSP ;1 -- dlo tf leave number, Z=0
2003 QNUMEND mNEXT ;4 TOS=-1 and Z=0 ==> conversion ok
2005 QNUMOK ADD #4,PSP ;1 -- addr ud2lo sign
2006 MOV @PSP+,0(PSP) ;4 -- udlo sign note : PSP is incremented before write back !!!
2007 XOR #-1,TOS ;1 -- udlo udhi inv(sign)
2008 JNZ QNUMEND ;2 if jump : TOS=-1 and Z=0 ==> conversion ok
2009 QNEGATE XOR #-1,0(PSP) ;3
2010 ADD #1,0(PSP) ;3 -- n tf
2011 XOR #-1,TOS ;1 -- udlo udhi tf TOS=-1 and Z=0
2012 QNUMEND mNEXT ;4 TOS=-1 and Z=0 ==> conversion ok
2013 .ENDIF ; DOUBLE_NUMBERS
2014 ; ----------------------------------;128 words
2015 .ENDIF ; of Hardware/Software MPY
2017 ;https://forth-standard.org/standard/core/EXECUTE
2018 ;C EXECUTE i*x xt -- j*x execute Forth word at 'xt'
2020 EXECUTE MOV TOS,W ; 1 put word address into W
2021 MOV @PSP+,TOS ; 2 fetch new TOS
2022 MOV W,PC ; 3 fetch code address into PC
2024 ;https://forth-standard.org/standard/core/Comma
2025 ;C , x -- append cell to dict
2033 .IFDEF DOUBLE_NUMBERS ; are recognized
2034 ;https://forth-standard.org/standard/core/LITERAL
2035 ;C LITERAL n -- append single numeric literal if compiling state
2036 ; d -- append double numeric literal if compiling state and if UF9<>0 (not ANS)
2037 FORTHWORDIMM "LITERAL" ; immediate
2038 LITERAL CMP #0,&STATE ;3
2039 JZ LITERAL2 ;2 if not compiling state, clear UF9 flag then NEXT
2040 LITERAL1 MOV &DDP,W ;3
2045 BIT #UF9,SR ;2 double number ?
2046 LITERAL2 BIC #UF9,SR ;2 in all case, clear UF9
2055 ;https://forth-standard.org/standard/core/LITERAL
2056 ;C LITERAL n -- append single numeric literal if compiling state
2057 FORTHWORDIMM "LITERAL" ; immediate
2058 LITERAL CMP #0,&STATE ;3
2059 JZ LITERALEND ;2 if not immediate, leave n|d on the stack
2060 LITERAL1 MOV &DDP,W ;3
2068 ;https://forth-standard.org/standard/core/COUNT
2069 ;C COUNT c-addr1 -- adr len counted->adr/len
2074 MOV.B -1(TOS),TOS ;3
2077 ; : SETIB SOURCE 2! 0 >IN ! ; ; org len -- set Input Buffer, shared by INTERPRET and [ELSE]
2078 SETIB MOV TOS,&SOURCE_LEN ; -- org len
2079 MOV @PSP+,&SOURCE_ORG ; -- len
2084 ;C INTERPRET i*x addr u -- j*x interpret given buffer
2085 ; This is the common factor of EVALUATE and QUIT.
2086 ; set addr u as input buffer then parse it word by word
2089 INTLOOP .word FBLANK,WORDD ; -- c-addr Z = End Of Line
2091 MOV #INTFINDNEXT,IP ;2 define INTFINDNEXT as FIND return
2092 JNZ FIND ;2 Z=0, EOL not reached
2093 JMP DROPEXIT ; Z=1, EOL reached
2095 INTFINDNEXT FORTHtoASM ; -- c-addr fl Z = not found
2096 MOV TOS,W ; W = flag =(-1|0|+1) as (normal|not_found|immediate)
2097 MOV @PSP+,TOS ; -- c-addr
2098 MOV #INTQNUMNEXT,IP ;2 define QNUMBER return
2099 JZ QNUMBER ;2 c-addr -- Z=1, not found, search a number
2100 MOV #INTLOOP,IP ;2 define (EXECUTE | COMMA) return
2102 JZ COMMA ;2 c-addr -- if W xor STATE = 0 compile xt then loop back to INTLOOP
2103 JNZ EXECUTE ;2 c-addr -- if W xor STATE <>0 execute xt then loop back to INTLOOP
2105 INTQNUMNEXT FORTHtoASM ; -- n|c-addr fl Z = not a number, SR(UF9) double number request
2107 MOV #INTLOOP,IP ;2 -- n|c-addr define LITERAL return
2108 JNZ LITERAL ;2 n -- Z=0, is a number, execute LITERAL then loop back to INTLOOP
2110 NotFoundExe ADD.B #1,0(TOS) ;3 c-addr -- Z=1, Not a Number : incr string count to add '?'
2111 MOV.B @TOS,Y ;2 Y=count+1
2112 ADD TOS,Y ;1 Y=end of string addr
2113 MOV.B #'?',0(Y) ;5 add '?' to end of string
2114 MOV #FQABORTYES,IP ;2 define the return of COUNT
2115 JMP COUNT ;2 -- addr len 35 words
2117 ;https://forth-standard.org/standard/core/EVALUATE
2118 ; EVALUATE \ i*x c-addr u -- j*x interpret string
2119 FORTHWORD "EVALUATE"
2120 EVALUATE MOV #SOURCE_LEN,X ;2
2121 MOV @X+,S ;2 S = SOURCE_LEN
2122 MOV @X+,T ;2 T = SOURCE_ORG
2123 MOV @X+,W ;2 W = TOIN
2124 PUSHM #4,IP ;6 PUSHM IP,S,T,W
2129 MOV @RSP+,&SOURCE_ORG ;4
2130 MOV @RSP+,&SOURCE_LEN ;4
2133 .IFDEF DEFER_QUIT ; defined in ThingsInFirst.inc
2135 QUIT0 MOV #0,&SAVE_SYSRSTIV ; clear SAVE_SYSRSTIV, usefull for next ABORT...
2136 MOV #RSTACK,RSP ; ANS mandatory for QUIT
2137 MOV #LSTACK,&LEAVEPTR ;
2138 MOV #0,&STATE ; ANS mandatory for QUIT
2141 ;c BOOT -- load BOOT.4th file from SD_Card then loop to QUIT1
2143 CMP #0,&SAVE_SYSRSTIV ; = 0 if WARM
2144 JZ BODYQUIT ; no boostrap if no reset event, default QUIT instead
2145 BIT.B #SD_CD,&SD_CDIN ; SD_memory in SD_Card module ?
2146 JNZ BODYQUIT ; if not, no bootstrap, default QUIT instead
2149 MOV &SAVE_SYSRSTIV,TOS ; -- SAVE_SYSRSTIV TOS = reset event, for tests in BOOT.4TH
2153 .word XSQUOTE ; -- addr u
2154 .byte 15,"LOAD\34 BOOT.4TH\34" ; LOAD" BOOT.4TH" issues error 2 if no such file...
2155 .word BRAN,QUIT4 ; to interpret this string
2156 ; ----------------------------------;
2158 ;https://forth-standard.org/standard/core/QUIT
2159 ;c QUIT -- interpret line by line the input stream, primary DEFERred word
2160 ; to enable bootstrap type: ' BOOT IS QUIT
2161 ; to disable bootstrap type: ' QUIT >BODY IS QUIT
2164 QUIT MOV @PC+,PC ;3 Code Field Address (CFA) of QUIT
2165 PFAQUIT .word BODYQUIT ; Parameter Field Address (PFA) of QUIT
2166 BODYQUIT ASMtoFORTH ; BODY of QUIT = default execution of QUIT
2169 .ELSE ; if no BOOTLOADER, QUIT is not DEFERred
2171 ;https://forth-standard.org/standard/core/QUIT
2172 ;c QUIT -- interpret line by line the input stream
2175 QUIT0 MOV #0,&SAVE_SYSRSTIV ; clear SAVE_SYSRSTIV, usefull for next ABORT...
2176 MOV #RSTACK,RSP ; ANS mandatory for QUIT
2177 MOV #LSTACK,&LEAVEPTR ;
2178 MOV #0,&STATE ; ANS mandatory for QUIT
2184 QUIT1 .word XSQUOTE ;
2185 .byte 5,13,10,"ok " ; CR+LF + Forth prompt
2186 QUIT2 .word TYPE ; display it
2190 .word REFILL ; -- org len refill input buffer from ACCEPT (one line)
2192 QUIT4 .word INTERPRET ; interpret this line|string
2193 .word DEPTH,ZEROLESS ; stack empty test
2194 .word XSQUOTE ; ABORT" stack empty! "
2195 .byte 12,"stack empty!" ;
2197 .word lit,FRAM_FULL ;
2198 .word HERE,ULESS ; FRAM full test
2199 .word XSQUOTE ; ABORT" FRAM full! "
2200 .byte 10,"FRAM full!" ;
2203 .word FSTATE,FETCH ; STATE @
2204 .word QFBRAN,QUIT1 ; 0= case of interpretion state
2205 .word XSQUOTE ; 0<> case of compilation state
2206 .byte 5,13,10," " ; CR+LF + 3 spaces
2210 ;https://forth-standard.org/standard/core/ABORT
2211 ;C ABORT i*x -- R: j*x -- clear stack & QUIT
2213 ABORT MOV #PSTACK,PSP
2216 ;https://forth-standard.org/standard/core/ABORTq
2217 ;C ABORT" i*x flag -- i*x R: j*x -- j*x flag=0
2218 ;C i*x flag -- R: j*x -- flag<>0
2219 FORTHWORDIMM "ABORT\34" ; immediate
2220 ABORTQUOTE mDOCOL ; ABORT address + 10
2222 .word lit,QABORT,COMMA
2225 ; define run-time part of ABORT"
2226 ;Z ?ABORT f c-addr u -- abort & print msg,
2227 ; FORTHWORD "?ABORT"
2228 QABORT CMP #0,2(PSP) ; -- f c-addr u flag test
2230 THREEDROP ADD #4,PSP ;
2233 ; ----------------------------------; QABORTYES = QABORT + 14
2234 QABORTYES CALL #QAB_DEFER ; init some variables, see WIPE
2235 ; ----------------------------------;
2236 QABORT_SDCARD ; close all handles
2237 ; ----------------------------------;
2238 .IFDEF SD_CARD_LOADER ;
2240 QABORTCLOSE CMP #0,T ;
2242 MOV.B #0,HDLB_Token(T) ;
2247 ; ----------------------------------;
2248 QABORT_TERM ; wait the end of downloading source file
2249 ; ----------------------------------;
2250 CALL #RXON ; send XON and/or set RTS low
2251 QABORTLOOP BIC #UCRXIFG,&TERM_IFG ; clear UCRXIFG
2252 MOV #int(frequency*2730),Y ; 2730*frequency ==> 65520 @ 24MHz
2253 QABUSBLOOPJ MOV #8,X ; 1~ <-------+ windows 10 seems very slow... ==> 2730*37 = 101ms delay
2254 ADD X,X ; 1~ | linux seems very very slow... ==> 2730*69 = 188ms delay
2255 QABUSBLOOPI NOP ; 1~ <---+ |
2256 SUB #1,X ; 1~ | | the loop must be longer than longuest existing silence on terminal
2257 JNZ QABUSBLOOPI ; 2~ 4~ loop ---+ | i.e. when USB driver refill they buffers.
2259 JNZ QABUSBLOOPJ ; 2~ 37~/69~ loop --+
2260 BIT #UCRXIFG,&TERM_IFG ; 4 new char in TERMRXBUF after delay for refill ?
2261 JNZ QABORTLOOP ; 2 yes, the input stream is still active: loop back
2262 ; ----------------------------------;
2264 .word PWR_STATE ; remove all words beyond PWR_HERE, including a definition leading to an error
2265 .word lit,LINE,FETCH ; fetch line number before set ECHO !
2266 .word ECHO ; to see abort message
2267 .word XSQUOTE ; -- c-addr u c-addr1 u1
2268 .byte 4,27,"[7m" ; type ESC[7m (set reverse video)
2269 .word TYPE ; -- c-addr u
2271 .word QFBRAN,ERRLINE_END; if LINE = 0
2272 ; ----------------------------------;
2273 ; Display error line:xxx ; if LINE <> 0 (if NOECHO state before calling ABORT")
2274 ; ----------------------------------;
2276 .word XSQUOTE ; displays the line where error occured
2281 ERRLINE_END ; -- c-addr u
2282 ; ----------------------------------;
2283 ; Display ABORT" message ; <== WARM jumps here
2284 ; ----------------------------------;
2286 .word TYPE ; -- type abort message
2287 .word XSQUOTE ; -- c-addr u
2289 .word TYPE ; -- set normal video
2290 FABORT .word ABORT ; no return; FABORT = BRACTICK-8
2291 ; ----------------------------------;
2293 ;-------------------------------------------------------------------------------
2295 ;-------------------------------------------------------------------------------
2297 ;https://forth-standard.org/standard/core/BracketTick
2298 ;C ['] <name> -- find word & compile it as literal
2299 FORTHWORDIMM "[']" ; immediate word, i.e. word executed during compilation
2301 .word TICK ; get xt of <name>
2302 .word lit,lit,COMMA ; append LIT action
2303 .word COMMA,EXIT ; append xt literal
2305 ;https://forth-standard.org/standard/core/Tick
2306 ;C ' -- xt find word in dictionary and leave on stack its execution address
2308 TICK mDOCOL ; separator -- xt
2309 .word FBLANK,WORDD,FIND
2310 .word QFBRAN,NotFound
2312 NotFound .word NotFoundExe ; see INTERPRET
2314 ;https://forth-standard.org/standard/block/bs
2316 ; everything up to the end of the current line is a comment.
2317 FORTHWORDIMM "\\" ; immediate
2318 BACKSLASH MOV &SOURCE_LEN,&TOIN ;
2321 ;https://forth-standard.org/standard/core/Bracket
2322 ;C [ -- enter interpretative state
2323 FORTHWORDIMM "[" ; immediate
2324 LEFTBRACKET MOV #0,&STATE
2327 ;https://forth-standard.org/standard/core/right-bracket
2328 ;C ] -- enter compiling state
2330 RIGHTBRACKET MOV #-1,&STATE
2333 ;https://forth-standard.org/standard/core/DEFERStore
2334 ;C DEFER! xt CFA_DEFER -- ; store xt into the PFA of DEFERed word
2335 ; FORTHWORD "DEFER!"
2336 DEFERSTORE MOV @PSP+,2(TOS) ; -- CFA_DEFER xt --> [CFA_DEFER+2]
2340 ;https://forth-standard.org/standard/core/IS
2343 ; DEFER DISPLAY create a "do nothing" definition (2 CELLS)
2344 ; inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY
2345 ; or in a definition : ... ['] U. IS DISPLAY ...
2346 ; KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words
2348 ; as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words...
2350 FORTHWORDIMM "IS" ; immediate
2352 .word FSTATE,FETCH ; STATE @
2353 .word QFBRAN,IS_EXEC ; if = 0
2354 IS_COMPILE .word BRACTICK ; find the word, compile its CFA as literal
2355 .word lit,DEFERSTORE ;
2356 .word COMMA ; compile DEFERSTORE
2358 IS_EXEC .word TICK,DEFERSTORE ; find the word, leave its CFA on the stack and
2359 .word EXIT ; put it into PFA of DEFERed word, then exit.
2361 ;https://forth-standard.org/standard/core/IMMEDIATE
2362 ;C IMMEDIATE -- make last definition immediate
2363 FORTHWORD "IMMEDIATE"
2364 IMMEDIATE MOV &LAST_NFA,W
2368 ;https://forth-standard.org/standard/core/RECURSE
2369 ;C RECURSE -- recurse to current definition (compile current definition)
2370 FORTHWORDIMM "RECURSE" ; immediate
2371 RECURSE MOV &DDP,X ;
2372 MOV &LAST_CFA,0(X) ;
2376 ;https://forth-standard.org/standard/core/POSTPONE
2377 FORTHWORDIMM "POSTPONE" ; immediate
2379 .word FBLANK,WORDD,FIND,QDUP
2380 .word QFBRAN,NotFound
2381 .word ZEROLESS ; immediate word ?
2382 .word QFBRAN,POST1 ; if immediate
2383 .word lit,lit,COMMA ; else compile lit
2384 .word COMMA ; compile xt
2385 .word lit,COMMA ; CFA of COMMA
2386 POST1 .word COMMA,EXIT ; then compile: if immediate xt of word found else CFA of COMMA
2388 ;https://forth-standard.org/standard/core/Semi
2389 ;C ; -- end a colon definition
2390 FORTHWORDIMM ";" ; immediate
2391 SEMICOLON CMP #0,&STATE ; if interpret mode, semicolon becomes a comment separator
2392 JZ BACKSLASH ; tip: ";" is transparent to the preprocessor, so semicolon comments are kept in file.4th
2393 mDOCOL ; compile mode
2394 .word lit,EXIT,COMMA
2395 .word QREVEAL,LEFTBRACKET,EXIT
2398 ;https://forth-standard.org/standard/core/ColonNONAME
2401 COLONNONAME SUB #2,PSP
2403 MOV &DDP,TOS ; -- xt of this NONAME word
2405 MOV #PAIN,X ;2 MOV Y,0(X) writes to PAIN read only register = first lure for semicolon REVEAL...
2406 MOV #PAOUT,Y ;2 MOV @X,-2(Y) also writes to PAIN register = 2th lure for semicolon REVEAL...
2407 CALL #HEADEREND ; ...because we don't want write a preamble of this :NONAME definition in dictionnary!
2410 ;-----------------------------------; common part of NONAME and :
2414 MOV #DOCOL1,-4(W) ; compile CALL rDOCOL
2417 MOV #DOCOL1,-4(W) ; compile PUSH IP 3~
2418 MOV #DOCOL2,-2(W) ; compile CALL rEXIT
2419 .CASE 3 ; inlined DOCOL
2420 MOV #DOCOL1,-4(W) ; compile PUSH IP 3~
2421 MOV #DOCOL2,-2(W) ; compile MOV PC,IP 1~
2422 MOV #DOCOL3,0(W) ; compile ADD #4,IP 1~
2423 MOV #NEXT,+2(W) ; compile MOV @IP+,PC 4~
2426 MOV #-1,&STATE ; enter compiling state
2427 SAVE_PSP MOV PSP,&LAST_PSP ; save PSP for check compiling, used by QREVEAL
2429 ;-----------------------------------;
2432 ;https://forth-standard.org/standard/core/Colon
2433 ;C : <name> -- begin a colon definition
2435 COLON PUSH #COLONNEXT ; define COLONNEXT as RET from HEADER
2437 ; HEADER create an header for a new word. Max count of chars = 126
2438 ; common code for DEFER, VARIABLE, CONSTANT, CREATE, :, MARKER, CODE, ASM.
2439 ; doesn't link the created word in vocabulary.
2441 .word CELLPLUSALIGN ; align and make room for LFA
2442 .word FBLANK,WORDD ;
2443 FORTHtoASM ; -- HERE HERE is the NFA of this new word
2445 MOV TOS,Y ; -- NFA Y=NFA
2446 MOV.B @TOS+,W ; -- NFA+1 W=Count_of_chars
2447 BIS.B #1,W ; W=count is always odd
2448 ADD.B #1,W ; W=add one byte for length
2449 ADD Y,W ; W=Aligned_CFA
2450 MOV &CURRENT,X ; X=VOC_BODY of CURRENT
2452 .CASE 1 ; nothing to do
2453 .ELSECASE ; multithreading add 5~ 4words
2454 MOV.B @TOS,TOS ; -- char TOS=first CHAR of new word
2455 AND #(THREADS-1)*2,TOS ; -- offset TOS= Thread offset
2456 ADD TOS,X ; X=VOC_PFAx = thread x of VOC_PFA of CURRENT
2459 MOV #4030h,0(W) ; by default, HEADER create a DEFERred word: CFA = MOV @PC+,PC = BR mNEXT
2460 MOV #NEXT_ADR,2(W) ; by default, HEADER create a DEFERred word: PFA = address of mNEXT to do nothing.
2462 HEADEREND MOV Y,&LAST_NFA ; NFA --> LAST_NFA used by QREVEAL, IMMEDIATE, MARKER
2463 MOV X,&LAST_THREAD ; VOC_PFAx --> LAST_THREAD used by QREVEAL
2464 MOV W,&LAST_CFA ; HERE=CFA --> LAST_CFA used by DOES>, RECURSE
2465 ADD #4,W ; by default make room for two words...
2467 RET ; 30 words, W is the new DDP value )
2468 ; X is LAST_THREAD > used by VARIABLE, CONSTANT, CREATE, DEFER and :
2471 ;;Z ?REVEAL -- if no stack mismatch, link this new word in the CURRENT vocabulary
2472 ; FORTHWORD "REVEAL" ; used by SEMICOLON and ENDCODE
2473 QREVEAL CMP PSP,&LAST_PSP ; Check SP with its saved value by :
2474 JNZ BAD_CSP ; if no stack mismatch.
2475 GOOD_CSP MOV &LAST_NFA,Y ; GOOD_CSP is the end of word MARKER
2476 MOV &LAST_THREAD,X ;
2477 REVEAL MOV @X,-2(Y) ; [LAST_THREAD] --> LFA (for NONAME: [LAST_THREAD] --> PAIN)
2478 MOV Y,0(X) ; LAST_NFA --> [LAST_THREAD] (for NONAME: LAST_NFA --> PAIN)
2483 .byte 15,"stack mismatch!"
2484 FQABORTYES .word QABORTYES
2486 ;https://forth-standard.org/standard/core/VARIABLE
2487 ;C VARIABLE <name> -- define a Forth VARIABLE
2488 FORTHWORD "VARIABLE"
2489 VARIABLE CALL #HEADER ; W = DDP = CFA + 2 words
2490 MOV #DOVAR,-4(W) ; CFA = DOVAR, PFA is undefined
2491 JMP REVEAL ; to link created VARIABLE in vocabulary
2493 ;https://forth-standard.org/standard/core/CONSTANT
2494 ;C CONSTANT <name> n -- define a Forth CONSTANT (and also a Forth VALUE)
2495 FORTHWORD "CONSTANT"
2496 CONSTANT CALL #HEADER ; W = DDP = CFA + 2 words
2497 MOV #DOCON,-4(W) ; CFA = DOCON
2498 MOV TOS,-2(W) ; PFA = n
2500 JMP REVEAL ; to link created CONSTANT in vocabulary
2502 ;https://forth-standard.org/standard/core/CREATE
2503 ;C CREATE <name> -- define a CONSTANT with its next address
2504 ; Execution: ( -- a-addr ) ; a-addr is the address of name's data field
2505 ; ; the execution semantics of name may be extended by using DOES>
2507 CREATE CALL #HEADER ; -- W = DDP
2508 MOV #DOCON,-4(W) ;4 -4(W) = CFA = DOCON
2509 MOV W,-2(W) ;3 -2(W) = PFA = W = next address
2510 JMP REVEAL ; to link created VARIABLE in vocabulary
2512 ;https://forth-standard.org/standard/core/DOES
2513 ;C DOES> -- set action for the latest CREATEd definition
2515 DOES MOV &LAST_CFA,W ; W = CFA of CREATEd word
2516 MOV #DODOES,0(W) ; replace CFA (DOCON) by new CFA (DODOES)
2517 MOV IP,2(W) ; replace PFA by the address after DOES> as execution address
2518 mSEMI ; exit of the new created word
2520 ;https://forth-standard.org/standard/core/DEFER
2521 ;C DEFER "<spaces>name" --
2522 ;Skip leading space delimiters. Parse name delimited by a space.
2523 ;Create a definition for name with the execution semantics defined below.
2526 ;Execute the xt that name is set to execute, i.e. NEXT (nothing),
2527 ;until the phrase ' word IS name is executed, causing a new value of xt to be assigned to name.
2530 DEFER PUSH #REVEAL ; to link created DEFER word in vocabulary
2531 JMP HEADER ; that create a secondary DEFERed word (whithout default code)
2533 ;https://forth-standard.org/standard/core/toBODY
2534 ; >BODY -- addr leave BODY of a CREATEd word
2539 .IFDEF MSP430ASSEMBLER
2541 FORTHWORD "CODE" ; a CODE word must be finished with ENDCODE
2542 ASMCODE CALL #HEADER ;
2543 ASMCODE1 SUB #4,W ; W = CFA
2544 MOV W,&DDP ; CFA --> DDP
2547 .word ALSO,ASSEMBLER
2551 FORTHWORD "CODENNM" ; CODENoNaMe is the assembly counterpart of :NONAME
2553 .word COLONNONAME,LEFTBRACKET
2557 asmword "ENDCODE" ; restore previous context and test PSP balancing
2559 .word PREVIOUS,QREVEAL
2562 ; ASM and ENDASM are used to define an assembler word which is not executable by FORTH interpreter
2563 ; i.e. typically an assembler word called by CALL and ended by RET, or an interrupt routine ended by RETI.
2564 ; ASM words are only usable in another ASSEMBLER words
2565 ; any ASM word must be finished with ENDASM.
2566 ; The template " ASM ... COLON ... ; " or any other finishing by SEMICOLON is
2567 ; prohibited because it doesn't restore CURRENT.
2570 MOV &CURRENT,&SAV_CURRENT
2571 MOV #BODYASSEMBLER,&CURRENT
2574 asmword "ENDASM" ; end of an ASM word
2575 MOV &SAV_CURRENT,&CURRENT
2579 ; here are words used to switch from/to FORTH to/from ASSEMBLER
2581 asmword "COLON" ; compile DOCOL, remove ASSEMBLER from CONTEXT, switch to compilation state
2585 MOV #DOCOL1,0(W) ; compile CALL xDOCOL
2589 MOV #DOCOL1,0(W) ; compile PUSH IP
2590 COLON1 MOV #DOCOL2,2(W) ; compile CALL rEXIT
2593 .CASE 3 ; inlined DOCOL
2594 MOV #DOCOL1,0(W) ; compile PUSH IP
2595 COLON1 MOV #DOCOL2,2(W) ; compile MOV PC,IP
2596 MOV #DOCOL3,4(W) ; compile ADD #4,IP
2597 MOV #NEXT,6(W) ; compile MOV @IP+,PC
2601 COLON2 MOV #-1,&STATE ; enter in compile state
2602 MOV #PREVIOUS,PC ; restore previous state of CONTEXT
2605 asmword "LO2HI" ; same as COLON but without saving IP
2607 .CASE 1 ; compile 2 words
2609 MOV #12B0h,0(W) ; compile CALL #EXIT, 2 words 4+6=10~
2613 .ELSECASE ; CASE 2 : compile 1 word, CASE 3 : compile 3 words
2614 SUB #2,&DDP ; to skip PUSH IP
2619 FORTHWORDIMM "HI2LO" ; immediate, switch to low level, add ASSEMBLER context, set interpretation state
2621 HI2LO .word HERE,CELLPLUS,COMMA
2623 HI2LONEXT .word ALSO,ASSEMBLER
2626 .ENDIF ; MSP430ASSEMBLER
2628 ; ------------------------------------------------------------------------------
2629 ; CONTROL STRUCTURES
2630 ; ------------------------------------------------------------------------------
2631 ; THEN and BEGIN compile nothing
2632 ; DO compile one word
2633 ; IF, ELSE, AGAIN, UNTIL, WHILE, REPEAT, LOOP & +LOOP compile two words
2634 ; LEAVE compile three words
2636 ;https://forth-standard.org/standard/core/IF
2637 ;C IF -- IFadr initialize conditional forward branch
2638 FORTHWORDIMM "IF" ; immediate
2641 MOV &DDP,TOS ; -- HERE
2642 ADD #4,&DDP ; compile one word, reserve one word
2643 MOV #QFBRAN,0(TOS) ; -- HERE compile QFBRAN
2644 CELLPLUS ADD #2,TOS ; -- HERE+2=IFadr
2647 ;https://forth-standard.org/standard/core/ELSE
2648 ;C ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack
2649 FORTHWORDIMM "ELSE" ; immediate
2650 ELSS ADD #4,&DDP ; make room to compile two words
2651 MOV &DDP,W ; W=HERE+4
2653 MOV W,0(TOS) ; HERE+4 ==> [IFadr]
2655 MOV W,TOS ; -- ELSEadr
2658 ;https://forth-standard.org/standard/core/THEN
2659 ;C THEN IFadr -- resolve forward branch
2660 FORTHWORDIMM "THEN" ; immediate
2661 THEN MOV &DDP,0(TOS) ; -- IFadr
2665 ;https://forth-standard.org/standard/core/BEGIN
2666 ;C BEGIN -- BEGINadr initialize backward branch
2667 FORTHWORDIMM "BEGIN" ; immediate
2668 BEGIN MOV #HERE,PC ; BR HERE
2670 ;https://forth-standard.org/standard/core/UNTIL
2671 ;C UNTIL BEGINadr -- resolve conditional backward branch
2672 FORTHWORDIMM "UNTIL" ; immediate
2674 UNTIL1 ADD #4,&DDP ; compile two words
2675 MOV &DDP,W ; W = HERE
2676 MOV X,-4(W) ; compile Bran or QFBRAN at HERE
2677 MOV TOS,-2(W) ; compile bakcward adr at HERE+2
2681 ;https://forth-standard.org/standard/core/AGAIN
2682 ;X AGAIN BEGINadr -- resolve uncondionnal backward branch
2683 FORTHWORDIMM "AGAIN" ; immediate
2687 ;https://forth-standard.org/standard/core/WHILE
2688 ;C WHILE BEGINadr -- WHILEadr BEGINadr
2689 FORTHWORDIMM "WHILE" ; immediate
2693 ;https://forth-standard.org/standard/core/REPEAT
2694 ;C REPEAT WHILEadr BEGINadr -- resolve WHILE loop
2695 FORTHWORDIMM "REPEAT" ; immediate
2697 .word AGAIN,THEN,EXIT
2699 ;https://forth-standard.org/standard/core/DO
2700 ;C DO -- DOadr L: -- 0
2701 FORTHWORDIMM "DO" ; immediate
2704 ADD #2,&DDP ; make room to compile xdo
2705 MOV &DDP,TOS ; -- HERE+2
2706 MOV #xdo,-2(TOS) ; compile xdo
2707 ADD #2,&LEAVEPTR ; -- HERE+2 LEAVEPTR+2
2709 MOV #0,0(W) ; -- HERE+2 L-- 0
2712 ;https://forth-standard.org/standard/core/LOOP
2713 ;C LOOP DOadr -- L-- an an-1 .. a1 0
2714 FORTHWORDIMM "LOOP" ; immediate
2716 LOOPNEXT ADD #4,&DDP ; make room to compile two words
2718 MOV X,-4(W) ; xloop --> HERE
2719 MOV TOS,-2(W) ; DOadr --> HERE+2
2720 ; resolve all "leave" adr
2721 LEAVELOOP MOV &LEAVEPTR,TOS ; -- Adr of top LeaveStack cell
2722 SUB #2,&LEAVEPTR ; --
2723 MOV @TOS,TOS ; -- first LeaveStack value
2724 CMP #0,TOS ; -- = value left by DO ?
2726 MOV W,0(TOS) ; move adr after loop as UNLOOP adr
2728 LOOPEND MOV @PSP+,TOS
2731 ;https://forth-standard.org/standard/core/PlusLOOP
2732 ;C +LOOP adrs -- L-- an an-1 .. a1 0
2733 FORTHWORDIMM "+LOOP" ; immediate
2734 PLUSLOOP MOV #xploop,X
2737 ;https://forth-standard.org/standard/core/LEAVE
2738 ;C LEAVE -- L: -- adrs
2739 FORTHWORDIMM "LEAVE" ; immediate
2740 LEAV MOV &DDP,W ; compile three words
2741 MOV #UNLOOP,0(W) ; [HERE] = UNLOOP
2742 MOV #BRAN,2(W) ; [HERE+2] = BRAN
2743 ADD #6,&DDP ; [HERE+4] = After LOOP adr
2747 MOV W,0(X) ; leave HERE+4 on LEAVEPTR stack
2750 ;https://forth-standard.org/standard/core/MOVE
2751 ;C MOVE addr1 addr2 u -- smart move
2752 ; VERSION FOR 1 ADDRESS UNIT = 1 CHAR
2754 MOVE MOV TOS,W ; W = cnt
2755 MOV @PSP+,Y ; Y = addr2 = dst
2756 MOV @PSP+,X ; X = addr1 = src
2757 MOV @PSP+,TOS ; pop new TOS
2759 JZ MOVE_X ; already done !
2760 CMP X,Y ; Y-X ; dst - src
2761 JZ MOVE_X ; already done !
2762 JC MOVEUP ; U>= if dst > src
2763 MOVEDOWN MOV.B @X+,0(Y) ; if X=src > Y=dst copy W bytes
2773 MOVUP2 MOV.B @X,0(Y) ; if X=src < Y=dst copy W bytes beginning with the end
2779 ;-------------------------------------------------------------------------------
2780 ; WORDS SET for VOCABULARY, not ANS compliant
2781 ;-------------------------------------------------------------------------------
2783 ;X VOCABULARY -- create a vocabulary, up to 7 vocabularies in CONTEXT
2785 .IFDEF VOCABULARY_SET
2787 FORTHWORD "VOCABULARY"
2792 .word lit,0,COMMA ; will keep the NFA of the last word of the future created vocabularies
2794 .word lit,THREADS,lit,0,xdo
2795 VOCABULOOP .word lit,0,COMMA
2796 .word xloop,VOCABULOOP
2798 .word HERE ; link via LASTVOC the future created vocabulary
2799 .word LIT,LASTVOC,DUP
2800 .word FETCH,COMMA ; compile [LASTVOC] to HERE+
2801 .word STORE ; store (HERE - CELL) to LASTVOC
2802 .word DOES ; compile CFA and PFA for the future defined vocabulary
2804 .ENDIF ; VOCABULARY_SET
2806 VOCDOES .word LIT,CONTEXT,STORE
2809 ;X FORTH -- ; set FORTH the first context vocabulary; FORTH is and must be the first vocabulary
2810 .IFDEF VOCABULARY_SET
2812 .ENDIF ; VOCABULARY_SET
2813 FORTH ; leave BODYFORTH on the stack and run VOCDOES
2814 mDODOES ; Code Field Address (CFA) of FORTH
2815 PFAFORTH .word VOCDOES ; Parameter Field Address (PFA) of FORTH
2816 BODYFORTH ; BODY of FORTH
2820 .word lastforthword1
2822 .word lastforthword1
2823 .word lastforthword2
2824 .word lastforthword3
2826 .word lastforthword1
2827 .word lastforthword2
2828 .word lastforthword3
2829 .word lastforthword4
2830 .word lastforthword5
2831 .word lastforthword6
2832 .word lastforthword7
2834 .word lastforthword1
2835 .word lastforthword2
2836 .word lastforthword3
2837 .word lastforthword4
2838 .word lastforthword5
2839 .word lastforthword6
2840 .word lastforthword7
2841 .word lastforthword8
2842 .word lastforthword9
2843 .word lastforthword10
2844 .word lastforthword11
2845 .word lastforthword12
2846 .word lastforthword13
2847 .word lastforthword14
2848 .word lastforthword15
2850 .word lastforthword1
2851 .word lastforthword2
2852 .word lastforthword3
2853 .word lastforthword4
2854 .word lastforthword5
2855 .word lastforthword6
2856 .word lastforthword7
2857 .word lastforthword8
2858 .word lastforthword9
2859 .word lastforthword10
2860 .word lastforthword11
2861 .word lastforthword12
2862 .word lastforthword13
2863 .word lastforthword14
2864 .word lastforthword15
2865 .word lastforthword16
2866 .word lastforthword17
2867 .word lastforthword18
2868 .word lastforthword19
2869 .word lastforthword20
2870 .word lastforthword21
2871 .word lastforthword22
2872 .word lastforthword23
2873 .word lastforthword24
2874 .word lastforthword25
2875 .word lastforthword26
2876 .word lastforthword27
2877 .word lastforthword28
2878 .word lastforthword29
2879 .word lastforthword30
2880 .word lastforthword31
2882 .word voclink ; here, voclink = 0
2886 .IFDEF MSP430ASSEMBLER
2887 ;X ASSEMBLER -- ; set ASSEMBLER the first context vocabulary
2888 .IFDEF VOCABULARY_SET
2889 FORTHWORD "ASSEMBLER"
2890 .ENDIF ; VOCABULARY_SET
2891 ASSEMBLER mDODOES ; leave BODYASSEMBLER on the stack and run VOCDOES
2893 BODYASSEMBLER .word lastasmword ; here is the structure created by VOCABULARY
2961 .ENDIF ; MSP430ASSEMBLER
2963 ;X ALSO -- make room to put a vocabulary as first in context
2964 .IFDEF VOCABULARY_SET
2966 .ENDIF ; VOCABULARY_SET
2967 ALSO MOV #12,W ; -- move up 6 words, 8th word of CONTEXT area must remain to 0
2968 MOV #CONTEXT,X ; X=src
2969 MOV #CONTEXT+2,Y ; Y=dst
2970 JMP MOVEUP ; src < dst
2972 ;X PREVIOUS -- pop last vocabulary out of context
2973 .IFDEF VOCABULARY_SET
2974 FORTHWORD "PREVIOUS"
2975 .ENDIF ; VOCABULARY_SET
2976 PREVIOUS MOV #14,W ; move down 7 words, with recopy of the 8th word equal to 0
2977 MOV #CONTEXT+2,X ; X=src
2978 MOV #CONTEXT,Y ; Y=dst
2979 JMP MOVEDOWN ; src > dst
2981 ;X ONLY -- cut context list to access only first vocabulary, ex.: FORTH ONLY
2982 .IFDEF VOCABULARY_SET
2984 .ENDIF ; VOCABULARY_SET
2985 ONLY MOV #0,&CONTEXT+2
2988 ;X DEFINITIONS -- set last context vocabulary as entry for further defining words
2989 .IFDEF VOCABULARY_SET
2990 FORTHWORD "DEFINITIONS"
2991 .ENDIF ; VOCABULARY_SET
2992 DEFINITIONS MOV &CONTEXT,&CURRENT
2995 ; ------------------------------------------------------------------------------
2996 ; forthMSP430FR : CONDITIONNAL COMPILATION
2997 ; ------------------------------------------------------------------------------
2999 .include "forthMSP430FR_CONDCOMP.asm"
3001 ; compile COMPARE [THEN] [ELSE] [IF] [UNDEFINED] [DEFINED] MARKER
3004 ; ------------------------------------------------------------------------------
3005 ;-------------------------------------------------------------------------------
3006 ; IMPROVED ON/OFF AND RESET
3007 ;-------------------------------------------------------------------------------
3009 STATE_DOES ; execution part of PWR_STATE ; sorry, doesn't restore search order pointers
3012 FORTHtoASM ; -- BODY IP is free
3013 MOV @TOS+,W ; -- BODY+2 W = old VOCLINK = VLK
3014 MOV W,&LASTVOC ; restore LASTVOC
3015 MOV @TOS,TOS ; -- OLD_DP
3016 MOV TOS,&DDP ; -- DP restore DP
3017 ; then restore words link(s) with it value < old DP
3019 .CASE 1 ; mono thread vocabularies
3020 MARKALLVOC MOV W,Y ; -- DP W=VLK Y=VLK
3021 MRKWORDLOOP MOV -2(Y),Y ; -- DP W=VLK Y=NFA
3022 CMP Y,TOS ; -- DP CMP = TOS-Y : OLD_DP-NFA
3023 JNC MRKWORDLOOP ; loop back if TOS<Y : OLD_DP<NFA
3024 MOV Y,-2(W) ; W=VLK X=THD Y=NFA refresh thread with good NFA
3025 MOV @W,W ; -- DP W=[VLK] = next voclink
3026 CMP #0,W ; -- DP W=[VLK] = next voclink end of vocs ?
3027 JNZ MARKALLVOC ; -- DP W=VLK no : loopback
3029 .ELSECASE ; multi threads vocabularies
3030 MARKALLVOC MOV #THREADS,IP ; -- DP W=VLK
3031 MOV W,X ; -- DP W=VLK X=VLK
3032 MRKTHRDLOOP MOV X,Y ; -- DP W=VLK X=VLK Y=VLK
3033 SUB #2,X ; -- DP W=VLK X=THD (thread ((case-2)to0))
3034 MRKWORDLOOP MOV -2(Y),Y ; -- DP W=VLK Y=NFA
3035 CMP Y,TOS ; -- DP CMP = TOS-Y : DP-NFA
3036 JNC MRKWORDLOOP ; loop back if TOS<Y : DP<NFA
3037 MARKTHREAD MOV Y,0(X) ; W=VLK X=THD Y=NFA refresh thread with good NFA
3038 SUB #1,IP ; -- DP W=VLK X=THD Y=NFA IP=CFT-1
3039 JNZ MRKTHRDLOOP ; loopback to compare NFA in next thread (thread-1)
3040 MOV @W,W ; -- DP W=[VLK] = next voclink
3041 CMP #0,W ; -- DP W=[VLK] = next voclink end of vocs ?
3042 JNZ MARKALLVOC ; -- DP W=VLK no : loopback
3044 .ENDCASE ; of THREADS ; -- DP
3049 FORTHWORD "PWR_STATE" ; executed by power ON, reinitializes dictionary in state defined by PWR_HERE
3050 PWR_STATE mDODOES ; DOES part of MARKER : resets pointers DP, voclink and latest
3051 .word STATE_DOES ; execution vector of PWR_STATE
3052 MARKVOC .word lastvoclink ; initialised by forthMSP430FR.asm as voclink value
3053 MARKDP .word ROMDICT ; initialised by forthMSP430FR.asm as DP value
3055 FORTHWORD "RST_STATE" ; executed by <reset>, reinitializes dictionary in state defined by RST_HERE
3056 RST_STATE MOV &INIVOC,&MARKVOC ; INIT value above (FRAM value)
3057 MOV &INIDP,&MARKDP ; INIT value above (FRAM value)
3060 FORTHWORD "PWR_HERE" ; define dictionnary bound for power ON
3061 PWR_HERE MOV &LASTVOC,&MARKVOC
3065 FORTHWORD "RST_HERE" ; define dictionnary bound for <reset>...
3066 RST_HERE MOV &LASTVOC,&INIVOC
3068 JMP PWR_HERE ; ...and obviously same bound for power ON...
3070 FORTHWORD "WIPE" ; restore the program as it was in forthMSP430FR.txt file
3071 WIPE ; reset JTAG and BSL signatures ; unlock JTAG, SBW and BSL
3072 MOV #16,X ; max known SIGNATURES length = 16
3074 MOV #-1,SIGNATURES(X) ; reset signature; WARNING ! DON'T CHANGE THIS IMMEDIATE VALUE !
3076 MOV #BODYSLEEP,&PFASLEEP ;4 MOV #SLEEP,X ADD #4,X MOV X,-2(X), restore default background task
3077 MOV #BODYWARM,&PFAWARM ;4 ' WARM >BODY IS WARM, restore default WARM
3078 .IFDEF DEFER_QUIT ; true if BOOTLOADER
3079 MOV #BODYQUIT,&PFAQUIT ;4 ' QUIT >BODY IS QUIT
3081 MOV #lastvoclink,&INIVOC ; reinit this 2 factory values
3083 PUSH #RST_STATE ; define the next of WIPE
3084 ;-----------------------------------;
3085 ; WIPE, QABORT common subroutine ; <--- ?ABORT calls here
3086 ;-----------------------------------;
3088 MOV #BODYEMIT,&PFAEMIT ;4 ' EMIT >BODY IS EMIT default console output
3089 MOV #BODYCR,&PFACR ;4 ' CR >BODY IS CR default CR
3090 MOV #BODYKEY,&PFAKEY ;4 ' KEY >BODY IS KEY default KEY
3091 .IFDEF DEFER_ACCEPT ; true if SD_LOADER
3092 MOV #BODYACCEPT,&PFAACCEPT ;4 ' ACCEPT >BODY IS ACCEPT
3093 MOV #TIB_ORG,&PFACIB ;4 TIB_ORG TO CIB (Current Input Buffer)
3095 ;-----------------------------------;
3096 ; WIPE, QABORT, COLD common subrouti; <--- COLD, reset and PUC calls here
3097 ;-----------------------------------;
3099 MOV #CPUOFF+GIE,&LPM_MODE ; set LPM0
3108 MOV #xdodoes,rDODOES
3109 .IFDEF MSP430ASSEMBLER
3110 MOV #RAM_ASM_LEN,X ; reset all 6 branch labels + SAVECURRENT + RPT_WORD if any
3113 MOV #0,RAM_ASM_ORG(X) ;
3117 MOV #32,&CAPS ; init CAPS ON
3119 ;-----------------------------------;
3121 ; --------------------------------------------------------------------------------
3122 ; forthMSP430FR : WARM
3123 ; --------------------------------------------------------------------------------
3125 ;Z WARM -- ; deferred word, enabling the initialisation of your application
3127 WARM MOV @PC+,PC ;3 Code Field Address (CFA) of WARM
3128 PFAWARM .word BODYWARM ; Parameter Field Address of WARM, may be redirected.
3129 BODYWARM MOV @PC+,IP ; MOV [BODYWARM+2],IP
3130 .word WARMTYPE ; define next step of WARM, examples: WARMTYPE, ABORT, BOOT...
3132 ;=================================================================================
3133 ; WARM 1: activates I/O: inputs and outputs are active only here (hiZ before here)
3134 ;=================================================================================
3135 BIC #LOCKLPM5,&PM5CTL0 ; activate all previous I/O settings (before I/O tests below).
3136 ; Moved in WARM area to be redirected in your app START routine,
3137 ; enabling you full control of the I/O RESET state.
3138 ;=================================================================================
3139 MOV &SAVE_SYSRSTIV,TOS ;
3140 CMP #0,TOS ; WARM event ?
3141 JZ RST_SEL_END ; yes
3142 ;---------------------------------------------------------------------------------
3143 ; RESET 7: test DEEP RESET before init TERMINAL I/O
3144 ;---------------------------------------------------------------------------------
3146 BIT.B #TXD,&TERM_IN ; TERM_TXD wired to GND via 4k7 resistor ?
3147 JNZ RST_TERM_IO ; no
3148 XOR #-1,TOS ; yes : force DEEP_RST (RESET + WIPE)
3149 ADD #1,TOS ; to display SAVE_SYSRSTIV as negative value
3150 ;---------------------------------------------------------------------------------
3151 ; RESET 8: INIT TERMINAL I/O
3152 ;---------------------------------------------------------------------------------
3154 BIS.B #TERM_BUS,&TERM_SEL ; Configure pins TXD & RXD for TERM_UART
3155 ;---------------------------------------------------------------------------------
3156 ; RESET 9: INIT SD_Card
3157 ;---------------------------------------------------------------------------------
3158 .IFDEF SD_CARD_LOADER ;
3159 BIT.B #SD_CD,&SD_CDIN ; SD_memory in SD_Card module ?
3161 .IF RAM_LEN < 2048 ; case of MSP430FR57xx : SD datas are in FRAM
3162 MOV #SD_LEN,X ; not initialised by RESET.
3163 ClearSDdata SUB #2,X ; 1
3164 MOV #0,SD_ORG(X) ; 3
3167 .include "forthMSP430FR_SD_INIT.asm"; no use IP,TOS
3169 ;---------------------------------------------------------------------------------
3170 ; RESET 10, RESET events handler: Select POWER_ON|<reset>|DEEP_RST
3171 ;---------------------------------------------------------------------------------
3172 RST_SEL CMP #0Ah,TOS ; SYSRSTIV = security violation: access of protected areas.
3173 JZ WIPE ; Add WIPE to this reset to do DEEP_RST
3174 CMP #16h,TOS ; SYSRSTIV > software POR : failure or DEEP_RST request
3175 JHS WIPE ; yes, reset event adds WIPE to this reset to do DEEP_RST
3176 CMP #2,TOS ; SYSRSTIV = BOR ?
3177 JZ PWR_STATE ; yes execute PWR_STATE, return to [BODYWARM+2]
3178 JHS RST_STATE ; if SYSRSTIV > BOR execute RST_STATE, return to [BODYWARM+2]
3179 RST_SEL_END mNEXT ; if SYSRSTIV = 1|0 return to [BODYWARM+2]
3181 ;---------------------------------------------------------------------------------
3182 ; WARM 2: type message on console output (if ECHO)
3183 ;---------------------------------------------------------------------------------
3184 WARMTYPE .word XSQUOTE ;
3185 .byte 6,13,1Bh,"[7m#" ; CR + cmd "reverse video" + #
3187 .word DOT ; display signed SAVE_SYSRSTIV
3189 .byte 31,"FastForth ",VER," (C)J.M.Thoorens "
3191 .word LIT,SIGNATURES,HERE,MINUS,UDOT
3193 .byte 11,"bytes free ";
3194 .word BRAN,QABORT_DISPLAY ;
3196 ;Z COLD -- performs a software reset
3198 COLD BIT #1,&TERM_STATW ;
3199 JNZ COLD ; loop back while TERM_UART is busy
3200 MOV #0A504h,&PMMCTL0 ; performs BOR (SYSRSTIV = #6) reset @ next address
3201 ; MOV #0A508h,&PMMCTL0 ; performs POR (SYSRSTIV = #20) reset @ next address
3203 ;---------------------------------------------------------------------------------
3204 ; RESET 1: Initialisation limited to FastForth usage : I/O, RAM, RTC
3205 ; all unused I/O are set as input with pullup resistor
3206 ;---------------------------------------------------------------------------------
3207 RESET .include "TargetInit.asm" ; include target specific FastForth init code
3208 ;---------------------------------------------------------------------------------
3210 ;---------------------------------------------------------------------------------
3212 INITRAMLOOP SUB #2,X
3214 JNZ INITRAMLOOP ; 6~ loop
3215 ;---------------------------------------------------------------------------------
3216 ; RESET 3: set all interrupt vectors
3217 ;---------------------------------------------------------------------------------
3218 MOV #VECT_LEN,X ;2 length of vectors area
3219 VECTORLOOP SUB #2,X ;1
3220 MOV #RESET,VECT_ORG(X) ;4 begin at end of area
3221 JNZ VECTORLOOP ;2 endloop when VECT_ORG(X) = VECT_ORG
3222 MOV #TERMINAL_INT,&TERM_VEC
3223 ;---------------------------------------------------------------------------------
3224 ; RESET 4: INIT TERM_UART UC
3225 ;---------------------------------------------------------------------------------
3226 MOV #0081h,&TERM_CTLW0 ; UC SWRST + UCLK = SMCLK
3227 MOV &TERMBRW_RST,&TERM_BRW ; RST value in FRAM
3228 MOV &TERMMCTLW_RST,&TERM_MCTLW ; RST value in FRAM
3229 BIC #UCSWRST,&TERM_CTLW0 ; release from reset...
3230 BIS #UCRXIE,&TERM_IE ; ... then enable RX interrupt for wake up on terminal input
3231 ;-------------------------------------------------------------------------------
3232 ; RESET 5: optionnal INIT SD_CARD UC
3233 ;-------------------------------------------------------------------------------
3234 .IFDEF SD_CARD_LOADER ;
3235 MOV #0A981h,&SD_CTLW0 ; UCxxCTL1 = CKPH, MSB, MST, SPI_3, SMCLK + UCSWRST
3236 MOV #FREQUENCY*3,&SD_BRW ; UCxxBRW init SPI CLK = 333 kHz ( < 400 kHz) for SD_Card init
3237 BIS.B #SD_CS,&SD_CSDIR ; SD_CS as output high
3238 BIS #SD_BUS,&SD_SEL ; Configure pins as SIMO, SOMI & SCK (PxDIR.y are controlled by eUSCI module)
3239 BIC #1,&SD_CTLW0 ; release eUSCI from reset
3241 ;---------------------------------------------------------------------------------
3242 ; RESET 6: INIT FORTH machine
3243 ;---------------------------------------------------------------------------------
3244 MOV #PSTACK,PSP ; init parameter stack
3245 MOV #RSTACK,RSP ; init return stack
3246 PUSH #WARM ; return for RST_INIT
3249 ;-------------------------------------------------------------------------------
3251 ;-------------------------------------------------------------------------------
3252 .IFDEF MSP430ASSEMBLER
3254 .include "forthMSP430FR_EXTD_ASM.asm"
3256 .include "forthMSP430FR_ASM.asm"
3262 ;-------------------------------------------------------------------------------
3263 ; FIXED POINT OPERATORS OPTION
3264 ;-------------------------------------------------------------------------------
3266 .include "ADDON/FIXPOINT.asm"
3269 ;-------------------------------------------------------------------------------
3270 ; SD CARD FAT OPTIONS
3271 ;-------------------------------------------------------------------------------
3272 .IFDEF SD_CARD_LOADER
3273 .include "forthMSP430FR_SD_LowLvl.asm" ; SD primitives
3274 .include "forthMSP430FR_SD_LOAD.asm" ; SD LOAD driver
3275 ;-----------------------------------------------------------------------
3277 ;-----------------------------------------------------------------------
3279 .include "ADDON/SD_TOOLS.asm"
3281 ;---------------------------------------------------------------------------
3282 ; SD CARD READ WRITE
3283 ;---------------------------------------------------------------------------
3284 .IFDEF SD_CARD_READ_WRITE
3285 .include "forthMSP430FR_SD_RW.asm" ; SD Read/Write driver
3289 ;-------------------------------------------------------------------------------
3290 ; UTILITY WORDS OPTION
3291 ;-------------------------------------------------------------------------------
3293 .include "ADDON/UTILITY.asm"
3296 ;-------------------------------------------------------------------------------
3297 ; ADD HERE YOUR CODE TO BE INTEGRATED IN KERNEL (protected against WIPE)
3298 ;vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
3302 ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3303 ; ADD HERE YOUR CODE TO BE INTEGRATED IN KERNEL (protected against WIPE)
3304 ;-------------------------------------------------------------------------------
3306 ;-------------------------------------------------------------------------------
3307 ; RESOLVE ASSEMBLY PTR
3308 ;-------------------------------------------------------------------------------
3310 .include "ThingsInLast.inc"