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) <2017> <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 .include "mspregister.mac" ;
25 ; macexp off ; uncomment to hide macro results
29 ;-------------------------------------------------------------------------------
30 ; Vingt fois sur le métier remettez votre ouvrage,
31 ; Polissez-le sans cesse, et le repolissez,
32 ; Ajoutez quelquefois, et souvent effacez.
33 ; Boileau, L'Art poétique
34 ;-------------------------------------------------------------------------------
36 ;===============================================================================
37 ;===============================================================================
38 ; before assembling or programming you must set TARGET in param1 (SHIFT+F8)
39 ; according to the TARGET "switched" below
40 ;===============================================================================
41 ;===============================================================================
43 ;-------------------------------------------------------------------------------
44 ; TARGETS kernel ; sizes are for 8MHz, DTC=2, 3WIRES (XON/XOFF)
45 ;-------------------------------------------------------------------------------
47 ;MSP_EXP430FR5739 ; compile for MSP-EXP430FR5739 launchpad ; 26 + 3962 bytes
48 ;MSP_EXP430FR5969 ; compile for MSP-EXP430FR5969 launchpad ; 26 + 3950 bytes
49 ;MSP_EXP430FR5994 ; compile for MSP-EXP430FR5994 launchpad ; 26 + 3968 bytes
50 ;MSP_EXP430FR6989 ; compile for MSP-EXP430FR6989 launchpad ; 26 + 3978 bytes
51 ;MSP_EXP430FR4133 ; compile for MSP-EXP430FR4133 launchpad ; 26 + 4012 bytes
52 MSP_EXP430FR2355 ;; compile for MSP-EXP430FR2355 launchpad ; 26 + 3944 bytes
53 ;MSP_EXP430FR2433 ; compile for MSP-EXP430FR2433 launchpad ; 26 + 3930 bytes
54 ;CHIPSTICK_FR2433 ; compile for the "CHIPSTICK" of M. Ken BOAK ; 26 + 3922 bytes
56 ; choose DTC (Direct Threaded Code) model, if you don't know, choose 2
57 DTC .equ 2 ; DTC model 1 : DOCOL = CALL rDOCOL 14 cycles 1 word shortest DTC model
58 ; DTC model 2 : DOCOL = PUSH IP, CALL rEXIT 13 cycles 2 words good compromize for mix FORTH/ASM code
59 ; DTC model 3 : inlined DOCOL 9 cycles 4 words fastest
61 THREADS .equ 16 ; 1, 2 , 4 , 8 , 16, 32 search entries in dictionnary.
62 ; +0, +28, +40, +56, +90, +154 bytes, usefull to speed compilation;
65 FREQUENCY .equ 24 ; fully tested at 0.25,0.5,1,2,4,8,16 (and 24 for MSP430FR57xx) MHz
67 ;-------------------------------------------------------------------------------
68 ; KERNEL ADD-ON SWITCHES
69 ;-------------------------------------------------------------------------------
70 MSP430ASSEMBLER ;; + 1814 bytes : adds embedded assembler with TI syntax; without, you can do all but all much more slowly...
71 CONDCOMP ;; + 324 bytes : adds conditionnal compilation : MARKER [UNDEFINED] [DEFINED] [IF] [ELSE] [THEN] COMPARE
72 FIXPOINT_INPUT ;; + 78 bytes : adds the interpretation input for S15.16 numbers, mandatory for FIXPOINT
73 LOWERCASE ;; + 46 bytes : enables to write strings in lowercase (whose VT100 set_up sequences...)
74 VOCABULARY_SET ;; + 104 bytes : adds words: VOCABULARY FORTH ASSEMBLER ALSO PREVIOUS ONLY DEFINITIONS (FORTH83)
75 ;SD_CARD_LOADER ; + 1748 bytes : to LOAD source files from SD_card
76 ;SD_CARD_READ_WRITE ; + 1192 bytes : to read, create, write and del files + source files direct copy from PC to SD_Card
77 NONAME ;; + 64 bytes : adds :NONAME CODENNM (CODENoNaMe)
78 ;BOOTLOADER ; + 72 bytes : adds to <reset> a bootstrap to SD_CARD\BOOT.4TH.
79 ;QUIETBOOT ; + 2 bytes : to perform bootload without displaying.
80 ;TOTAL ; + 4 bytes : to save R4 to R7 registers during interrupts.
82 ;-------------------------------------------------------------------------------
83 ; OPTIONAL KERNEL ADD-ON SWITCHES (that can be downloaded later) >-----------------------+
84 ; Tip: when added here, ADD-ONs become protected against WIPE and Deep Reset... |
85 ;------------------------------------------------------------------------------- v
86 ;UARTtoI2C ; to redirect source file to a I2C TERMINAL FastForth device UART2IIC.f
87 ;FIXPOINT ; + 422/528 bytes (MPY/noMPY): add HOLDS F+ F- F/ F* F#S F. S>F 2@ 2CONSTANT FIXPOINT.f
88 UTILITY ;; + 434/524 bytes (1/16threads) : add .S .RS WORDS U.R DUMP ? UTILITY.f
89 ;SD_TOOLS ; + 142 bytes for trivial DIR, FAT, CLUSTER and SECTOR view, adds UTILITY SD_TOOLS.f
90 ;ANS_CORE_COMPLIANT ; + 876 bytes : required to pass coretest.4th ; (includes items below) ANS_COMP.f
91 ;ARITHMETIC ; + 358 bytes : add S>D M* SM/REM FM/MOD * /MOD / MOD */MOD /MOD */
92 ;DOUBLE ; + 130 bytes : add 2@ 2! 2DUP 2SWAP 2OVER
93 ;ALIGNMENT ; + 24 bytes : add ALIGN ALIGNED
94 ;PORTABILITY ; + 46 bytes : add CHARS CHAR+ CELLS CELL+
97 ;-------------------------------------------------------------------------------
98 ; FAST FORTH TERMINAL configuration
99 ;-------------------------------------------------------------------------------
101 TERMINALBAUDRATE .equ 6000000 ; choose value considering the frequency and the UART2USB bridge, see explanations below.
102 .include "TERMINALBAUDRATE.inc"
104 ;HALFDUPLEX ; to use FAST FORTH with half duplex terminal
106 TERMINAL3WIRES ; enable 3 wires (GND,TX,RX) with XON/XOFF software flow control (PL2303TA/HXD, CP2102)
107 TERMINAL4WIRES ; + 18 bytes enable 4 wires with hardware flow control on RX with RTS (PL2303TA/HXD, FT232RL)
108 ; this RTS pin may be permanently wired on SBWTCK/TEST pin without disturbing SBW 2 wires programming
109 ;TERMINAL5WIRES ; + 6 bytes enable 5 wires with hardware flow control on RX/TX with RTS/CTS (PL2303TA/HXD, FT232RL)...
111 ; if you uncomment TERMINAL3WIRES, you have a XON/XOFF terminal (software flow control)
112 ; if you uncomment TERMINAL5WIRES, you have a RTS/CTS terminal (hardware flow control); mandatory option if you also want to perform binary transfers
113 ; if you uncomment TERMINAL3WIRES + TERMINAL4WIRES, you have a XON/XOFF + RTS terminal; sufficient option to dowload with hardware control flow
114 ; if you uncomment TERMINAL3WIRES + TERMINAL5WIRES, you have a XON/XOFF + RTS/CTS terminal
117 ; --------------------------------------------------------------------------------------------
118 ; Only two usb2uart bridges correctly handle XON / XOFF: cp2102 and pl2303.
119 ; --------------------------------------------------------------------------------------------
123 ; the best and cheapest: UARTtoUSB cable with Prolific PL2303HXD (or PL2303TA)
124 ; works wel in 3 WIRES (XON/XOF) and 4WIRES (GND,RX,TX,RTS) config
125 ; --------------------------------------------------------------------------------------------
126 ; PL2303TA 4 wires CABLE PL2303HXD 6 wires CABLE
127 ; pads upside: 3V3,txd,rxd,gnd,5V pads upside: gnd, 3V3,txd,rxd,5V
128 ; downside: cts,dcd,dsr,rts,dtr downside: rts,cts
129 ; --------------------------------------------------------------------------------------------
130 ; WARNING ! if you use PL2303TA/HXD cable as supply, open box before to weld red wire on 3v3 pad !
131 ; --------------------------------------------------------------------------------------------
132 ; 9600,19200,38400,57600 (250kHz)
133 ; + 115200,134400 (500kHz)
134 ; + 201600,230400,268800 (1MHz)
135 ; + 403200,460800,614400 (2MHz)
136 ; + 806400,921600,1228800 (4MHz)
137 ; + 2457600 (8MHz,PL2303TA)
138 ; + 1843200,2457600 (8MHz,PL2303HXD)
139 ; + 3MBds (16MHz,PL2303TA)
140 ; + 3MBds,4MBds,5MBds (16MHz,PL2303HXD)
141 ; + 6MBds (MSP430FR57xx family,24MHz)
144 ; UARTtoUSB module with Silabs CP2102 (supply current = 20 mA)
145 ; ---------------------------------------------------------------------------------------------------
146 ; WARNING ! if you use it as supply, buy a CP2102 module with a VCC switch 5V/3V3 and swith on 3V3 !
147 ; ---------------------------------------------------------------------------------------------------
148 ; 9600,19200,38400 (250kHz)
150 ; + 115200,134400,230400 (1MHz)
152 ; + 921600 (4MHz,8MHz,16MHz,24MHz)
155 ; Launchpad --- UARTtoUSB device
160 ; TERATERM config terminal : NewLine receive : AUTO,
161 ; NewLine transmit : CR+LF
162 ; Size : 128 chars x 49 lines (adjust lines to your display)
164 ; TERATERM config serial port : TERMINALBAUDRATE value,
165 ; 8bits, no parity, 1Stopbit,
166 ; XON/XOFF flow control,
167 ; delay = 0ms/line, 0ms/char
169 ; don't forget : save new TERATERM configuration !
172 ;===============================================================================
173 ; Hardware control flow configuration: RTS is wired on UART2USB CTS pin
174 ;===============================================================================
176 ; Launchpad <-> UARTtoUSB
182 ; notice that the control flow seems not necessary for TX (CTS pin)
184 ; UARTtoUSB module with PL2303TA/HXD
185 ; --------------------------------------------------------------------------------------------
186 ; WARNING ! if you use PL2303HXD cable as supply, open box before to weld red wire on 3v3 pad !
187 ; --------------------------------------------------------------------------------------------
188 ; 9600,19200,38400,57600 (250kHz)
189 ; + 115200,134400 (500kHz)
190 ; + 201600,230400,268800 (1MHz)
191 ; + 403200,460800,614400 (2MHz)
192 ; + 806400,921600,1228800 (4MHz)
193 ; + 2457600,3000000 (8MHz)
194 ; + 4000000,5000000 (16MHz)
198 ; UARTtoUSB module with FTDI FT232RL (FT230X don't work correctly)
199 ; ------------------------------------------------------------------------------
200 ; WARNING ! buy a FT232RL module with a switch 5V/3V3 and select 3V3 !
201 ; ------------------------------------------------------------------------------
202 ; 9600,19200,38400,57600,115200 (500kHz)
205 ; + 921600 (4,8,16 MHz)
207 ; TERATERM config terminal : NewLine receive : AUTO,
208 ; NewLine transmit : CR+LF
209 ; Size : 128 chars x 49 lines (adjust lines to your display)
211 ; TERATERM config serial port : TERMINALBAUDRATE value,
212 ; 8bits, no parity, 1Stopbit,
213 ; Hardware flow control,
214 ; delay = 0ms/line, 0ms/char
216 ; don't forget : save new TERATERM configuration !
218 ; ------------------------------------------------------------------------------
219 ; UARTtoBluetooth 4.2 module (RN4870/RN4871 MIKROE click 2543/2544) at 921600 bds
220 ; ------------------------------------------------------------------------------
221 ; UARTtoBluetooth 2.0 module (RN42 sparkfun bluesmirf) at 921600bds
222 ; ------------------------------------------------------------------------------
223 ; 9600,19200,38400,57600,115200 (500kHz)
226 ; + 921600 (4,8,16 MHz)
228 ; RN42 config : connect RN41/RN42 module on teraterm, via USBtoUART bridge,
229 ; ----------- 8n1, 115200 bds, no flow control, echo on
230 ; $$$ // enter control mode, response: AOK
231 ; SU,92 // set 921600 bds, response: AOK
232 ; R,1 // reset module to take effect
234 ; connect RN42 module on FastForth target
235 ; add new bluetooth device on windows, password=1234
236 ; open the created output COMx port with TERATERM at 921600bds
239 ; TERATERM config terminal : NewLine receive : AUTO,
240 ; NewLine transmit : CR+LF
241 ; Size : 128 chars x 49 lines (adjust lines to your display)
243 ; TERATERM config serial port : TERMINALBAUDRATE value,
244 ; 8bits, no parity, 1Stopbit,
245 ; Hardware flow control or software flow control or ...no flow control!
246 ; delay = 0ms/line, 0ms/char
248 ; in fact, compared to using a UART USB bridge, only the COMx port is to be updated.
249 ; don't forget : save new TERATERM configuration !
251 ; ------------------------------------------------------------------------------
253 .include "Device.inc" ; to define target config: I/O, memory, SFR, vectors, TERMINAL eUSCI, SD_Card eUSCI, LF_XTAL,
255 .include "ForthThreads.mac" ; init vocabulary pointers
257 ;-------------------------------------------------------------------------------
258 ; DTCforthMSP430FR5xxx RAM memory map:
259 ;-------------------------------------------------------------------------------
261 ; name words ; comment
263 ;LSTACK = L0 = LEAVEPTR ; ----- RAM_ORG
265 LSTACK_SIZE .equ 16 ; | grows up
268 PSTACK_SIZE .equ 48 ; | grows down
270 ;PSTACK=S0 ; ----- RAM_ORG + $80
272 RSTACK_SIZE .equ 48 ; | grows down
274 ;RSTACK=R0 ; ----- RAM_ORG + $E0
276 ; names bytes ; comments
278 ;PAD ; ----- RAM_ORG + $E4
280 PAD_LEN .equ 84 ; | grows up (ans spec. : PAD >= 84 chars)
282 ;PAD_END ; ----- RAM_ORG + $138
285 ;TIB ; ----- RAM_ORG + $13C
287 TIB_LEN .equ 84 ; | grows up (ans spec. : TIB >= 80 chars)
289 ;HOLDS_ORG ; ------RAM_ORG + $190
291 HOLD_SIZE .equ 34 ; | grows down (ans spec. : HOLD_SIZE >= (2*n) + 2 char, with n = 16 bits/cell
293 ;BASE_HOLD ; ----- RAM_ORG + $1B2
297 ; ----- RAM_ORG + $1E4
301 ; variables system END ; ----- RAM_ORG + $1FC
304 ;SD_BUF ; ----- RAM_ORG + $200
308 ; ----- RAM_ORG + $2FF
312 LEAVEPTR .equ LSTACK ; Leave-stack pointer
313 PSTACK .equ LSTACK+(LSTACK_SIZE*2)+(PSTACK_SIZE*2)
314 RSTACK .equ PSTACK+(RSTACK_SIZE*2)
315 PAD_I2CADR .equ PAD_ORG-4
316 PAD_I2CCNT .equ PAD_ORG-2
317 PAD_ORG .equ RSTACK+4
318 TIB_I2CADR .equ TIB_ORG-4
319 TIB_I2CCNT .equ TIB_ORG-2
320 TIB_ORG .equ PAD_ORG+PAD_LEN+4
321 HOLDS_ORG .equ TIB_ORG+TIB_LEN
323 BASE_HOLD .equ HOLDS_ORG+HOLD_SIZE
326 ; ----------------------------------------------------
327 ; RAM_ORG + $1B2 : RAM VARIABLES
328 ; ----------------------------------------------------
330 HP .equ BASE_HOLD ; HOLD ptr
331 CAPS .equ BASE_HOLD+2
332 LAST_NFA .equ BASE_HOLD+4 ; NFA, VOC_PFA, CFA, PSP of last created word
333 LAST_THREAD .equ BASE_HOLD+6 ; used by QREVEAL
334 LAST_CFA .equ BASE_HOLD+8
335 LAST_PSP .equ BASE_HOLD+10
336 STATE .equ BASE_HOLD+12 ; Interpreter state
337 SOURCE .equ BASE_HOLD+14
338 SOURCE_LEN .equ BASE_HOLD+14
339 SOURCE_ADR .equ BASE_HOLD+16 ; len, addr of input stream
340 TOIN .equ BASE_HOLD+18 ; CurrentInputBuffer pointer
341 DDP .equ BASE_HOLD+20 ; dictionnary pointer
342 LASTVOC .equ BASE_HOLD+22 ; keep VOC-LINK
343 CONTEXT .equ BASE_HOLD+24 ; CONTEXT dictionnary space (8 CELLS)
344 CURRENT .equ BASE_HOLD+40 ; CURRENT dictionnary ptr
345 BASE .equ BASE_HOLD+42
346 LINE .equ BASE_HOLD+44 ; line in interpretation (initialized by NOECHO)
347 ; --------------------------------------------------------------;
348 ; RAM_ORG + $1E0 : free for user after source file compilation ;
349 ; --------------------------------------------------------------;
350 SAV_CURRENT .equ BASE_HOLD+46 ; preserve CURRENT during create assembler words
351 ASMBW1 .equ BASE_HOLD+48
352 ASMBW2 .equ BASE_HOLD+50
353 ASMBW3 .equ BASE_HOLD+52
354 ASMFW1 .equ BASE_HOLD+54
355 ASMFW2 .equ BASE_HOLD+56
356 ASMFW3 .equ BASE_HOLD+58
357 ; ----------------------------------;
358 ; RAM_ORG + $1EE : free for user ;
359 ; ----------------------------------;
362 ; --------------------------------------------------
363 ; RAM_ORG + $1FC : RAM SD_CARD SD_BUF 4 + 512 bytes
364 ; --------------------------------------------------
365 SD_BUF_I2CADR .equ SD_BUF-4
366 SD_BUF_I2CCNT .equ SD_BUF-2
367 SD_BUF .equ BASE_HOLD+78
368 SD_BUFEND .equ SD_BUF + 200h ; 512bytes
371 ;-------------------------------------------------------------------------------
372 ; INFO(DCBA) >= 256 bytes memory map:
373 ;-------------------------------------------------------------------------------
377 ; --------------------------
378 ; FRAM INFO KERNEL CONSTANTS
379 ; --------------------------
381 INI_THREAD .word THREADS ; used by ADDON_UTILITY.f
382 TERMBRW_RST .word TERMBRW_INI ; set by TERMINALBAUDRATE.inc
383 TERMMCTLW_RST .word TERMMCTLW_INI ; set by TERMINALBAUDRATE.inc
387 .ELSEIF FREQUENCY = 0.5
390 FREQ_KHZ .word FREQUENCY*1000 ; user use
393 SAVE_SYSRSTIV .word 05 ; value to identify first start after core recompiling
394 LPM_MODE .word CPUOFF+GIE ; LPM0 is the default mode
395 ;LPM_MODE .word CPUOFF+GIE+SCG0 ; LPM1 is the default mode (disable FLL)
396 INIDP .word ROMDICT ; define RST_STATE
397 INIVOC .word lastvoclink ; define RST_STATE
398 GPFLAGS .word 0 ; always usefull
400 .word RXON ; user use
401 .word RXOFF ; user use
403 .IFDEF SD_CARD_LOADER
404 .word ReadSectorWX ; used by ADDON_SD_TOOLS.f
405 .IFDEF SD_CARD_READ_WRITE
406 .word WriteSectorWX ; used by ADDON_SD_TOOLS.f
409 .ENDIF ; SD_CARD_READ_WRITE
412 .ENDIF ; SD_CARD_LOADER
417 ; -------------------------------
418 ; VARIABLES that should be in RAM
419 ; -------------------------------
421 .IFDEF SD_CARD_LOADER
423 .IF RAM_LEN < 2048 ; if RAM < 2K (FR57xx) the variables below are in INFO space (FRAM)
425 SD_ORG .equ INFO_BASE_END+18 ; 8 words free to set some core routines addresses + 1 word guard...
426 ; ...while preserving FRAM area SD_LEN.
428 .ELSE ; if RAM >= 2k the variables below are in RAM
430 SD_ORG .equ SD_BUFEND+2 ; 1 word guard
435 ; ---------------------------------------
436 ; FAT FileSystemInfos
437 ; ---------------------------------------
438 FATtype .equ SD_ORG+0
439 BS_FirstSectorL .equ SD_ORG+2 ; init by SD_Init, used by RW_Sector_CMD
440 BS_FirstSectorH .equ SD_ORG+4 ; init by SD_Init, used by RW_Sector_CMD
441 OrgFAT1 .equ SD_ORG+6 ; init by SD_Init,
442 FATSize .equ SD_ORG+8 ; init by SD_Init,
443 OrgFAT2 .equ SD_ORG+10 ; init by SD_Init,
444 OrgRootDIR .equ SD_ORG+12 ; init by SD_Init, (FAT16 specific)
445 OrgClusters .equ SD_ORG+14 ; init by SD_Init, Sector of Cluster 0
446 SecPerClus .equ SD_ORG+16 ; init by SD_Init, byte size
448 SD_LOW_LEVEL .equ SD_ORG+18
449 ; ---------------------------------------
451 ; ---------------------------------------
452 SD_CMD_FRM .equ SD_LOW_LEVEL ; SD_CMDx inverted frame ${CRC7,ll,LL,hh,HH,CMD}
453 SectorL .equ SD_LOW_LEVEL+6
454 SectorH .equ SD_LOW_LEVEL+8
456 ; ---------------------------------------
458 ; ---------------------------------------
459 BufferPtr .equ SD_LOW_LEVEL+10
460 BufferLen .equ SD_LOW_LEVEL+12
462 SD_FAT_LEVEL .equ SD_LOW_LEVEL+14
463 ; ---------------------------------------
465 ; ---------------------------------------
466 ClusterL .equ SD_FAT_LEVEL ;
467 ClusterH .equ SD_FAT_LEVEL+2 ;
468 NewClusterL .equ SD_FAT_LEVEL+4 ;
469 NewClusterH .equ SD_FAT_LEVEL+6 ;
470 CurFATsector .equ SD_FAT_LEVEL+8 ; current FATSector of last free cluster
472 ; ---------------------------------------
474 ; ---------------------------------------
475 DIRClusterL .equ SD_FAT_LEVEL+10 ; contains the Cluster of current directory ; = 1 as FAT16 root directory
476 DIRClusterH .equ SD_FAT_LEVEL+12 ; contains the Cluster of current directory ; = 1 as FAT16 root directory
477 EntryOfst .equ SD_FAT_LEVEL+14
479 ; ---------------------------------------
481 ; ---------------------------------------
482 CurrentHdl .equ SD_FAT_LEVEL+16 ; contains the address of the last opened file structure, or 0
484 ; ---------------------------------------
485 ; Load file operation
486 ; ---------------------------------------
487 pathname .equ SD_FAT_LEVEL+18 ; start address
488 EndOfPath .equ SD_FAT_LEVEL+20 ; end address
490 ; ---------------------------------------
492 FirstHandle .equ SD_FAT_LEVEL+22
494 ; ---------------------------------------
496 ; ---------------------------------------
497 ; three handle tokens :
498 ; HDLB_Token= 0 : free handle
500 ; = 2 : file updated (write)
501 ; =-1 : LOAD"ed file (source file)
504 HDLW_PrevHDL .equ 0 ; previous handle
505 HDLB_Token .equ 2 ; token
506 HDLB_ClustOfst .equ 3 ; Current sector offset in current cluster (Byte)
507 HDLL_DIRsect .equ 4 ; Dir SectorL
508 HDLH_DIRsect .equ 6 ; Dir SectorH
509 HDLW_DIRofst .equ 8 ; SD_BUF offset of Dir entry
510 HDLL_FirstClus .equ 10 ; File First ClusterLo (identify the file)
511 HDLH_FirstClus .equ 12 ; File First ClusterHi (identify the file)
512 HDLL_CurClust .equ 14 ; Current ClusterLo
513 HDLH_CurClust .equ 16 ; Current ClusterHi
514 HDLL_CurSize .equ 18 ; written size / not yet read size (Long)
515 HDLH_CurSize .equ 20 ; written size / not yet read size (Long)
516 HDLW_BUFofst .equ 22 ; SD_BUF offset ; used by LOAD"
519 .IF RAM_LEN < 2048 ; due to the lack of RAM, only 5 handles and PAD replaces SDIB
521 HandleMax .equ 5 ; and not 8 to respect INFO size (FRAM)
523 HandleEnd .equ FirstHandle+handleMax*HandleLenght
525 LOADPTR .equ HandleEnd
526 LOAD_STACK .equ HandleEnd+2
527 LOADSTACK_SIZE .equ HandleMax+1 ; make room for 3 words * handles
528 LoadStackEnd .equ LOAD_STACK+LOADSTACK_SIZE*6
530 SDIB_I2CADR .equ PAD_ORG-4
531 SDIB_I2CCNT .equ PAD_ORG-2
532 SDIB_ORG .equ PAD_ORG
534 SD_END .equ LoadStackEnd
535 SD_LEN .equ SD_END-SD_ORG
537 .ELSE ; RAM_Size >= 2k all is in RAM
541 HandleEnd .equ FirstHandle+handleMax*HandleLenght
543 LOADPTR .equ HandleEnd
544 LOAD_STACK .equ HandleEnd+2
545 LOADSTACK_SIZE .equ HandleMax+1 ; make room for 3 words * handles
546 LoadStackEnd .equ LOAD_STACK+LOADSTACK_SIZE*6 ; 3 words by handle
548 SDIB_I2CADR .equ SDIB_ORG-4
549 SDIB_I2CCNT .equ SDIB_ORG-2
550 SDIB_ORG .equ LoadStackEnd+4
551 SDIB_LEN .equ 84 ; = TIB_LEN = PAD_LEN
553 SD_END .equ SDIB_ORG+SDIB_LEN
558 .ENDIF ; SD_CARD_LOADER
561 ;-------------------------------------------------------------------------------
562 ; DTCforthMSP430FR5xxx program (FRAM) memory
563 ;-------------------------------------------------------------------------------
567 ;-------------------------------------------------------------------------------
568 ; DEFINING EXECUTIVE WORDS - DTC model
569 ;-------------------------------------------------------------------------------
571 ;-------------------------------------------------------------------------------
572 ; very nice FAST FORTH added feature:
573 ;-------------------------------------------------------------------------------
574 ; as IP is always computed from the PC value, we can place low level to high level
575 ; switches "COLON" or "LO2HI" anywhere in a word, i.e. not only at its beginning
576 ; as ITC competitors.
577 ;-------------------------------------------------------------------------------
579 RSP .reg R1 ; RSP = Return Stack Pointer (return stack)
581 ; DOxxx registers ; must be saved before use and restored after use
585 rDOCOL .reg R7 ; COLD defines xdocol as R7 content
588 M .reg r6 ; ex. PUSHM L,N
599 ; Forth virtual machine
600 IP .reg R13 ; interpretative pointer
601 TOS .reg R14 ; first PSP cell
602 PSP .reg R15 ; PSP = Parameters Stack Pointer (stack data)
604 mNEXT .MACRO ; return for low level words (written in assembler)
605 MOV @IP+,PC ; 4 fetch code address into PC, IP=PFA
606 .ENDM ; 4 cycles,1word = ITC -2cycles -1 word
608 NEXT .equ 4D30h ; 4 MOV @IP+,PC
610 FORTHtoASM .MACRO ; compiled by HI2LO
612 .ENDM ; 0 cycle, 1 word
617 ;-------------------------------------------------------------------------------
618 .CASE 1 ; DOCOL = CALL rDOCOL
619 ;-------------------------------------------------------------------------------
622 xdocol MOV @RSP+,W ; 2
623 PUSH IP ; 3 save old IP on return stack
624 MOV W,IP ; 1 set new IP to PFA
625 MOV @IP+,PC ; 4 = NEXT
628 ASMtoFORTH .MACRO ; compiled by LO2HI
629 CALL #EXIT ; 2 words, 10 cycles
632 mDOCOL .MACRO ; compiled by : and by colon
633 CALL rDOCOL ; 1 word, 14 cycles (CALL included) = ITC+4
636 DOCOL1 .equ 1287h ; 4 CALL R7
638 ;-------------------------------------------------------------------------------
639 .CASE 2 ; DOCOL = PUSH IP + CALL rEXIT
640 ;-------------------------------------------------------------------------------
642 rEXIT .reg R7 ; COLD defines EXIT as R7 content
644 ASMtoFORTH .MACRO ; compiled by LO2HI
645 CALL rEXIT ; 1 word, 10 cycles
648 mDOCOL .MACRO ; compiled by : and by COLON
651 .ENDM ; 2 words, 13 cycles = ITC+3
653 DOCOL1 .equ 120Dh ; 3 PUSH IP
654 DOCOL2 .equ 1287h ; 4 CALL rEXIT
656 ;-------------------------------------------------------------------------------
657 .CASE 3 ; inlined DOCOL
658 ;-------------------------------------------------------------------------------
660 R .reg R7 ; Scratch register
662 ASMtoFORTH .MACRO ; compiled by LO2HI
666 .ENDM ; 6 cycles, 3 words
668 mDOCOL .MACRO ; compiled by : and by COLON
673 .ENDM ; 4 words, 9 cycles (ITC-1)
675 DOCOL1 .equ 120Dh ; 3 PUSH IP
676 DOCOL2 .equ 400Dh ; 1 MOV PC,IP
677 DOCOL3 .equ 522Dh ; 1 ADD #4,IP
681 ;-------------------------------------------------------------------------------
682 ; mDOVAR leave on parameter stack the PFA of a VARIABLE definition
683 ;-------------------------------------------------------------------------------
685 mDOVAR .MACRO ; compiled by VARIABLE
686 CALL rDOVAR ; 1 word, 14 cycles (ITC+4)
689 DOVAR .equ 1286h ; CALL rDOVAR ; [rDOVAR] is defined as RFROM by COLD
692 ;-------------------------------------------------------------------------------
693 ; mDOCON leave on parameter stack the [PFA] of a CONSTANT definition
694 ;-------------------------------------------------------------------------------
696 mDOCON .MACRO ; compiled by CONSTANT
697 CALL rDOCON ; 1 word, 16 cycles (ITC+4)
700 DOCON .equ 1285h ; 4 CALL rDOCON ; [rDOCON] is defined as xdocon by COLD
702 xdocon ; -- constant ; 4 for CALL rDOCON
704 MOV TOS,0(PSP) ; 3 save TOS on parameters stack
705 MOV @RSP+,TOS ; 2 TOS = CFA address of master word CONSTANT
706 MOV @TOS,TOS ; 2 TOS = CONSTANT value
707 MOV @IP+,PC ; 4 execute next word
710 ;-------------------------------------------------------------------------------
711 ; mDODOES leave on parameter stack the PFA of a CREATE definition and execute Master word
712 ;-------------------------------------------------------------------------------
714 mDODOES .MACRO ; compiled by DOES>
715 CALL rDODOES ; CALL xdodoes
716 .ENDM ; 1 word, 19 cycles (ITC-2)
718 DODOES .equ 1284h ; 4 CALL rDODOES ; [rDODOES] is defind as xdodoes by COLD
720 xdodoes ; -- a-addr ; 4 for CALL rDODOES
722 MOV TOS,0(PSP) ; 3 save TOS on parameters stack
723 MOV @RSP+,TOS ; 2 TOS = CFA address of master word, i.e. address of its first cell after DOES>
724 PUSH IP ; 3 save IP on return stack
725 MOV @TOS+,IP ; 2 IP = CFA of Master word, TOS = BODY address of created word
726 MOV @IP+,PC ; 4 Execute Master word
728 ;-------------------------------------------------------------------------------
730 ;-------------------------------------------------------------------------------
732 ;https://forth-standard.org/standard/core/EXIT
733 ;C EXIT -- exit a colon definition; CALL #EXIT performs ASMtoFORTH (10 cycles)
734 ; JMP #EXIT performs EXIT
736 EXIT MOV @RSP+,IP ; 2 pop previous IP (or next PC) from return stack
737 MOV @IP+,PC ; 4 = NEXT
740 ;Z lit -- x fetch inline literal to stack
741 ; This is the execution part of LITERAL.
743 lit SUB #2,PSP ; 2 push old TOS..
744 MOV TOS,0(PSP) ; 3 ..onto stack
745 MOV @IP+,TOS ; 2 fetch new TOS value
749 ;-------------------------------------------------------------------------------
751 ;-------------------------------------------------------------------------------
753 ;https://forth-standard.org/standard/core/DUP
754 ;C DUP x -- x x duplicate top of stack
756 DUP SUB #2,PSP ; 2 push old TOS..
757 MOV TOS,0(PSP) ; 3 ..onto stack
760 ;https://forth-standard.org/standard/core/qDUP
761 ;C ?DUP x -- 0 | x x DUP if nonzero
763 QDUP CMP #0,TOS ; 2 test for TOS nonzero
767 ;https://forth-standard.org/standard/core/DROP
768 ;C DROP x -- drop top of stack
770 DROP MOV @PSP+,TOS ; 2
773 ;https://forth-standard.org/standard/core/NIP
774 ;C NIP x1 x2 -- x2 Drop the first item below the top of stack
779 ;https://forth-standard.org/standard/core/SWAP
780 ;C SWAP x1 x2 -- x2 x1 swap top two items
787 ;https://forth-standard.org/standard/core/OVER
788 ;C OVER x1 x2 -- x1 x2 x1
790 OVER MOV TOS,-2(PSP) ; 3 -- x1 (x2) x2
791 MOV @PSP,TOS ; 2 -- x1 (x2) x1
792 SUB #2,PSP ; 2 -- x1 x2 x1
795 ;https://forth-standard.org/standard/core/ROT
796 ;C ROT x1 x2 x3 -- x2 x3 x1
798 ROT MOV @PSP,W ; 2 fetch x2
799 MOV TOS,0(PSP) ; 3 store x3
800 MOV 2(PSP),TOS ; 3 fetch x1
801 MOV W,2(PSP) ; 3 store x2
804 ;https://forth-standard.org/standard/core/toR
805 ;C >R x -- R: -- x push to return stack
811 ;https://forth-standard.org/standard/core/Rfrom
812 ;C R> -- x R: x -- pop from return stack ; CALL #RFROM performs DOVAR
819 ;https://forth-standard.org/standard/core/RFetch
820 ;C R@ -- x R: x -- x fetch from rtn stk
827 ;https://forth-standard.org/standard/core/DEPTH
828 ;C DEPTH -- +n number of items on stack, must leave 0 if stack empty
830 DEPTH MOV TOS,-2(PSP)
832 SUB PSP,TOS ; PSP-S0--> TOS
833 SUB #2,PSP ; post decrement stack...
834 RRA TOS ; TOS/2 --> TOS
837 ;-------------------------------------------------------------------------------
839 ;-------------------------------------------------------------------------------
841 ;https://forth-standard.org/standard/core/Fetch
842 ;C @ a-addr -- x fetch cell from memory
847 ;https://forth-standard.org/standard/core/Store
848 ;C ! x a-addr -- store cell in memory
850 STORE MOV @PSP+,0(TOS) ;4
854 ;https://forth-standard.org/standard/core/CFetch
855 ;C C@ c-addr -- char fetch char from memory
857 CFETCH MOV.B @TOS,TOS ;2
860 ;https://forth-standard.org/standard/core/CStore
861 ;C C! char c-addr -- store char in memory
863 CSTORE MOV.B @PSP+,0(TOS) ;4
868 ;-------------------------------------------------------------------------------
869 ; ARITHMETIC OPERATIONS
870 ;-------------------------------------------------------------------------------
872 ;https://forth-standard.org/standard/core/Plus
873 ;C + n1/u1 n2/u2 -- n3/u3 add n1+n2
878 ;https://forth-standard.org/standard/core/Minus
879 ;C - n1/u1 n2/u2 -- n3/u3 n3 = n1-n2
881 MINUS SUB @PSP+,TOS ;2 -- n2-n1
882 NEGATE XOR #-1,TOS ;1
883 ADD #1,TOS ;1 -- n3 = -(n2-n1)
886 ;https://forth-standard.org/standard/core/OnePlus
887 ;C 1+ n1/u1 -- n2/u2 add 1 to TOS
892 ;https://forth-standard.org/standard/core/OneMinus
893 ;C 1- n1/u1 -- n2/u2 subtract 1 from TOS
898 ;https://forth-standard.org/standard/double/DABS
899 ;C DABS d1 -- |d1| absolute value
901 DABBS AND #-1,TOS ; clear V, set N
902 JGE DABBSEND ; JMP if positive
903 DNEGATE XOR #-1,0(PSP)
909 ;-------------------------------------------------------------------------------
910 ; COMPARAISON OPERATIONS
911 ;-------------------------------------------------------------------------------
913 ;https://forth-standard.org/standard/core/ZeroEqual
914 ;C 0= n/u -- flag return true if TOS=0
916 ZEROEQUAL SUB #1,TOS ; borrow (clear cy) if TOS was 0
917 SUBC TOS,TOS ; TOS=-1 if borrow was set
920 ;https://forth-standard.org/standard/core/Zeroless
921 ;C 0< n -- flag true if TOS negative
923 ZEROLESS ADD TOS,TOS ;1 set carry if TOS negative
924 SUBC TOS,TOS ;1 TOS=-1 if carry was clear
925 XOR #-1,TOS ;1 TOS=-1 if carry was set
928 ;https://forth-standard.org/standard/core/Equal
929 ;C = x1 x2 -- flag test x1=x2
931 EQUAL SUB @PSP+,TOS ;2
933 TOSFALSE MOV #0,TOS ;1
936 ;https://forth-standard.org/standard/core/Uless
937 ;C U< u1 u2 -- flag test u1<u2, unsigned
940 SUB TOS,W ;1 u1-u2 in W, carry clear if borrow
941 JC TOSFALSE ; unsigned
942 TOSTRUE MOV #-1,TOS ;1
945 ;https://forth-standard.org/standard/core/less
946 ;C < n1 n2 -- flag test n1<n2, signed
948 LESS MOV @PSP+,W ;2 W=n1
949 SUB TOS,W ;1 W=n1-n2 flags set
950 LESSNEXT JL TOSTRUE ;2 signed
951 JGE TOSFALSE ;2 --> +5
953 ;https://forth-standard.org/standard/core/more
954 ;C > n1 n2 -- flag test n1>n2, signed
956 GREATER SUB @PSP+,TOS ;2 TOS=n2-n1
959 ;-------------------------------------------------------------------------------
960 ; BRANCH and LOOP OPERATORS
961 ;-------------------------------------------------------------------------------
963 ;Z branch -- branch always
967 ;Z ?branch x -- branch if TOS = zero
968 QBRAN CMP #0,TOS ; 1 test TOS value
969 QBRAN1 MOV @PSP+,TOS ; 2 pop new TOS value (doesn't change flags)
970 JZ bran ; 2 if TOS was zero, take the branch = 11 cycles
971 ADD #2,IP ; 1 else skip the branch destination
972 mNEXT ; 4 ==> branch not taken = 10 cycles
974 ;Z 0?branch x -- branch if TOS <> zero
975 QZBRAN SUB #1,TOS ; 1 borrow (clear cy) if TOS was 0
976 SUBC TOS,TOS ; 1 TOS=-1 if borrow was set
980 ;Z (do) n1|u1 n2|u2 -- R: -- sys1 sys2 run-time code for DO
981 ; n1|u1=limit, n2|u2=index
982 xdo MOV #8000h,X ;2 compute 8000h-limit "fudge factor"
984 MOV TOS,Y ;1 loop ctr = index+fudge
985 MOV @PSP+,TOS ;2 pop new TOS
987 PUSHM #2,X ;4 PUSHM X,Y, i.e. PUSHM LIMIT, INDEX
990 ;Z (+loop) n -- R: sys1 sys2 -- | sys1 sys2
991 ; run-time code for +LOOP
992 ; Add n to the loop index. If loop terminates, clean up the
993 ; return stack and skip the branch. Else take the inline branch.
994 xploop ADD TOS,0(RSP) ;4 increment INDEX by TOS value
995 MOV @PSP+,TOS ;2 get new TOS, doesn't change flags
996 xloopnext BIT #100h,SR ;2 is overflow bit set?
997 JZ bran ;2 no overflow = loop
998 ADD #2,IP ;1 overflow = loop done, skip branch ofs
999 UNXLOOP ADD #4,RSP ;1 empty RSP
1000 mNEXT ;4 16~ taken or not taken xloop/loop
1003 ;Z (loop) R: sys1 sys2 -- | sys1 sys2
1004 ; run-time code for LOOP
1005 ; Add 1 to the loop index. If loop terminates, clean up the
1006 ; return stack and skip the branch. Else take the inline branch.
1007 ; Note that LOOP terminates when index=8000h.
1008 xloop ADD #1,0(RSP) ;4 increment INDEX
1011 ;https://forth-standard.org/standard/core/UNLOOP
1012 ;C UNLOOP -- R: sys1 sys2 -- drop loop parms
1016 ;https://forth-standard.org/standard/core/I
1017 ;C I -- n R: sys1 sys2 -- sys1 sys2
1018 ;C get the innermost loop index
1020 II SUB #2,PSP ;1 make room in TOS
1022 MOV @RSP,TOS ;2 index = loopctr - fudge
1026 ;https://forth-standard.org/standard/core/J
1027 ;C J -- n R: 4*sys -- 4*sys
1028 ;C get the second loop index
1030 JJ SUB #2,PSP ; make room in TOS
1032 MOV 4(RSP),TOS ; index = loopctr - fudge
1036 ;-------------------------------------------------------------------------------
1038 ;-------------------------------------------------------------------------------
1040 ;https://forth-standard.org/standard/core/BL
1041 ;C BL -- char an ASCII space
1046 ;-------------------------------------------------------------------------------
1048 ;-------------------------------------------------------------------------------
1050 ;https://forth-standard.org/standard/core/BASE
1051 ;C BASE -- a-addr holds conversion radix
1054 .word BASE ; VARIABLE address in RAM space
1056 ;https://forth-standard.org/standard/core/STATE
1057 ;C STATE -- a-addr holds compiler state
1060 .word STATE ; VARIABLE address in RAM space
1062 ;-------------------------------------------------------------------------------
1063 ; ANS complement OPTION
1064 ;-------------------------------------------------------------------------------
1065 .IFDEF ANS_CORE_COMPLIANT
1066 .include "ADDON/ANS_COMPLEMENT.asm"
1069 ;-------------------------------------------------------------------------------
1070 ; ALIGNMENT OPERATORS OPTION
1071 ;-------------------------------------------------------------------------------
1072 .IFDEF ALIGNMENT ; included in ANS_COMPLEMENT
1073 .include "ADDON/ALIGNMENT.asm"
1076 ;-------------------------------------------------------------------------------
1077 ; PORTABILITY OPERATORS OPTION
1078 ;-------------------------------------------------------------------------------
1080 .include "ADDON/PORTABILITY.asm"
1081 .ENDIF ; PORTABILITY
1083 ;-------------------------------------------------------------------------------
1084 ; DOUBLE OPERATORS OPTION
1085 ;-------------------------------------------------------------------------------
1086 .IFDEF DOUBLE ; included in ANS_COMPLEMENT
1087 .include "ADDON/DOUBLE.asm"
1090 ;-------------------------------------------------------------------------------
1091 ; ARITHMETIC OPERATORS OPTION
1092 ;-------------------------------------------------------------------------------
1093 .IFDEF ARITHMETIC ; included in ANS_COMPLEMENT
1094 .include "/ADDON/ARITHMETIC.asm"
1097 .ENDIF ; ANS_COMPLEMENT
1099 ;-------------------------------------------------------------------------------
1101 ;-------------------------------------------------------------------------------
1103 ; Numeric conversion is done last digit first, so
1104 ; the output buffer is built backwards in memory.
1106 ;https://forth-standard.org/standard/core/num-start
1107 ;C <# -- begin numeric conversion (initialize Hold Pointer)
1109 LESSNUM MOV #BASE_HOLD,&HP
1112 ;https://forth-standard.org/standard/core/UMDivMOD
1113 ; UM/MOD udlo|udhi u1 -- r q unsigned 32/16->16
1115 UMSLASHMOD PUSH #DROP ;3 as return address for MU/MOD
1117 ; unsigned 32-BIT DiViDend : 16-BIT DIVisor --> 32-BIT QUOTient, 16-BIT REMainder
1118 ; 2 times faster if DVDhi = 0 (it's the general case)
1120 ; reg division MU/MOD NUM
1121 ; -----------------------------------------
1122 ; S = DVDlo (15-0) = ud1lo = ud1lo
1123 ; TOS = DVDhi (31-16) = ud1hi = ud1hi
1125 ; W = REMlo = REMlo = digit --> char --> -[HP]
1126 ; X = QUOTlo = ud2lo = ud2lo
1127 ; Y = QUOThi = ud2hi = ud2hi
1130 ; MU/MOD DVDlo DVDhi DIVlo -- REMlo QUOTlo QUOThi, used by fixpoint and #
1131 MUSMOD MOV TOS,T ;1 T = DIVlo
1132 MOV @PSP,TOS ;2 TOS = DVDhi
1133 MOV 2(PSP),S ;3 S = DVDlo
1134 MUSMOD1 MOV #0,W ;1 W = REMlo = 0
1135 MUSMOD2 MOV #32,rDODOES ;2 init loop count
1136 CMP #0,TOS ;1 DVDhi=0 ?
1138 RRA rDODOES ;1 yes:loop count / 2
1139 MOV S,TOS ;1 DVDhi <-- DVDlo
1140 MOV #0,S ;1 DVDlo <-- 0
1141 MOV #0,X ;1 QUOTlo <-- 0 (to do QUOThi = 0 at the end of division)
1142 MDIV1 CMP T,W ;1 REMlo U>= DIVlo ?
1143 JNC MDIV2 ;2 no : carry is reset
1144 SUB T,W ;1 yes: REMlo - DIVlo ; carry is set after soustraction!
1145 MDIV2 ADDC X,X ;1 RLC quotLO
1146 ADDC Y,Y ;1 RLC quotHI
1147 SUB #1,rDODOES ;1 Decrement loop counter
1149 ADD S,S ;1 RLA DVDlo
1150 ADDC TOS,TOS ;1 RLC DVDhi
1151 ADDC W,W ;1 RLC REMlo
1153 SUB T,W ;1 REMlo - DIVlo
1156 ENDMDIV MOV #xdodoes,rDODOES;2 restore rDODOES
1157 MOV W,2(PSP) ;3 REMlo in 2(PSP)
1158 MOV X,0(PSP) ;3 QUOTlo in 0(PSP)
1159 MOV Y,TOS ;1 QUOThi in TOS
1160 RET ;4 35 words, about 252/473 cycles, not FORTH executable !
1162 ;https://forth-standard.org/standard/core/num
1163 ;C # ud1lo ud1hi -- ud2lo ud2hi convert 1 digit of output
1165 NUM MOV &BASE,T ;3 T = Divisor
1166 NUM1 MOV @PSP,S ;2 -- DVDlo DVDhi S = DVDlo
1167 SUB #2,PSP ;1 -- DVDlo x DVDhi TOS = DVDhi
1168 CALL #MUSMOD1 ;4 -- REMlo QUOTlo QUOThi
1169 MOV @PSP+,0(PSP) ;4 -- QUOTlo QUOThi
1170 TODIGIT CMP.B #10,W ;2 W = REMlo
1173 TODIGIT1 ADD #30h,W ;2
1174 HOLDW SUB #1,&HP ;3 store W=char --> -[HP]
1179 ;https://forth-standard.org/standard/core/numS
1180 ;C #S udlo:udhi -- udlo:udhi=0 convert remaining digits
1183 .word NUM ; X=QUOTlo
1185 SUB #2,IP ;1 restore NUM return
1186 CMP #0,X ;1 test ud2lo first (generally true)
1188 CMP #0,TOS ;1 then test ud2hi (generally false)
1191 mNEXT ;4 10 words, about 241/417 cycles/char
1193 ;https://forth-standard.org/standard/core/num-end
1194 ;C #> udlo:udhi -- c-addr u end conversion, get string
1196 NUMGREATER MOV &HP,0(PSP)
1201 ;https://forth-standard.org/standard/core/HOLD
1202 ;C HOLD char -- add char to output string
1208 ;https://forth-standard.org/standard/core/SIGN
1209 ;C SIGN n -- add minus sign if n<0
1217 ;https://forth-standard.org/standard/core/Ud
1218 ;C U. u -- display u (unsigned)
1221 .word LESSNUM,lit,0,NUMS,NUMGREATER,TYPE,SPACE,EXIT
1223 ;https://forth-standard.org/standard/double/Dd
1224 ;C D. dlo dhi -- display d (signed)
1227 .word LESSNUM,SWAP,OVER,DABBS,NUMS
1228 .word ROT,SIGN,NUMGREATER,TYPE,SPACE,EXIT
1230 ;https://forth-standard.org/standard/core/d
1231 ;C . n -- display n (signed)
1237 MOV #-1,TOS ; extend sign
1240 ;-------------------------------------------------------------------------------
1241 ; DICTIONARY MANAGEMENT
1242 ;-------------------------------------------------------------------------------
1244 ;https://forth-standard.org/standard/core/HERE
1245 ;C HERE -- addr returns dictionary ptr
1252 ;https://forth-standard.org/standard/core/ALLOT
1253 ;C ALLOT n -- allocate n bytes in dict
1259 ;https://forth-standard.org/standard/core/CComma
1260 ;C C, char -- append char to dict
1268 ; ------------------------------------------------------------------------------
1269 ; TERMINAL I/O, input part
1270 ; ------------------------------------------------------------------------------
1272 ;https://forth-standard.org/standard/core/KEY
1273 ;C KEY -- c wait character from input device ; primary DEFERred word
1275 KEY MOV @PC+,PC ;3 Code Field Address (CFA) of KEY
1276 PFAKEY .word BODYKEY ; Parameter Field Address (PFA) of KEY
1277 BODYKEY ; BODY of KEY = default execution of KEY
1278 MOV &TERMRXBUF,Y ; empty buffer
1279 SUB #2,PSP ; 1 push old TOS..
1280 MOV TOS,0(PSP) ; 4 ..onto stack
1282 KEYLOOP BIT #UCRXIFG,&TERMIFG ; loop if bit0 = 0 in interupt flag register
1284 MOV &TERMRXBUF,TOS ;
1288 ;-------------------------------------------------------------------------------
1289 ; INTERPRETER INPUT, the kernel of kernel !
1290 ;-------------------------------------------------------------------------------
1292 .IFDEF SD_CARD_LOADER
1293 .include "forthMSP430FR_SD_ACCEPT.asm"
1294 DEFER_ACCEPT ; CIB (Current Input Buffer) and ACCEPT must to be redirected for SD_LOAD usage
1297 .IFNDEF DEFER_ACCEPT
1299 ; : REFILL TIB DUP TIB_LEN ACCEPT ; -- TIB TIB len shared by QUIT and [ELSE]
1300 REFILL SUB #6,PSP ;2
1303 MOV #TIB_ORG,0(PSP) ;4
1307 ;https://forth-standard.org/standard/core/ACCEPT
1308 ;C ACCEPT addr addr len -- addr len' get line at addr to interpret len' chars
1314 ; CIB -- addr of Current Input Buffer
1315 FORTHWORD "CIB" ; constant, may be redirected as SDIB_ORG by OPEN.
1316 FCIB mDOCON ; Code Field Address (CFA) of FCIB
1317 PFACIB .WORD TIB_ORG ; Parameter Field Address (PFA) of FCIB
1319 ; : REFILL CIB DUP TIB_LEN ACCEPT ; -- CIB CIB len shared by QUIT and [ELSE]
1320 REFILL SUB #6,PSP ;2
1323 MOV &PFACIB,0(PSP) ;5
1327 ;https://forth-standard.org/standard/core/ACCEPT
1328 ;C ACCEPT addr addr len -- addr len' get line at addr to interpret len' chars
1330 ACCEPT MOV @PC+,PC ;3 Code Field Address (CFA) of ACCEPT
1331 PFAACCEPT .word BODYACCEPT ; Parameter Field Address (PFA) of ACCEPT
1332 BODYACCEPT ; BODY of ACCEPT = default execution of ACCEPT
1334 .ENDIF ; DEFER_ACCEPT
1336 .IFDEF HALFDUPLEX ; to use FAST FORTH with half duplex input terminal (bluetooth or wifi connexion)
1338 .include "forthMSP430FR_HALFDUPLEX.asm"
1340 .ELSE ; to use FAST FORTH with full duplex terminal (USBtoUART bridge)
1342 ; con speed of TERMINAL link, there are three bottlenecks :
1343 ; 1- time to send XOFF/RTS_high on CR (CR+LF=EOL), first emergency.
1344 ; 2- the char loop time,
1345 ; 3- the time between sending XON/RTS_low and clearing UCRXIFG on first received char,
1346 ; everything must be done to reduce these times, taking into account the necessity of switching to SLEEP (LPMx mode).
1347 ; ----------------------------------;
1348 ; ACCEPT part I prepare TERMINAL_INT;
1349 ; ----------------------------------;
1351 PUSHM #4,R7 ;6 push R7,R6,R5,R4
1353 MOV #ENDACCEPT,S ;2 S = ACCEPT XOFF return
1354 MOV #AKEYREAD1,T ;2 T = default XON return
1355 PUSHM #3,IP ;5 PUSHM IP,S,T, as IP ret, XOFF ret, XON ret
1356 MOV TOS,W ;1 -- addr len
1357 MOV @PSP,TOS ;2 -- org ptr )
1358 ADD TOS,W ;1 -- org ptr W=Bound )
1359 MOV #0Dh,T ;2 T = 'CR' to speed up char loop in part II > prepare stack and registers
1360 MOV #20h,S ;2 S = 'BL' to speed up char loop in part II ) for TERMINAL_INT use
1361 MOV #AYEMIT_RET,IP ;2 IP = return for YEMIT )
1362 BIT #UCRXIFG,&TERMIFG ;3 RX_Int ?
1363 JZ ACCEPTNEXT ;2 no : case of quiet input terminal
1364 MOV &TERMRXBUF,Y ;3 yes: clear RX_Int
1365 CMP #0Ah,Y ;2 received char = LF ? (end of downloading ?)
1366 JNZ RXON ;2 no : RXON return = AKEYREAD1, to process first char of new line.
1367 ACCEPTNEXT ADD #2,RSP ;1 yes: remove AKEYREAD1 as XON return,
1368 MOV #SLEEP,X ;2 and set XON return = SLEEP
1369 PUSHM #5,IP ;7 PUSHM IP,S,T,W,X before SLEEP (and so WAKE on any interrupts)
1370 ; ----------------------------------;
1372 ; ----------------------------------;
1373 .IFDEF TERMINAL3WIRES ;
1374 ; .IF TERMINALBAUDRATE/FREQUENCY <230400 ; Incompatible option with baudrate change on the fly.
1375 RXON_LOOP BIT #UCTXIFG,&TERMIFG ;3 wait the sending end of XON, useless at high baudrates
1378 MOV #17,&TERMTXBUF ;4 move char XON into TX_buf
1380 .IFDEF TERMINAL4WIRES ;
1381 BIC.B #RTS,&HANDSHAKOUT ;4 set RTS low
1383 ; vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv;
1384 ; starts first and 3th stopwatches ;
1385 ; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^;
1386 RET ;4 to BACKGND (End of file download or quiet input) or AKEYREAD1 (get next line of file downloading)
1387 ; ----------------------------------; ...or user defined
1390 ; ----------------------------------;
1392 ; ----------------------------------;
1393 .IFDEF TERMINAL3WIRES ;
1394 MOV #19,&TERMTXBUF ;4 move XOFF char into TX_buf
1396 .IFDEF TERMINAL4WIRES ;
1397 BIS.B #RTS,&HANDSHAKOUT ;4 set RTS high
1399 RET ;4 to ENDACCEPT, ...or user defined
1400 ; ----------------------------------;
1403 ; ----------------------------------;
1404 ASMWORD "SLEEP" ; may be redirected
1405 SLEEP MOV @PC+,PC ;3 Code Field Address (CFA) of SLEEP
1406 PFASLEEP .word BODYSLEEP ; Parameter Field Address (PFA) of SLEEP
1407 BODYSLEEP ; BODY of SLEEP = default execution of SLEEP
1408 BIS &LPM_MODE,SR ;3 enter in LPMx sleep mode with GIE=1
1409 ; ----------------------------------; default FAST FORTH mode (for its input terminal use) : LPM0.
1411 ;###############################################################################################################
1412 ;###############################################################################################################
1414 ; ### # # ####### ####### ###### ###### # # ###### ####### ##### # # ####### ###### #######
1415 ; # ## # # # # # # # # # # # # # # # # # # # #
1416 ; # # # # # # # # # # # # # # # # # # # # # #
1417 ; # # # # # ##### ###### ###### # # ###### # ##### ####### ##### ###### #####
1418 ; # # # # # # # # # # # # # # # # # # # # #
1419 ; # # ## # # # # # # # # # # # # # # # # # #
1420 ; ### # # # ####### # # # # ##### # # ##### # # ####### # # #######
1422 ;###############################################################################################################
1423 ;###############################################################################################################
1426 ; here, Fast FORTH sleeps, waiting any interrupt.
1427 ; IP,S,T,W,X,Y registers (R13 to R8) are free for any interrupt routine...
1428 ; ...and so PSP and RSP stacks with their rules of use.
1429 ; remember: in any interrupt routine you must include : BIC #0x78,0(RSP) before RETI
1430 ; to force return to SLEEP.
1431 ; or (bad idea ? previous SR flags are lost) simply : ADD #2 RSP, then RET instead of RETI
1434 ; ==================================;
1435 JMP SLEEP ;2 here is the return for any interrupts, else TERMINAL_INT :-)
1436 ; ==================================;
1439 ; **********************************;
1440 TERMINAL_INT ; <--- TEMR RX interrupt vector, delayed by the LPMx wake up time
1441 ; **********************************; if wake up time increases, max bauds rate decreases...
1442 ; (ACCEPT) part II under interrupt ; Org Ptr -- len'
1443 ; ----------------------------------;
1444 ADD #4,RSP ;1 remove SR and PC from stack, SR flags are lost (unused by FORTH interpreter)
1445 POPM #4,IP ;6 POPM W=buffer_bound, T=0Dh,S=20h, IP=AYEMIT_RET
1446 ; vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv;
1447 ; starts the 2th stopwatch ;
1448 ; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^;
1449 AKEYREAD MOV.B &TERMRXBUF,Y ;3 read character into Y, UCRXIFG is cleared
1450 ; vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv;
1451 ; stops the 3th stopwatch ; 3th bottleneck result : 17~ + LPMx wake_up time ( + 5~ XON loop if F/Bds<230400 )
1452 ; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^;
1454 CMP.B S,Y ;1 printable char ?
1455 JHS ASTORETEST ;2 yes
1456 CMP.B T,Y ;1 char = CR ?
1457 JZ RXOFF ;2 then RET to ENDACCEPT
1458 ; vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv;+ 4 to send RXOFF
1459 ; stops the first stopwatch ;= first bottleneck, best case result: 27~ + LPMx wake_up time..
1460 ; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^; ...or 14~ in case of empty line
1461 CMP.B #8,Y ;1 char = BS ?
1462 JNE WAITaKEY ;2 case of other control chars
1463 ; ----------------------------------;
1464 ; start of backspace ; made only by an human
1465 ; ----------------------------------;
1466 CMP @PSP,TOS ; Ptr = Org ?
1467 JZ WAITaKEY ; yes: do nothing
1468 SUB #1,TOS ; no : dec Ptr
1469 JMP YEMIT1 ; send BS
1470 ; ----------------------------------;
1471 ; end of backspace ;
1472 ; ----------------------------------;
1473 ASTORETEST CMP W,TOS ; 1 Bound is reached ?
1474 JZ YEMIT1 ; 2 yes: send echo then loopback
1475 MOV.B Y,0(TOS) ; 3 no: store char @ Ptr, send echo then loopback
1476 ADD #1,TOS ; 1 increment Ptr
1478 ; .IF TERMINALBAUDRATE/FREQUENCY <230401; Incompatible with baudrate modification on the fly.
1479 BIT #UCTXIFG,&TERMIFG ; 3 wait the sending end of previous char (sent before ACCEPT), useless at high baudrates
1480 JZ YEMIT1 ; 2 but there's no point in wanting to save time here:
1481 ; .ENDIF ; it must be understood that the receiver loses time also when receiving the char.
1483 .IFDEF TERMINAL5WIRES ;
1484 BIT.B #CTS,&HANDSHAKIN ; 3
1487 YEMIT ; hi7/4~ lo:12/9~ send/send_not echo to terminal
1488 .word 4882h ; 4882h = MOV Y,&<next_adr>
1491 ; ----------------------------------;
1492 AYEMIT_RET FORTHtoASM ; 0 YEMII NEXT address; NOP9
1493 SUB #2,IP ; 1 set YEMIT NEXT address to AYEMIT_RET
1494 WAITaKEY BIT #UCRXIFG,&TERMIFG ; 3 new char in TERMRXBUF ?
1495 JNZ AKEYREAD ; 2 yes
1497 ; vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv;
1498 ; stops the 2th stopwatch ; best case result: 26~/22~ (with/without echo) ==> 385/455 kBds/MHz
1499 ; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^;
1501 ; ----------------------------------;
1502 ENDACCEPT ; <--- XOFF return address
1503 ; ----------------------------------;
1504 MOV #LPM0+GIE,&LPM_MODE ; reset LPM_MODE to default mode LPM0 for next line of input stream
1505 CMP #0,&LINE ; if LINE <> 0...
1507 ADD #1,&LINE ; ...increment LINE
1508 ACCEPTEND SUB @PSP+,TOS ; Org Ptr -- len'
1509 MOV @RSP+,IP ; 2 and continue with INTERPRET with GIE=0.
1510 ; So FORTH machine is protected against any interrupt...
1512 POPM #4,R7 ;6 pop R4,R5,R6,R7
1514 mNEXT ; ...until next falling down to LPMx mode of (ACCEPT) part1,
1515 ; **********************************; i.e. when the FORTH interpreter has no more to do.
1517 ; ------------------------------------------------------------------------------
1518 ; TERMINAL I/O, output part
1519 ; ------------------------------------------------------------------------------
1521 ;https://forth-standard.org/standard/core/EMIT
1522 ;C EMIT c -- output character to the output device ; primary DEFERred word
1524 EMIT MOV @PC+,PC ;3 Code Field Address (CFA) of EMIT
1525 PFAEMIT .word BODYEMIT ; Parameter Field Address (PFA) of EMIT
1526 BODYEMIT ; BODY of EMIT = default execution of EMIT
1533 ;Z ECHO -- connect console output (default)
1535 ECHO MOV #4882h,&YEMIT ; 4882h = MOV Y,&<next_adr>
1539 ;Z NOECHO -- disconnect console output
1541 NOECHO MOV #NEXT,&YEMIT ; NEXT = 4030h = MOV @IP+,PC
1545 ;https://forth-standard.org/standard/core/SPACE
1546 ;C SPACE -- output a space
1553 ;https://forth-standard.org/standard/core/SPACES
1554 ;C SPACES n -- output n spaces
1561 SPACESNEXT FORTHtoASM
1564 JNZ SPACE ;25~ ==> 27~ by space ==> 2.963 MBds @ 8 MHz
1565 DROPEXIT MOV @RSP+,IP ;
1566 ONEDROP MOV @PSP+,TOS ; -- drop n
1569 ;https://forth-standard.org/standard/core/TYPE
1570 ;C TYPE adr len -- type line to terminal
1573 JZ TWODROP ; abort fonction
1574 .word 0151Eh ;5 PUSM TOS,IP R-- len,IP
1576 TYPELOOP MOV @PSP,Y ;2 -- adr adr ; 30~ char loop
1578 MOV Y,0(PSP) ;3 -- adr+1 char
1579 SUB #2,PSP ;1 emit consumes one cell
1581 TYPE_NEXT FORTHtoASM
1583 SUB #1,2(RSP) ;4 len-1
1585 POPM #2,TOS ;4 POPM IP,TOS
1586 TWODROP ADD #2,PSP ;
1590 ;https://forth-standard.org/standard/core/CR
1591 ;C CR -- send CR to the output device
1593 CR MOV @PC+,PC ;3 Code Field Address (CFA) of CR
1594 PFACR .word BODYCR ; Parameter Field Address (PFA) of CR
1595 BODYCR ; BODY of CR = default execution of CR
1601 ; ------------------------------------------------------------------------------
1602 ; STRINGS PROCESSING
1603 ; ------------------------------------------------------------------------------
1605 ;Z (S") -- addr u run-time code for S"
1606 ; get address and length of string.
1607 XSQUOTE SUB #4,PSP ; 1 -- x x TOS ; push old TOS on stack
1608 MOV TOS,2(PSP) ; 3 -- TOS x x ; and reserve one cell on stack
1609 MOV.B @IP+,TOS ; 2 -- x u ; u = lenght of string
1610 MOV IP,0(PSP) ; 3 -- addr u
1611 ADD TOS,IP ; 1 -- addr u IP=addr+u=addr(end_of_string)
1612 BIT #1,IP ; 1 -- addr u IP=addr+u Carry set/clear if odd/even
1613 ADDC #0,IP ; 1 -- addr u IP=addr+u aligned
1619 CAPS_ON MOV #-1,&CAPS ; state by default
1622 FORTHWORD "CAPS_OFF"
1623 CAPS_OFF MOV #0,&CAPS
1626 ;https://forth-standard.org/standard/core/Sq
1627 ;C S" -- compile in-line string
1628 FORTHWORDIMM "S\34" ; immediate
1630 .word lit,XSQUOTE,COMMA
1631 SQUOTE1 .word CAPS_OFF
1632 .word lit,'"',WORDD ; -- c-addr (= HERE)
1637 ;https://forth-standard.org/standard/core/Sq
1638 ;C S" -- compile in-line string
1639 FORTHWORDIMM "S\34" ; immediate
1641 .word lit,XSQUOTE,COMMA
1642 SQUOTE1 .word lit,'"',WORDD ; -- c-addr (= HERE)
1648 MOV.B @TOS,TOS ; -- u
1649 SUB #1,TOS ; -1 byte
1653 BIT #1,&DDP ;3 carry set if 1
1654 ADDC #2,&DDP ;4 +2 bytes
1657 ;https://forth-standard.org/standard/core/Dotq
1658 ;C ." -- compile string to print
1659 FORTHWORDIMM ".\34" ; immediate
1662 .word lit,TYPE,COMMA,EXIT
1664 ;-------------------------------------------------------------------------------
1666 ;-------------------------------------------------------------------------------
1668 ;https://forth-standard.org/standard/core/WORD
1669 ;C WORD char -- addr Z=1 if len=0
1670 ; parse a word delimited by char separator
1671 ; "word" is capitalized
1672 ; TOIN is the relative displacement in the ascii string
1673 ; separator filled line = 25 cycles + 7 cycles by char
1675 WORDD MOV #SOURCE_LEN,S ;2 -- separator
1676 MOV @S+,X ;2 X = str_len
1677 MOV @S+,W ;2 W = str_org
1678 ADD W,X ;1 W = str_org X = str_org + str_len = str_end
1679 ADD @S+,W ;2 W = str_org + >IN = str_ptr X = str_end
1680 MOV @S,Y ;2 -- separator W = str_ptr X = str_end Y = HERE, as dst_ptr
1681 SKIPCHARLOO CMP W,X ;1 str_ptr = str_end ?
1682 JZ EOL_END ;2 -- separator if yes : End Of Line !
1683 CMP.B @W+,TOS ;2 does char = separator ?
1684 JZ SKIPCHARLOO ;2 -- separator if yes
1685 SCANWORD SUB #1,W ;1
1686 MOV #96,T ;2 T = 96 = ascii(a)-1 (test value set in a register before SCANWORD loop)
1688 SCANWORDLOO ; -- separator 15/23 cycles loop for upper/lower case char... write words in upper case !
1689 MOV.B S,0(Y) ;3 first time make room in dst for word length, then put char @ dst.
1690 CMP W,X ;1 str_ptr = str_end ?
1691 JZ SCANWORDEND ;2 if yes
1693 CMP.B S,TOS ;1 does char = separator ?
1694 JZ SCANWORDEND ;2 if yes
1695 ADD #1,Y ;1 increment dst just before test loop
1696 CMP.B S,T ;1 char U< 'a' ? ('a'-1 U>= char) this condition is tested at each loop
1697 JC SCANWORDLOO ;2 15~ upper case char loop
1699 QCAPS CMP #0,&CAPS ;3 CAPS is OFF ? (available only for ABORT" ." .( )
1700 JZ SCANWORDLOO ;2 yes, don't convert lower to upper case
1701 .ENDIF ; LOWERCASE ; here CAPS is ON
1702 CMP.B #123,S ;2 char U>= 'z'+1 ?
1703 JC SCANWORDLOO ;2 if yes
1704 SUB.B #32,S ;2 convert lowercase char to uppercase
1707 SUB &SOURCE_ADR,W ;3 -- separator W=str_ptr - str_org = new >IN (first char separator next)
1708 MOV W,&TOIN ;3 update >IN
1709 EOL_END MOV &DDP,TOS ;3 -- c-addr
1710 SUB TOS,Y ;1 Y=Word_Length
1712 mNEXT ;4 -- c-addr 40 words Z=1 <==> lenght=0 <==> EOL
1714 ;https://forth-standard.org/standard/core/FIND
1715 ;C FIND c-addr -- c-addr 0 if not found ; flag Z=1
1716 ;C xt -1 if found ; flag Z=0
1717 ;C xt 1 if immediate ; flag Z=0
1718 ; compare WORD at c-addr (HERE) with each of words in each of listed vocabularies in CONTEXT
1719 ; FIND to WORDLOOP : 14/20 cycles,
1720 ; mismatch word loop: 13 cycles on len, +8 cycles on first char,
1721 ; +10 cycles char loop,
1722 ; VOCLOOP : 12/18 cycles,
1723 ; WORDFOUND to end : 21 cycles.
1724 ; note: with 16 threads vocabularies, FIND takes about 75% of CORETEST.4th processing time
1726 FIND SUB #2,PSP ;1 -- ???? c-addr reserve one cell here, not at FINDEND because interacts with flag Z
1727 MOV TOS,S ;1 S=c-addr
1728 MOV.B @S,rDOCON ;2 R5= string count
1729 MOV.B #80h,rDODOES ;2 R4= immediate mask
1731 VOCLOOP MOV @T+,TOS ;2 -- ???? VOC_PFA T=CTXT+2
1732 CMP #0,TOS ;1 no more vocabulary in CONTEXT ?
1733 JZ FINDEND ;2 -- ???? 0 yes ==> exit; Z=1
1736 .ELSECASE ; search thread add 6cycles 5words
1737 MAKETHREAD MOV.B 1(S),Y ;3 -- ???? VOC_PFA0 S=c-addr Y=CHAR0
1738 AND.B #(THREADS-1)*2,Y ;2 -- ???? VOC_PFA0 Y=thread offset
1739 ADD Y,TOS ;1 -- ???? VOC_PFAx
1741 ADD #2,TOS ;1 -- ???? VOC_PFA+2
1742 WORDLOOP MOV -2(TOS),TOS ;3 -- ???? [VOC_PFA] [VOC_PFA] first, then [LFA]
1743 CMP #0,TOS ;1 -- ???? NFA no more word in the thread ?
1744 JZ VOCLOOP ;2 -- ???? NFA yes ==> search next voc in context
1746 MOV.B @X+,Y ;2 TOS=NFA,X=NFA+1,Y=NFA_char
1747 BIC.B rDODOES,Y ;1 hide Immediate bit
1748 LENCOMP CMP.B rDOCON,Y ;1 compare lenght
1749 JNZ WORDLOOP ;2 -- ???? NFA 13~ word loop on lenght mismatch
1751 CHARLOOP ADD #1,W ;1
1752 CHARCOMP CMP.B @X+,0(W) ;4 compare chars
1753 JNZ WORDLOOP ;2 -- ???? NFA 21~ word loop on first char mismatch
1754 SUB.B #1,Y ;1 decr count
1755 JNZ CHARLOOP ;2 -- ???? NFA 10~ char loop
1757 WORDFOUND BIT #1,X ;1
1759 MOV X,S ;1 S=aligned CFA
1760 MOV.B @TOS,W ;2 -- ???? NFA W=NFA_first_char
1761 MOV #1,TOS ;1 -- ???? 1 preset immediate flag
1762 CMP.B #0,W ;1 W is negative if immediate flag
1763 JN FINDEND ;2 -- ???? 1
1764 SUB #2,TOS ;1 -- ???? -1
1765 FINDEND MOV S,0(PSP) ;3 not found: -- c-addr 0 flag Z=1
1766 ; found: -- xt -1|+1 (not immediate|immediate) flag Z=0
1767 MOV #xdocon,rDOCON ;2
1768 MOV #xdodoes,rDODOES ;2
1769 mNEXT ;4 42/47 words
1773 ;https://forth-standard.org/standard/core/toNUMBER
1774 ;C convert a string to double number until count2 = 0 or until not convertible char
1775 ;C >NUMBER ud1lo|ud1hi addr1 count1 -- ud2lo|ud2hi addr2 count2
1776 FORTHWORD ">NUMBER" ; 23 cycles + 32/34 cycles DEC/HEX char loop
1777 TONUMBER MOV @PSP+,S ;2 S = adr
1778 MOV @PSP+,Y ;2 Y = ud1hi
1779 MOV @PSP,X ;2 X = ud1lo
1782 TONUMLOOP MOV.B @S,W ;2 -- ud1lo ud1hi adr count W=char
1783 DDIGITQ SUB.B #30h,W ;2 skip all chars < '0'
1784 CMP.B #10,W ;2 char was U< "10" ?
1785 JLO DDIGITQNEXT ;2 no
1788 JLO TONUMEND ;2 skip all chars between "9" and "A"
1789 DDIGITQNEXT CMP T,W ;1 digit-base
1790 JHS TONUMEND ;2 -- ud1lo ud1hi adr count abort if < 0 or >= base
1791 MOV X,&MPY32L ;3 Load 1st operand (ud1lo)
1792 MOV Y,&MPY32H ;3 Load 1st operand (ud1hi)
1793 MOV T,&OP2 ;3 Load 2nd operand with BASE
1794 MOV &RES0,X ;3 lo result in X (ud2lo)
1795 MOV &RES1,Y ;3 hi result in Y (ud2hi)
1796 ADD W,X ;1 ud2lo + digit
1797 ADDC #0,Y ;1 ud2hi + carry
1798 TONUMPLUS ADD #1,S ;1 -- ud1lo ud1hi adr+1 count S=adr+1
1799 SUB #1,TOS ;1 -- ud1lo ud1hi adr+1 count-1
1800 JNZ TONUMLOOP ;2 if count <>0
1801 TONUMEND MOV S,0(PSP) ;3 -- ud1lo ud1hi adr2 count2
1802 MOV Y,2(PSP) ;3 -- ud1lo ud2hi adr2 count2
1803 MOV X,4(PSP) ;3 -- ud2lo ud2hi adr2 count2
1806 ; ?NUMBER makes the interface between >NUMBER and INTERPRET; it's a subset of INTERPRET.
1807 ; convert a string to a signed number; FORTH 2012 prefixes $, %, # are recognized
1808 ; 32 bits numbers (with decimal point) and fixed point signed numbers (with a comma) are recognized.
1809 ; prefixes # % $ - are processed before calling >NUMBER
1810 ; not convertible chars '.' (double) and ',' (fixed point) are processed as >NUMBER exits
1811 ;Z ?NUMBER c-addr -- n -1 if convert ok ; flag Z=0
1812 ;Z c-addr -- c-addr 0 if convert ko ; flag Z=1
1814 MOV &BASE,T ;3 T=BASE
1815 BIC #UF9,SR ;2 reset flag UF9, before use as decimal point flag
1816 PUSHM #3,IP ;5 R-- IP sign base
1819 MOV #QNUMNEXT,IP ;2 return from >NUMBER
1820 SUB #8,PSP ;1 -- x x x x c-addr save TOS and make room for >NUMBER
1821 MOV TOS,6(PSP) ;3 -- c-addr x x x c-addr
1822 MOV TOS,S ;1 S=addrr
1823 MOV.B @S+,TOS ;2 -- c-addr x x x cnt TOS=count
1824 MOV.B @S,W ;2 W=char
1826 JHS QSIGN ;2 for current base, and for ',' or '.' process
1828 QBINARY MOV #2,T ;3 preset base 2
1829 ADD.B #8,W ;1 '%' + 8 = '-' binary number ?
1831 QDECIMAL ADD #8,T ;4
1832 ADD.B #2,W ;1 '#' + 2 = '%' decimal number ?
1835 SUB.B #1,W ;2 '$' - 1 = '#' hex number ?
1836 JNZ TONUMLOOP ;2 -- c-addr ud=0 x x other cases will cause error
1837 PREFIXED ADD #1,S ;1
1838 SUB #1,TOS ;1 -- c-addr ud=0 x count S=adr+1 TOS=count-1
1839 MOV.B @S,W ;2 X=2th char, W=adr
1842 JNZ TONUMLOOP ;2 for positive number and for , or . process
1843 MOV #-1,2(RSP) ;3 R-- IP sign base
1845 ; ----------------------------------;40
1846 QNUMNEXT FORTHtoASM ; -- c-addr ud2lo-hi addr2 cnt2 R-- IP sign BASE S=addr2
1847 CMP #0,TOS ;1 cnt2=0 : conversion is ok ?
1849 BIT #UF9,SR ;2 already flagged? (to discard repeated points or repeated commas)
1850 JNZ QNUMNEXT1 ;2 abort
1851 BIS #UF9,SR ;2 set double number flag
1852 .IFDEF FIXPOINT_INPUT ;48
1853 ; ----------------------------------;
1854 QQNUMDP CMP.B #'.',0(S) ;4 rejected char by >NUMBER = decimal point ?
1856 SUB #2,IP ;1 yes: reset QNUMNEXT address as >NUMBER return
1857 JMP TONUMPLUS ;2 loop back to >NUMBER to terminate conversion
1858 QQcomma CMP.B #',',0(S) ;5 rejected char by >NUMBER is a comma ?
1860 S15Q16 MOV TOS,W ;1 -- c-addr ud2lo x x x yes W=cnt2
1861 MOV #0,X ;1 -- c-addr ud2lo x 0 x init X = ud2lo' = 0
1862 S15Q16LOOP MOV X,2(PSP) ;3 -- c-addr ud2lo ud2lo' ud2lo' x 0(PSP) = ud2lo'
1863 SUB.B #1,W ;1 decrement cnt2
1864 MOV W,X ;1 X = cnt2-1
1865 ADD S,X ;1 X = end_of_string-1, first...
1866 MOV.B @X,X ;2 X = last char of string, first...
1867 SUB #30h,X ;2 char --> digit conversion
1872 JLO S15Q16EOC ;2 skip all chars between "9" and "A"
1873 QS15Q16DIGI CMP T,X ;1 R-- IP sign BASE is X a digit ?
1874 JHS S15Q16EOC ;2 -- c-addr ud2lo ud2lo' x ud2lo' if no
1875 MOV X,0(PSP) ;3 -- c-addr ud2lo ud2lo' digit x
1876 MOV T,TOS ;1 -- c-addr ud2lo ud2lo' digit base R-- IP sign base
1877 PUSHM #3,S ;6 PUSH S,T,W: R-- IP sign base addr2 base cnt2
1878 CALL #MUSMOD ;4 -- c-addr ud2lo ur uqlo uqhi
1879 POPM #3,S ;6 restore W,T,S: R-- IP sign BASE
1880 JMP S15Q16LOOP ;2 W=cnt
1881 S15Q16EOC MOV 4(PSP),2(PSP) ;5 -- c-addr ud2lo ud2hi uqlo x ud2lo from >NUMBER part1 becomes here ud2hi=S15 part2
1882 MOV @PSP,4(PSP) ;4 -- c-addr ud2lo ud2hi x x uqlo becomes ud2lo
1883 MOV W,TOS ;1 -- c-addr ud2lo ud2hi x cnt2
1884 CMP.B #0,TOS ;1 TOS = 0 if end of conversion char = ',' (happy end)
1885 .ELSE ; no FIXPOINT_INPUT
1886 ; ----------------------------------;
1887 QQNUMDP CMP.B #'.',0(S) ;4 rejected char by >NUMBER = decimal point ?
1889 SUB #2,IP ;1 yes: set QNUMNEXT address as >NUMBER return
1890 JMP TONUMPLUS ;2 loop back to >NUMBER to terminate conversion
1891 .ENDIF ; of FIXPOINT_INPUT ;54
1892 ; ----------------------------------;
1893 QNUMNEXT1 POPM #3,IP ;4 -- c-addr ud2lo-hi x cnt2 POPM T,S,IP S = sign flag = {-1;0}
1894 MOV S,TOS ;1 -- c-addr ud2lo-hi x sign
1896 JZ QNUMOK ;2 -- c-addr ud2lo-hi x sign conversion OK
1897 QNUMKO ADD #6,PSP ;1 -- c-addr sign
1898 AND #0,TOS ;1 -- c-addr ff TOS=0 and Z=1 ==> conversion ko
1900 ; ----------------------------------;63
1901 QNUMOK ADD #2,PSP ;1 -- c-addr ud2lo-hi cnt2
1902 MOV 2(PSP),4(PSP) ; -- udlo udlo udhi sign
1903 MOV @PSP+,0(PSP) ;4 -- udlo udhi sign note : PSP is incremented before write back !!!
1904 XOR #-1,TOS ;1 -- udlo udhi inv(sign)
1905 JNZ QDOUBLE ;2 if jump : TOS=-1 and Z=0 ==> conversion ok
1906 Q2NEGATE XOR #-1,TOS ;1 -- udlo udhi tf
1907 XOR #-1,2(PSP) ;3 -- dlo-1 dhi-1 tf
1908 XOR #-1,0(PSP) ;3 -- dlo-1 udhi tf
1909 ADD #1,2(PSP) ;3 -- dlo dhi-1 tf
1910 ADDC #0,0(PSP) ;3 -- dlo dhi tf
1911 QDOUBLE BIT #UF9,SR ;2 decimal point added ?
1912 JNZ QNUMEND ;2 leave double
1913 ADD #2,PSP ;1 leave number
1914 QNUMEND mNEXT ;4 TOS=-1 and Z=0 ==> conversion ok
1915 ; ----------------------------------;85/125 words
1917 .ELSE ; no hardware HRDWMPY
1919 ; T.I. SIGNED MULTIPLY SUBROUTINE: U1 x U2 -> Ud
1920 ;https://forth-standard.org/standard/core/UMTimes
1921 ;C UM* u1 u2 -- ud unsigned 16x16->32 mult.
1923 UMSTAR MOV @PSP,S ;2 MDlo
1924 UMSTAR1 MOV #0,T ;1 MDhi=0
1927 MOV #1,W ;1 BIT TEST REGISTER
1928 UMSTARLOOP BIT W,TOS ;1 TEST ACTUAL BIT MRlo
1929 JZ UMSTARNEXT ;2 IF 0: DO NOTHING
1930 ADD S,X ;1 IF 1: ADD MDlo TO RES0
1931 ADDC T,Y ;1 ADDC MDhi TO RES1
1932 UMSTARNEXT ADD S,S ;1 (RLA LSBs) MDlo x 2
1933 ADDC T,T ;1 (RLC MSBs) MDhi x 2
1934 ADD W,W ;1 (RLA) NEXT BIT TO TEST
1935 JNC UMSTARLOOP ;2 IF BIT IN CARRY: FINISHED 10~ loop
1936 MOV X,0(PSP) ;3 low result on stack
1937 MOV Y,TOS ;1 high result in TOS
1940 ;https://forth-standard.org/standard/core/toNUMBER
1941 ;C convert a string to double number until count2 = 0 or until not convertible char
1942 ;C >NUMBER ud1lo|ud1hi addr1 count1 -- ud2lo|ud2hi addr2 count2
1944 TONUMBER MOV @PSP,S ; S=adr
1947 TONUMLOOP MOV.B @S,X ; -- ud1lo ud1hi x x S=adr, T=count, W=BASE, X=char
1948 DDIGITQ SUB.B #30h,X ;2 skip all chars < '0'
1949 CMP.B #10,X ; char was > "9" ?
1950 JLO DDIGITQNEXT ; -- ud1lo ud1hi x x no: good end
1951 SUB.B #07,X ;2 skip all chars between "9" and "A"
1952 CMP.B #10,X ;2 char was < "A" ?
1953 JLO TONUMEND ;2 yes: for bad end
1954 DDIGITQNEXT CMP W,X ; -- ud1lo ud1hi x x digit-base
1957 PUSHM #6,IP ; -- ud1lo ud1hi x x R-- IP adr count base digit digit PSUHM IP,S,T,W,X,Y
1958 MOV 2(PSP),S ; -- ud1lo ud1hi x x S=ud1hi
1959 MOV W,TOS ; -- ud1lo ud1hi x base
1960 MOV #UMSTARNEXT1,IP ;
1961 UMSTARONE JMP UMSTAR1 ; ud1hi * base -- x ud3hi X=ud3lo
1962 UMSTARNEXT1 FORTHtoASM ; -- ud1lo ud1hi x ud3hi
1963 MOV X,2(RSP) ; R-- IP adr count base ud3lo digit
1964 MOV 4(PSP),S ; -- ud1lo ud1hi x ud3hi S=ud1lo
1965 MOV 4(RSP),TOS ; -- ud1lo ud1hi x base R-- IP adr count base ud3lo digit
1966 MOV #UMSTARNEXT2,IP ;
1967 UMSTARTWO JMP UMSTAR1 ; -- ud1lo ud1hi x ud4hi X=ud4lo
1968 UMSTARNEXT2 FORTHtoASM ; -- ud1lo ud1hi x ud4hi
1969 ADD @RSP+,X ; -- ud1lo ud1hi x ud4hi X=ud4lo+digit=ud2lo r-- IP adr count base ud3lo
1970 MPLUS ADDC @RSP+,TOS ; -- ud1lo ud1hi x ud2hi TOS=ud4hi+ud3lo+carry=ud2hi r-- IP adr count base
1971 MOV X,4(PSP) ; -- ud2lo ud1hi x ud2hi
1972 MOV TOS,2(PSP) ; -- ud2lo ud2hi x x R-- IP adr count base
1973 POPM #4,IP ; -- ud2lo ud2hi x x W=base, T=count, S=adr, IP=prevIP
1974 TONUMPLUS ADD #1,S ;
1976 JNZ TONUMLOOP ; -- ud2lo ud2hi x x S=adr+1, T=count-1, W=base
1977 TONUMEND MOV S,0(PSP) ; -- ud2lo ud2hi adr2 count2
1978 MOV T,TOS ; -- ud2lo ud2hi adr2 count2
1979 mNEXT ; 46 words, W = BASE
1981 ; convert a string to a signed number
1982 ;Z ?NUMBER c-addr -- n -1 if convert ok ; flag Z=0
1983 ;Z c-addr -- c-addr 0 if convert ko ; flag Z=1
1984 ; FORTH 2012 prefixes $, %, # are recognised
1985 ; 32 bits numbers (with decimal point) are recognised
1986 ; with FIXPOINT_INPUT switched ON, fixed point signed numbers (with a comma) are recognised.
1987 ; prefixes # % $ - are processed before calling >NUMBER, decimal point and comma are >NUMBER exits
1988 ; FORTHWORD "?NUMBER"
1990 MOV &BASE,T ;3 T=BASE
1991 PUSHM #3,IP ;5 R-- IP sign base
1992 MOV #QNUMNEXT,IP ;2 define >NUMBER return
1994 BIC #UF9,SR ;2 reset flag UF9 used here as decimal point flag
1995 SUB #8,PSP ;1 -- x x x x c-addr
1996 MOV TOS,6(PSP) ;3 -- c-addr x x x c-addr
1998 MOV #0,2(PSP) ;3 -- c-addr ud=0 x c-addr
2000 MOV.B @S+,T ;2 -- c-addr ud=0 x x S=adr, T=count
2001 MOV.B @S,X ;2 X=char
2003 JHS QSIGN ;2 for current base, and for ',' or '.' process
2005 QBINARY MOV #2,W ;1 preset base 2
2006 ADD.B #8,X ;1 '%' + 8 = '-' binary number ?
2008 QDECIMAL ADD #8,W ;1
2009 ADD.B #2,X ;1 '#' + 2 = '%' decimal number ?
2012 SUB.B #1,X ;2 '$' - 1 = '#' hex number ?
2013 JNZ TONUMLOOP ;2 -- c-addr ud=0 x x other cases will cause error
2014 PREFIXED ADD #1,S ;1
2015 SUB #1,T ;1 -- c-addr ud=0 x x S=adr+1 T=count-1
2016 MOV.B @S,X ;2 X=2th char, W=adr
2019 JNZ TONUMLOOP ;2 for positive number and for , or . process
2020 MOV #-1,2(RSP) ;3 R-- IP sign base
2022 ; ----------------------------------;45
2023 QNUMNEXT FORTHtoASM ; -- c-addr ud2lo-hi addr2 cnt2 R-- IP sign BASE S=addr2,T=cnt2
2024 CMP #0,TOS ;1 cnt2=0 ? conversion is ok ?
2025 JZ QNUMNEXT1 ;2 yes (neither comma nor point in string)
2026 BIT #UF9,SR ;2 already flagged? (to discard repeated points or repeated commas)
2027 JNZ QNUMNEXT1 ;2 abort
2028 BIS #UF9,SR ;2 set double number flag
2029 .IFDEF FIXPOINT_INPUT
2030 ; ----------------------------------;
2031 QNUMDP CMP.B #'.',0(S) ;4 rejected char by >NUMBER is a decimal point ?
2033 QNUMDPFOUND SUB #2,IP ;1 yes set >NUMBER return address
2034 JMP TONUMPLUS ;2 to terminate conversion
2035 QS15Q16 CMP.B #',',0(S) ;5 rejected char by >NUMBER is a comma ?
2037 S15Q16 MOV #0,X ;1 -- c-addr ud2lo x 0 x init ud2lo' = 0
2038 S15Q16LOOP MOV X,2(PSP) ;3 -- c-addr ud2lo ud2lo' ud2lo' x X = 0(PSP) = ud2lo'
2039 SUB.B #1,T ;1 decrement cnt2
2040 MOV T,X ;1 X = cnt2-1
2041 ADD S,X ;1 X = end_of_string-1, first...
2042 MOV.B @X,X ;2 X = last char of string, first...
2043 SUB #30h,X ;2 char --> digit conversion
2049 QS15Q16DIGI CMP W,X ;1 R-- IP sign BASE, W=BASE, is X a digit ?
2050 JHS S15Q16EOC ;2 -- c-addr ud2lo ud2lo' x ud2lo' if no
2051 MOV X,0(PSP) ;3 -- c-addr ud2lo ud2lo' digit x
2052 MOV W,TOS ;1 -- c-addr ud2lo ud2lo' digit base R-- IP sign base
2053 PUSHM #3,S ;5 PUSH S,T,W: R-- IP sign base addr2 cnt2 base
2054 CALL #MUSMOD ;4 -- c-addr ud2lo ur uqlo uqhi
2055 POPM #3,S ;5 restore W,T,S: R-- IP sign BASE
2056 JMP S15Q16LOOP ;2 W=cnt
2057 S15Q16EOC MOV 4(PSP),2(PSP) ;5 -- c-addr ud2lo ud2lo uqlo x ud2lo from >NUMBER part1 becomes here ud2hi=S15 part2
2058 MOV @PSP,4(PSP) ;4 -- c-addr ud2lo ud2hi x x uqlo becomes ud2lo
2059 MOV T,TOS ;1 -- c-addr ud2lo ud2hi x cnt2
2060 CMP.B #0,TOS ;1 TOS = 0 if end of conversion char = ',' (happy end)
2061 .ELSE ; no FIXPOINT_INPUT
2062 ; ----------------------------------;
2063 QNUMDP CMP.B #'.',0(S) ;4 rejected char by >NUMBER is a decimal point ?
2065 QNUMDPFOUND SUB #2,IP ;1 set >NUMBER return address
2066 JMP TONUMPLUS ;2 to terminate conversion
2067 .ENDIF ; of FIXPOINT_INPUT
2068 ; ----------------------------------;97
2069 QNUMNEXT1 POPM #3,IP ;4 -- c-addr ud2lo-hi x cnt2 POPM T,S,IP S = sign flag = {-1;0}
2070 MOV S,TOS ;1 -- c-addr ud2lo-hi x sign
2072 JZ QNUMOK ;2 -- c-addr ud2lo-hi x sign conversion OK
2073 QNUMKO ADD #6,PSP ;1 -- c-addr sign
2074 AND #0,TOS ;1 -- c-addr ff TOS=0 and Z=1 ==> conversion ko
2076 ; ----------------------------------;
2077 QNUMOK ADD #2,PSP ;1 -- c-addr ud2lo-hi sign
2078 MOV 2(PSP),4(PSP) ; -- udlo udlo udhi sign
2079 MOV @PSP+,0(PSP) ;4 -- udlo udhi sign note : PSP is incremented before write back !!!
2080 XOR #-1,TOS ;1 -- udlo udhi inv(sign)
2081 JNZ QDOUBLE ;2 if jump : TOS=-1 and Z=0 ==> conversion ok
2082 Q2NEGATE XOR #-1,TOS ;1 -- udlo udhi tf
2083 XOR #-1,2(PSP) ;3 -- dlo-1 dhi-1 tf
2084 XOR #-1,0(PSP) ;3 -- dlo-1 udhi tf
2085 ADD #1,2(PSP) ;3 -- dlo dhi-1 tf
2086 ADDC #0,0(PSP) ;3 -- dlo dhi tf
2087 QDOUBLE BIT #UF9,SR ;2 decimal point added ?
2088 JNZ QNUMEND ;2 leave double
2089 ADD #2,PSP ;1 leave number
2090 QNUMEND mNEXT ;4 TOS=-1 and Z=0 ==> conversion ok
2091 ; ----------------------------------;128 words
2093 .ENDIF ; of Hardware MPY
2095 ;https://forth-standard.org/standard/core/EXECUTE
2096 ;C EXECUTE i*x xt -- j*x execute Forth word at 'xt'
2098 EXECUTE MOV TOS,W ; 1 put word address into W
2099 MOV @PSP+,TOS ; 2 fetch new TOS
2100 MOV W,PC ; 3 fetch code address into PC
2102 ;https://forth-standard.org/standard/core/Comma
2103 ;C , x -- append cell to dict
2111 ;https://forth-standard.org/standard/core/LITERAL
2112 ;C LITERAL (n|d) -- append single numeric literal if compiling state
2113 ; (n|d) -- append double numeric literal if compiling state and if UF9<>0 (not ANS)
2114 FORTHWORDIMM "LITERAL" ; immediate
2115 LITERAL CMP #0,&STATE ;3
2116 JZ LITERALEND ;2 if not immediate, leave n|d on the stack
2117 LITERAL1 MOV &DDP,W ;3
2125 LITERALEND mNEXT ;4 30~
2127 ;https://forth-standard.org/standard/core/COUNT
2128 ;C COUNT c-addr1 -- adr len counted->adr/len
2133 MOV.B -1(TOS),TOS ;3
2136 ; : SETIB SOURCE 2! 0 >IN ! ; ; org len -- set Input Buffer, shared by INTERPRET and [ELSE]
2137 SETIB MOV #0,&TOIN ;
2138 MOV TOS,&SOURCE_LEN ; -- org len
2139 MOV @PSP+,&SOURCE_ADR ; -- len
2143 ;C INTERPRET i*x addr u -- j*x interpret given buffer
2144 ; This is the common factor of EVALUATE and QUIT.
2145 ; set addr u as input buffer then parse it word by word
2147 .word SETIB ; set Input buffer pointers SOURCE_LEN, SOURCE_ORG clear >IN
2148 INTLOOP .word FBLANK,WORDD ; -- c-addr Z = End Of Line
2150 MOV #INTFINDNEXT,IP ;2 define INTFINDNEXT as FIND return
2151 JNZ FIND ;2 if EOL not reached
2152 JMP DROPEXIT ; if EOL reached
2154 INTFINDNEXT FORTHtoASM ; -- c-addr fl Z = not found
2155 MOV TOS,W ; W = flag =(-1|0|+1) as (normal|not_found|immediate)
2156 MOV @PSP+,TOS ; -- c-addr
2157 MOV #INTQNUMNEXT,IP ;2 define QNUMBER return
2158 JZ QNUMBER ;2 c-addr -- if not found search a number
2159 MOV #INTLOOP,IP ;2 define (EXECUTE | COMMA) return
2161 JZ COMMA ;2 c-addr -- if W xor STATE = 0 compile xt then loop back to INTLOOP
2162 JNZ EXECUTE ;2 c-addr -- if W xor STATE <>0 execute xt then loop back to INTLOOP
2164 INTQNUMNEXT FORTHtoASM ; -- n|c-addr fl Z = not a number, SR(UF9) double number request
2166 MOV #INTLOOP,IP ;2 -- n|c-addr define LITERAL return
2167 JNZ LITERAL ;2 n -- execute LITERAL then loop back to INTLOOP
2168 NotFoundExe ADD.B #1,0(TOS) ;3 c-addr -- Not a Number : incr string count to add '?'
2171 MOV.B #'?',0(Y) ;5 add '?' to end of word string
2172 MOV #FQABORTYES,IP ;2 define COUNT return
2173 JMP COUNT ;2 -- addr len 36 words
2175 ;https://forth-standard.org/standard/core/EVALUATE
2176 ; EVALUATE \ i*x c-addr u -- j*x interpret string
2177 FORTHWORD "EVALUATE"
2178 EVALUATE MOV #SOURCE_LEN,X ;2
2179 MOV @X+,S ;2 S = SOURCE_LEN
2180 MOV @X+,T ;2 T = SOURCE_ADR
2181 MOV @X+,W ;2 W = TOIN
2182 PUSHM #4,IP ;6 PUSHM IP,S,T,W
2187 MOV @RSP+,&SOURCE_ADR ;4
2188 MOV @RSP+,&SOURCE_LEN ;4
2193 PREQUIT0 MOV #0,&SAVE_SYSRSTIV ;
2194 PREQUIT1 MOV #RSTACK,RSP
2195 MOV #LSTACK,&LEAVEPTR
2199 .IFDEF BOOTLOAD ; Boot loader requires Conditional Compilation
2200 ;c BOOT -- jump to bootstrap then continues with (QUIT)
2203 .word PREQUIT1 ; doesn't reset SAVE_SYSRSTIV before testing !
2205 ; ----------------------------------;
2207 ; ----------------------------------;
2208 CMP #0,&SAVE_SYSRSTIV ; if WARM
2209 JZ QUIT0 ; no boostrap
2210 BIT.B #SD_CD,&SD_CDIN ; SD_memory in SD_Card module ?
2211 JNZ QUIT0 ; if not, no bootstrap
2212 ; ----------------------------------;
2213 ; BOOTSTRAP ; on SYSRSTIV <> 0
2214 ; ----------------------------------;
2217 MOV &SAVE_SYSRSTIV,TOS ;
2218 MOV #0,&SAVE_SYSRSTIV ;
2221 .word NOECHO ; warning ! your BOOT.4TH must to be finished with ECHO command!
2223 .word XSQUOTE ; -- addr u
2224 .byte 15,"LOAD\34 BOOT.4TH\34" ; issues error 2 if no such file...
2225 .word BRAN,QUIT4 ; to interpret this string
2226 ; ----------------------------------;
2228 ;https://forth-standard.org/standard/core/QUIT
2229 ;c QUIT -- interpret line by line the input stream, primary DEFERred word
2231 QUIT MOV @PC+,PC ;3 Code Field Address (CFA) of QUIT
2232 PFAQUIT .word BODYQUIT ; Parameter Field Address (PFA) of QUIT
2233 BODYQUIT ; BODY of QUIT = default execution of QUIT
2235 .ELSE ; if no BOOTLOADER, QUIT is not DEFERred
2237 ;https://forth-standard.org/standard/core/QUIT
2238 ;c QUIT -- interpret line by line the input stream
2247 .byte 5,13,10,"ok " ; CR+LF + Forth prompt
2248 QUIT2 .word TYPE ; display it
2251 QUIT4 .word INTERPRET
2252 .word DEPTH,ZEROLESS
2254 .byte 13,"stack empty! "
2256 .word lit,FRAM_FULL,HERE,ULESS
2258 .byte 11,"FRAM full! "
2261 .word QBRAN,QUIT1 ; case of interpretion state
2262 .word XSQUOTE ; case of compilation state
2263 .byte 5,13,10," " ; CR+LF + 3 blanks
2266 ;https://forth-standard.org/standard/core/ABORT
2267 ;C ABORT i*x -- R: j*x -- clear stack & QUIT
2269 ABORT MOV #PSTACK,PSP
2272 WIP_DEFER ; WIPE resets ALL factory primary DEFERred words
2273 MOV #BODYWARM,&PFAWARM ; ' WARM >BODY IS WARM default init
2274 MOV #BODYSLEEP,&PFASLEEP ; MOV #SLEEP,X ADD #4,X MOV X,-2(X) default background task
2275 QAB_DEFER ; QABORT resets some primary DEFERred words
2276 MOV #BODYEMIT,&PFAEMIT ;4 ' EMIT >BODY IS EMIT default console output
2277 MOV #BODYCR,&PFACR ;4 ' CR >BODY IS CR default CR
2278 MOV #BODYKEY,&PFAKEY ;4 ' KEY >BODY IS KEY default KEY
2280 .IFDEF DEFER_ACCEPT ; true if SD_LOADER
2281 MOV #BODYACCEPT,&PFAACCEPT ;4 ' ACCEPT >BODY IS ACCEPT
2282 MOV #TIB_ORG,&PFACIB ;4 TIB_ORG TO CIB (Current Input Buffer)
2284 .IFDEF MSP430ASSEMBLER ; reset all 6 branch labels
2287 RAZASM MOV #0,ASMBW1(Y) ; begins with last label...
2289 JHS RAZASM ; out of loop when Y = -2...
2295 RefillUSBtime .equ int(frequency*2730) ; 2730*frequency ==> 65520 @ max freq (24MHz)
2297 ;Z ?ABORT f c-addr u -- abort & print msg
2298 ; FORTHWORD "?ABORT"
2299 QABORT CMP #0,2(PSP) ; -- f c-addr u flag test
2301 THREEDROP ADD #4,PSP
2305 QABORTYES MOV #4882h,&YEMIT ; restore default YEMIT = set ECHO
2306 ; ----------------------------------;
2308 ; ----------------------------------;
2309 .IFDEF SD_CARD_LOADER ; close all handles
2311 QABORTCLOSE CMP #0,T
2313 MOV.B #0,HDLB_Token(T)
2318 ; ----------------------------------;
2319 QABORTYESNOECHO ; <== WARM jumps here, thus, if NOECHO, TERMINAL can be disconnected without freezing the app
2320 ; ----------------------------------;
2322 ; ----------------------------------;
2323 QABORTTERM ; wait the end of source file downloading
2324 ; ----------------------------------;
2325 .IFDEF TERMINAL3WIRES ;
2326 BIT #UCTXIFG,&TERMIFG ; TX buffer empty ?
2328 ; ----------------------------------;
2329 MOV #17,&TERMTXBUF ; yes move XON char into TX_buf
2331 .IFDEF TERMINAL4WIRES ;
2332 BIC.B #RTS,&HANDSHAKOUT ; set /RTS low (connected to /CTS pin of UARTtoUSB bridge)
2334 QABORTLOOP BIC #UCRXIFG,&TERMIFG ; reset TERMIFG(UCRXIFG)
2335 MOV #RefillUSBtime,Y ; 2730*36 = 98 ms : PL2303TA seems to be the slower USB device to refill its TX buffer.
2336 QABUSBLOOPJ MOV #8,X ; 1~ <-------+
2337 QABUSBLOOPI NOP ; 1~ <---+ |
2339 JNZ QABUSBLOOPI ; 2~ > 4~ loop -+ |
2341 JNZ QABUSBLOOPJ ; 2~ --> 36~ loop --+
2342 BIT #UCRXIFG,&TERMIFG ; 4 new char in TERMRXBUF after refill time out ?
2343 JNZ QABORTLOOP ; 2 yes, the input stream (download source file) is still active
2344 ; ----------------------------------;
2345 ; Display ABORT message ; no, the input stream is quiet (end of download source file)
2346 ; ----------------------------------;
2348 .word XSQUOTE ; -- c-addr u c-addr1 u1
2349 .byte 4,27,"[7m" ; type ESC[7m
2350 .word TYPE ; -- c-addr u set reverse video
2351 ERRLINE .word lit,LINE,FETCH,QDUP; if LINE <> 0
2352 .word QBRAN,ERRLINE_END
2354 .word XSQUOTE ; displays the line where error occured
2359 ERRLINE_END .word TYPE ; -- type abort message
2360 .word XSQUOTE ; -- c-addr2 u2
2362 .word TYPE ; -- set normal video
2363 ; ----------------------------------;
2364 .word PWR_STATE ; remove all words beyond PWR_HERE
2368 .word ABORT ; no return
2369 ; ----------------------------------;
2371 ;https://forth-standard.org/standard/core/ABORTq
2372 ;C ABORT" i*x flag -- i*x R: j*x -- j*x flag=0
2373 ;C i*x flag -- R: j*x -- flag<>0
2374 FORTHWORDIMM "ABORT\34" ; immediate
2377 .word lit,QABORT,COMMA
2380 ;https://forth-standard.org/standard/core/Tick
2381 ;C ' -- xt find word in dictionary and leave on stack its execution address
2383 TICK mDOCOL ; separator -- xt
2384 .word FBLANK,WORDD,FIND ; Z=1 if not found
2385 .word QBRAN,NotFound
2387 NotFound .word NotFoundExe ; in INTERPRET
2389 ;https://forth-standard.org/standard/block/bs
2391 ; everything up to the end of the current line is a comment.
2392 FORTHWORDIMM "\\" ; immediate
2393 BACKSLASH MOV &SOURCE_LEN,&TOIN ;
2396 ;-------------------------------------------------------------------------------
2398 ;-------------------------------------------------------------------------------
2400 ;https://forth-standard.org/standard/core/Bracket
2401 ;C [ -- enter interpretative state
2402 FORTHWORDIMM "[" ; immediate
2403 LEFTBRACKET MOV #0,&STATE
2406 ;https://forth-standard.org/standard/core/right-bracket
2407 ;C ] -- enter compiling state
2409 RIGHTBRACKET MOV #-1,&STATE
2412 ;https://forth-standard.org/standard/core/BracketTick
2413 ;C ['] <name> -- find word & compile it as literal
2414 FORTHWORDIMM "[']" ; immediate word, i.e. word executed during compilation
2416 .word TICK ; get xt of <name>
2417 .word lit,lit,COMMA ; append LIT action
2418 .word COMMA,EXIT ; append xt literal
2420 ;https://forth-standard.org/standard/core/DEFERStore
2421 ;C DEFER! xt CFA_DEFER -- ; store xt to the address after DODEFER
2422 ; FORTHWORD "DEFER!"
2423 DEFERSTORE MOV @PSP+,2(TOS) ; -- CFA_DEFER xt --> [CFA_DEFER+2]
2427 ;https://forth-standard.org/standard/core/IS
2430 ; DEFER DISPLAY create a "do nothing" definition (2 CELLS)
2431 ; inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY
2432 ; or in a definition : ... ['] U. IS DISPLAY ...
2433 ; KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words
2435 ; as IS replaces the PFA value of a "PFA word", it may be also used with VARIABLE and CONSTANT words...
2437 FORTHWORDIMM "IS" ; immediate
2441 IS_COMPILE .word BRACTICK ; find the word, compile its CFA as literal
2442 .word lit,DEFERSTORE,COMMA ; compile DEFERSTORE
2444 IS_EXEC .word TICK,DEFERSTORE ; find the word, leave its CFA on the stack and execute DEFERSTORE
2447 ;https://forth-standard.org/standard/core/IMMEDIATE
2448 ;C IMMEDIATE -- make last definition immediate
2449 FORTHWORD "IMMEDIATE"
2450 IMMEDIATE MOV &LAST_NFA,W
2454 ;https://forth-standard.org/standard/core/RECURSE
2455 ;C RECURSE -- recurse to current definition (compile current definition)
2456 FORTHWORDIMM "RECURSE" ; immediate
2457 RECURSE MOV &DDP,X ;
2458 MOV &LAST_CFA,0(X) ;
2462 ;https://forth-standard.org/standard/core/POSTPONE
2463 FORTHWORDIMM "POSTPONE" ; immediate
2465 .word FBLANK,WORDD,FIND,QDUP
2466 .word QBRAN,NotFound
2467 .word ZEROLESS ; immediate ?
2468 .word QBRAN,POST1 ; yes
2469 .word lit,lit,COMMA,COMMA
2471 POST1 .word COMMA,EXIT
2473 ;;Z ?REVEAL -- if no stack mismatch, link this created word in the CURRENT vocabulary
2474 ; FORTHWORD "REVEAL"
2475 QREVEAL CMP PSP,&LAST_PSP ; Check SP with its saved value by :
2476 JZ GOOD_CSP ; if no stack mismatch.
2479 .byte 15,"stack mismatch!"
2480 FQABORTYES .word QABORTYES
2482 ;https://forth-standard.org/standard/core/Semi
2483 ;C ; -- end a colon definition
2484 FORTHWORDIMM ";" ; immediate
2485 SEMICOLON CMP #0,&STATE ; in interpret mode semicolon becomes a comment separator
2486 JZ BACKSLASH ; tip: ";" is transparent to the preprocessor, so semicolon comments are kept in file.4th
2487 mDOCOL ; compile mode
2488 .word lit,EXIT,COMMA
2489 .word QREVEAL,LEFTBRACKET,EXIT
2492 ;https://forth-standard.org/standard/core/ColonNONAME
2495 COLONNONAME SUB #2,PSP
2499 MOV #PAIN,X ; PAIN is a read only register in all MSP430FRxxxx devices...
2500 MOV X,Y ; so, MOV Y,0(X) writes to a read only register = lure for semicolon LAST_THREAD REVEAL...
2501 ADD #2,Y ; so, MOV @X,-2(Y) writes to same register = lure for semicolon LAST_NFA REVEAL...
2502 CALL #HEADEREND ; ...because we don't want write preamble of word in dictionnary!
2507 MOV #DOCOL1,-4(W) ; compile CALL rDOCOL
2510 MOV #DOCOL1,-4(W) ; compile PUSH IP 3~
2511 MOV #DOCOL2,-2(W) ; compile CALL rEXIT
2512 .CASE 3 ; inlined DOCOL
2513 MOV #DOCOL1,-4(W) ; compile PUSH IP 3~
2514 MOV #DOCOL2,-2(W) ; compile MOV PC,IP 1~
2515 MOV #DOCOL3,0(W) ; compile ADD #4,IP 1~
2516 MOV #NEXT,+2(W) ; compile MOV @IP+,PC 4~
2519 MOV #-1,&STATE ; enter compiling state
2520 SAVE_PSP MOV PSP,&LAST_PSP ; save PSP for check compiling, used by QREVEAL
2523 ;https://forth-standard.org/standard/core/Colon
2524 ;C : <name> -- begin a colon definition
2526 COLON PUSH #COLONNEXT ; define COLONNEXT as RET for HEADER
2528 ; HEADER create an header for a new word. Max count of chars = 126
2529 ; common code for VARIABLE, CONSTANT, CREATE, DEFER, :, MARKER, CODE, ASM.
2530 ; don't link created word in vocabulary.
2532 .word CELLPLUSALIGN ; ALIGN then make room for LFA
2533 .word FBLANK,WORDD ;
2534 FORTHtoASM ; -- HERE HERE is the NFA of this new word
2536 MOV.B @TOS+,W ; -- xxx W=Count_of_chars Y=NFA
2537 BIS.B #1,W ; -- xxx W=count is always odd
2538 ADD.B #1,W ; -- xxx W=add one byte for length
2539 ADD Y,W ; -- xxx W=Aligned_CFA
2540 MOV &CURRENT,X ; -- xxx X=VOC_BODY of CURRENT Y=NFA
2542 .CASE 1 ; nothing to do
2543 .ELSECASE ; multithreading add 5~ 4words
2544 MOV.B @TOS,TOS ; -- xxx TOS=first CHAR of new word
2545 AND #(THREADS-1)*2,TOS ; -- xxx TOS= Thread offset
2546 ADD TOS,X ; -- xxx TOS= Thread X=VOC_PFAx = thread x of VOC_PFA of CURRENT
2550 MOV #4030h,0(W) ;4 by default, HEADER create a DEFERred word: CFA = MOV @PC+,PC = BR...
2551 MOV #PFA_DEFER,2(W) ;4 by default, HEADER create a DEFERred word: PFA = address of NEXT to do nothing.
2553 HEADEREND MOV Y,&LAST_NFA ; -- NFA --> LAST_NFA used by QREVEAL, IMMEDIATE
2554 MOV X,&LAST_THREAD ; -- VOC_PFAx --> LAST_THREAD used by QREVEAL
2555 MOV W,&LAST_CFA ; -- HERE=CFA --> LAST_CFA used by DOES>, RECURSE
2556 ADD #4,W ; -- by default make room for two words...
2558 RET ; 23 words, W is the new DDP value )
2559 ; X is LAST_THREAD > used by VARIABLE, CONSTANT, CREATE, DEFER and :
2562 ;https://forth-standard.org/standard/core/VARIABLE
2563 ;C VARIABLE <name> -- define a Forth VARIABLE
2564 FORTHWORD "VARIABLE"
2565 VARIABLE CALL #HEADER ; W = DDP = CFA + 2 words
2566 MOV #DOVAR,-4(W) ; CFA = DOVAR
2567 JMP REVEAL ; PFA is undefined
2569 ;https://forth-standard.org/standard/core/CONSTANT
2570 ;C CONSTANT <name> n -- define a Forth CONSTANT (and also a Forth VALUE)
2571 FORTHWORD "CONSTANT"
2572 CONSTANT CALL #HEADER ; W = DDP = CFA + 2 words
2573 MOV #DOCON,-4(W) ; CFA = DOCON
2574 MOV TOS,-2(W) ; PFA = n
2578 ;;https://forth-standard.org/standard/core/VALUE
2579 ;;( x "<spaces>name" -- ) define a Forth VALUE
2580 ;;Skip leading space delimiters. Parse name delimited by a space.
2581 ;;Create a definition for name with the execution semantics defined below,
2582 ;;with an initial value equal to x.
2584 ;;name Execution: ( -- x )
2585 ;;Place x on the stack. The value of x is that given when name was created,
2586 ;;until the phrase x TO name is executed, causing a new value of x to be assigned to name.
2588 ; FORTHWORD "VALUE" ; VALUE is an alias of CONSTANT
2591 ;;TO name Run-time: ( x -- )
2592 ;;Assign the value x to name.
2594 ; FORTHWORDIMM "TO" ; TO is an alias of IS
2597 ; usage : SDIB_ORG IS CIB ; modify Current_Input_Buffer address to read a SD file sector
2599 ; TIB_ORG IS CIB ; restore Terminal_Input_Buffer address as Current_Input_Buffer address
2601 ;https://forth-standard.org/standard/core/CREATE
2602 ;C CREATE <name> -- define a CONSTANT with its next address
2603 ; Execution: ( -- a-addr ) ; a-addr is the address of name's data field
2604 ; ; the execution semantics of name may be extended by using DOES>
2606 CREATE CALL #HEADER ; -- W = DDP
2607 MOV #DOCON,-4(W) ;4 -4(W) = CFA = DOCON
2608 MOV W,-2(W) ;3 -2(W) = PFA = W = next address
2611 ;https://forth-standard.org/standard/core/DOES
2612 ;C DOES> -- set action for the latest CREATEd definition
2614 DOES MOV &LAST_CFA,W ; W = CFA of CREATEd word
2615 MOV #DODOES,0(W) ; replace CFA (DOCON) by new CFA (DODOES)
2616 MOV IP,2(W) ; replace PFA by the address after DOES> as execution address
2617 MOV @RSP+,IP ; exit of the new created word
2620 ;https://forth-standard.org/standard/core/DEFER
2621 ;C DEFER "<spaces>name" --
2622 ;Skip leading space delimiters. Parse name delimited by a space.
2623 ;Create a definition for name with the execution semantics defined below.
2626 ;Execute the xt that name is set to execute, i.e. NEXT (nothing),
2627 ;until the phrase ' word IS name is executed, causing a new value of xt to be assigned to name.
2630 DEFER CALL #HEADER ; that create a secondary DEFERred word (whithout subsequent code)
2633 ;https://forth-standard.org/standard/core/toBODY
2634 ; >BODY -- addr leave BODY of a CREATEd word or of a primary DEFERred word
2641 ; ------------------------------------------------------------------------------
2642 ; forthMSP430FR : CONDITIONNAL COMPILATION
2643 ; ------------------------------------------------------------------------------
2644 .include "forthMSP430FR_CONDCOMP.asm"
2646 ; compile the words: COMPARE [THEN] [ELSE] [IF] [UNDEFINED] [DEFINED] MARKER
2650 GOOD_CSP MOV &LAST_NFA,Y ; GOOD_CSP is the end of word MARKER
2651 MOV &LAST_THREAD,X ;
2652 REVEAL MOV @X,-2(Y) ; [LAST_THREAD] --> LFA
2653 MOV Y,0(X) ; LAST_NFA --> [LAST_THREAD]
2656 ; ------------------------------------------------------------------------------
2657 ; CONTROL STRUCTURES
2658 ; ------------------------------------------------------------------------------
2659 ; THEN and BEGIN compile nothing
2660 ; DO compile one word
2661 ; IF, ELSE, AGAIN, UNTIL, WHILE, REPEAT, LOOP & +LOOP compile two words
2662 ; LEAVE compile three words
2664 ;https://forth-standard.org/standard/core/IF
2665 ;C IF -- IFadr initialize conditional forward branch
2666 FORTHWORDIMM "IF" ; immediate
2669 MOV &DDP,TOS ; -- HERE
2670 ADD #4,&DDP ; compile one word, reserve one word
2671 MOV #QBRAN,0(TOS) ; -- HERE compile QBRAN
2672 CELLPLUS ADD #2,TOS ; -- HERE+2=IFadr
2675 ;https://forth-standard.org/standard/core/ELSE
2676 ;C ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack
2677 FORTHWORDIMM "ELSE" ; immediate
2678 ELSS ADD #4,&DDP ; make room to compile two words
2679 MOV &DDP,W ; W=HERE+4
2681 MOV W,0(TOS) ; HERE+4 ==> [IFadr]
2683 MOV W,TOS ; -- ELSEadr
2686 ;https://forth-standard.org/standard/core/THEN
2687 ;C THEN IFadr -- resolve forward branch
2688 FORTHWORDIMM "THEN" ; immediate
2689 THEN MOV &DDP,0(TOS) ; -- IFadr
2693 ;https://forth-standard.org/standard/core/BEGIN
2694 ;C BEGIN -- BEGINadr initialize backward branch
2695 FORTHWORDIMM "BEGIN" ; immediate
2696 BEGIN MOV #HERE,PC ; BR HERE
2698 ;https://forth-standard.org/standard/core/UNTIL
2699 ;C UNTIL BEGINadr -- resolve conditional backward branch
2700 FORTHWORDIMM "UNTIL" ; immediate
2702 UNTIL1 ADD #4,&DDP ; compile two words
2703 MOV &DDP,W ; W = HERE
2704 MOV X,-4(W) ; compile Bran or qbran at HERE
2705 MOV TOS,-2(W) ; compile bakcward adr at HERE+2
2709 ;https://forth-standard.org/standard/core/AGAIN
2710 ;X AGAIN BEGINadr -- resolve uncondionnal backward branch
2711 FORTHWORDIMM "AGAIN" ; immediate
2715 ;https://forth-standard.org/standard/core/WHILE
2716 ;C WHILE BEGINadr -- WHILEadr BEGINadr
2717 FORTHWORDIMM "WHILE" ; immediate
2721 ;https://forth-standard.org/standard/core/REPEAT
2722 ;C REPEAT WHILEadr BEGINadr -- resolve WHILE loop
2723 FORTHWORDIMM "REPEAT" ; immediate
2725 .word AGAIN,THEN,EXIT
2727 ;https://forth-standard.org/standard/core/
2729 ;C DO -- DOadr L: -- 0
2730 FORTHWORDIMM "DO" ; immediate
2733 ADD #2,&DDP ; make room to compile xdo
2734 MOV &DDP,TOS ; -- HERE+2
2735 MOV #xdo,-2(TOS) ; compile xdo
2736 ADD #2,&LEAVEPTR ; -- HERE+2 LEAVEPTR+2
2738 MOV #0,0(W) ; -- HERE+2 L-- 0
2741 ;https://forth-standard.org/standard/core/LOOP
2742 ;C LOOP DOadr -- L-- an an-1 .. a1 0
2743 FORTHWORDIMM "LOOP" ; immediate
2745 ENDLOOP ADD #4,&DDP ; make room to compile two words
2747 MOV X,-4(W) ; xloop --> HERE
2748 MOV TOS,-2(W) ; DOadr --> HERE+2
2749 ; resolve all "leave" adr
2750 LEAVELOOP MOV &LEAVEPTR,TOS ; -- Adr of top LeaveStack cell
2751 SUB #2,&LEAVEPTR ; --
2752 MOV @TOS,TOS ; -- first LeaveStack value
2753 CMP #0,TOS ; -- = value left by DO ?
2755 MOV W,0(TOS) ; move adr after loop as UNLOOP adr
2757 ENDLOOPEND MOV @PSP+,TOS
2760 ;https://forth-standard.org/standard/core/PlusLOOP
2761 ;C +LOOP adrs -- L-- an an-1 .. a1 0
2762 FORTHWORDIMM "+LOOP" ; immediate
2763 PLUSLOOP MOV #xploop,X
2766 ;https://forth-standard.org/standard/core/LEAVE
2767 ;C LEAVE -- L: -- adrs
2768 FORTHWORDIMM "LEAVE" ; immediate
2769 LEAV MOV &DDP,W ; compile three words
2770 MOV #UNLOOP,0(W) ; [HERE] = UNLOOP
2771 MOV #BRAN,2(W) ; [HERE+2] = BRAN
2772 ADD #6,&DDP ; [HERE+4] = take word for AfterLOOPadr
2776 MOV W,0(X) ; leave HERE+4 on LEAVEPTR stack
2779 ;https://forth-standard.org/standard/core/MOVE
2780 ;C MOVE addr1 addr2 u -- smart move
2781 ; VERSION FOR 1 ADDRESS UNIT = 1 CHAR
2784 MOV @PSP+,Y ; dest adrs
2785 MOV @PSP+,X ; src adrs
2786 MOV @PSP+,TOS ; pop new TOS
2788 JZ MOVE_X ; already made !
2789 CMP X,Y ; Y-X ; dst - src
2790 JZ MOVE_X ; already made !
2791 JC MOVEUP ; U>= if dst > src
2792 MOVEDOWN MOV.B @X+,0(Y) ; if X=src > Y=dst copy W bytes down
2797 MOVEUP ADD W,Y ; start at end
2801 MOVUP2 MOV.B @X,0(Y) ; if X=src < Y=dst copy W bytes up
2807 ;-------------------------------------------------------------------------------
2808 ; WORDS SET for VOCABULARY, not ANS compliant
2809 ;-------------------------------------------------------------------------------
2811 ;X VOCABULARY -- create a vocabulary
2813 .IFDEF VOCABULARY_SET
2815 FORTHWORD "VOCABULARY"
2820 .word lit,0,COMMA ; will keep the NFA of the last word of the future created vocabularies
2822 .word lit,THREADS,lit,0,xdo
2823 VOCABULOOP .word lit,0,COMMA
2824 .word xloop,VOCABULOOP
2826 .word HERE ; link via LASTVOC the future created vocabularies
2827 .word LIT,LASTVOC,DUP
2828 .word FETCH,COMMA ; compile [LASTVOC] to HERE+
2829 .word STORE ; store (HERE - CELL) to LASTVOC
2830 .word DOES ; compile CFA and PFA for the future defined vocabulary
2832 .ENDIF ; VOCABULARY_SET
2834 VOCDOES .word LIT,CONTEXT,STORE
2837 ;X FORTH -- ; set FORTH the first context vocabulary; FORTH is and must be the first vocabulary
2838 .IFDEF VOCABULARY_SET
2840 .ENDIF ; VOCABULARY_SET
2841 FORTH ; leave BODYFORTH on the stack and run VOCDOES
2842 mDODOES ; Code Field Address (CFA) of FORTH
2843 PFAFORTH .word VOCDOES ; Parameter Field Address (PFA) of FORTH
2844 BODYFORTH ; BODY of FORTH
2848 .word lastforthword1
2850 .word lastforthword1
2851 .word lastforthword2
2852 .word lastforthword3
2854 .word lastforthword1
2855 .word lastforthword2
2856 .word lastforthword3
2857 .word lastforthword4
2858 .word lastforthword5
2859 .word lastforthword6
2860 .word lastforthword7
2862 .word lastforthword1
2863 .word lastforthword2
2864 .word lastforthword3
2865 .word lastforthword4
2866 .word lastforthword5
2867 .word lastforthword6
2868 .word lastforthword7
2869 .word lastforthword8
2870 .word lastforthword9
2871 .word lastforthword10
2872 .word lastforthword11
2873 .word lastforthword12
2874 .word lastforthword13
2875 .word lastforthword14
2876 .word lastforthword15
2878 .word lastforthword1
2879 .word lastforthword2
2880 .word lastforthword3
2881 .word lastforthword4
2882 .word lastforthword5
2883 .word lastforthword6
2884 .word lastforthword7
2885 .word lastforthword8
2886 .word lastforthword9
2887 .word lastforthword10
2888 .word lastforthword11
2889 .word lastforthword12
2890 .word lastforthword13
2891 .word lastforthword14
2892 .word lastforthword15
2893 .word lastforthword16
2894 .word lastforthword17
2895 .word lastforthword18
2896 .word lastforthword19
2897 .word lastforthword20
2898 .word lastforthword21
2899 .word lastforthword22
2900 .word lastforthword23
2901 .word lastforthword24
2902 .word lastforthword25
2903 .word lastforthword26
2904 .word lastforthword27
2905 .word lastforthword28
2906 .word lastforthword29
2907 .word lastforthword30
2908 .word lastforthword31
2910 .ELSECASE ; = CASE 1
2912 .word voclink ; here, voclink = 0
2915 ;X ALSO -- make room to put a vocabulary as first in context
2916 .IFDEF VOCABULARY_SET
2918 .ENDIF ; VOCABULARY_SET
2919 ALSO MOV #12,W ; -- move up 6 words, 8th word of CONTEXT area must remain to 0
2920 MOV #CONTEXT,X ; X=src
2921 MOV #CONTEXT+2,Y ; Y=dst
2922 JMP MOVEUP ; src < dst
2924 ;X PREVIOUS -- pop last vocabulary out of context
2925 .IFDEF VOCABULARY_SET
2926 FORTHWORD "PREVIOUS"
2927 .ENDIF ; VOCABULARY_SET
2928 PREVIOUS MOV #14,W ; move down 7 words, with recopy of the 8th word equal to 0
2929 MOV #CONTEXT+2,X ; X=src
2930 MOV #CONTEXT,Y ; Y=dst
2931 JMP MOVEDOWN ; src > dst
2933 ;X ONLY -- cut context list to access only first vocabulary, ex.: FORTH ONLY
2934 .IFDEF VOCABULARY_SET
2936 .ENDIF ; VOCABULARY_SET
2937 ONLY MOV #0,&CONTEXT+2
2940 ;X DEFINITIONS -- set last context vocabulary as entry for further defining words
2941 .IFDEF VOCABULARY_SET
2942 FORTHWORD "DEFINITIONS"
2943 .ENDIF ; VOCABULARY_SET
2944 DEFINITIONS MOV &CONTEXT,&CURRENT
2947 ;-------------------------------------------------------------------------------
2948 ; IMPROVED ON/OFF AND RESET
2949 ;-------------------------------------------------------------------------------
2951 STATE_DOES ; execution part of PWR_STATE ; sorry, doesn't restore search order pointers
2952 .word FORTH,ONLY,DEFINITIONS
2953 FORTHtoASM ; -- BODY IP is free
2954 MOV @TOS+,W ; -- BODY+2 W = old VOCLINK = VLK
2955 MOV W,&LASTVOC ; -- BODY+2 restore LASTVOC
2956 MOV @TOS,TOS ; -- OLD_DP
2957 MOV TOS,&DDP ; -- DP restore DP
2958 ; then restore words link(s) with it value < old DP
2960 .CASE 1 ; mono thread vocabularies
2961 MARKALLVOC MOV W,Y ; -- DP W=VLK Y=VLK
2962 MRKWORDLOOP MOV -2(Y),Y ; -- DP W=VLK Y=NFA
2963 CMP Y,TOS ; -- DP CMP = TOS-Y : OLD_DP-NFA
2964 JNC MRKWORDLOOP ; loop back if TOS<Y : OLD_DP<NFA
2965 MOV Y,-2(W) ; W=VLK X=THD Y=NFA refresh thread with good NFA
2966 MOV @W,W ; -- DP W=[VLK] = next voclink
2967 CMP #0,W ; -- DP W=[VLK] = next voclink end of vocs ?
2968 JNZ MARKALLVOC ; -- DP W=VLK no : loopback
2970 .ELSECASE ; multi threads vocabularies
2971 MARKALLVOC MOV #THREADS,IP ; -- DP W=VLK
2972 MOV W,X ; -- DP W=VLK X=VLK
2973 MRKTHRDLOOP MOV X,Y ; -- DP W=VLK X=VLK Y=VLK
2974 SUB #2,X ; -- DP W=VLK X=THD (thread ((case-2)to0))
2975 MRKWORDLOOP MOV -2(Y),Y ; -- DP W=VLK Y=NFA
2976 CMP Y,TOS ; -- DP CMP = TOS-Y : DP-NFA
2977 JNC MRKWORDLOOP ; loop back if TOS<Y : DP<NFA
2978 MARKTHREAD MOV Y,0(X) ; W=VLK X=THD Y=NFA refresh thread with good NFA
2979 SUB #1,IP ; -- DP W=VLK X=THD Y=NFA IP=CFT-1
2980 JNZ MRKTHRDLOOP ; loopback to compare NFA in next thread (thread-1)
2981 MOV @W,W ; -- DP W=[VLK] = next voclink
2982 CMP #0,W ; -- DP W=[VLK] = next voclink end of vocs ?
2983 JNZ MARKALLVOC ; -- DP W=VLK no : loopback
2985 .ENDCASE ; of THREADS ; -- DP
2990 FORTHWORD "PWR_STATE" ; executed by power ON, reinitializes dictionary in state defined by PWR_HERE
2991 PWR_STATE mDODOES ; DOES part of MARKER : resets pointers DP, voclink and latest
2992 .word STATE_DOES ; execution vector of PWR_STATE
2993 MARKVOC .word lastvoclink ; initialised by forthMSP430FR.asm as voclink value
2994 MARKDP .word ROMDICT ; initialised by forthMSP430FR.asm as DP value
2996 FORTHWORD "RST_STATE" ; executed by <reset>, reinitializes dictionary in state defined by RST_HERE;
2997 RST_STATE MOV &INIVOC,&MARKVOC ; INI value saved in FRAM
2998 MOV &INIDP,&MARKDP ; INI value saved in FRAM
3001 FORTHWORD "PWR_HERE" ; define dictionnary bound for power ON
3002 PWR_HERE MOV &LASTVOC,&MARKVOC
3006 FORTHWORD "RST_HERE" ; define dictionnary bound for <reset>...
3007 RST_HERE MOV &LASTVOC,&INIVOC
3009 JMP PWR_HERE ; ...and also for power ON...
3011 FORTHWORD "WIPE" ; restore the program as it was in forthMSP430FR.txt file
3012 WIPE ; reset JTAG and BSL signatures ; unlock JTAG, SBW and BSL
3013 MOV #16,X ; max known SIGNATURES length = 10
3015 MOV #-1,SIGNATURES(X) ; reset signature; WARNING ! DON'T CHANGE THIS IMMEDIATE VALUE !
3017 CALL #WIP_DEFER ; set default execute part of all factory primary DEFERred words
3018 MOV #ROMDICT,&INIDP ; reinit this 2 factory values
3019 MOV #lastvoclink,&INIVOC
3020 JMP RST_STATE ; then execute RST_STATE and PWR_STATE
3022 ; ------------------------------------------------------------------------------
3023 ; forthMSP430FR : WARM
3024 ; ------------------------------------------------------------------------------
3026 ;Z WARM -- ; deferred word used to init your application
3027 ; define this word: : START ...init app here... LIT RECURSE IS WARM (WARM) ;
3029 WARM MOV @PC+,PC ;3 Code Field Address (CFA) of WARM
3030 PFAWARM .word BODYWARM ; Parameter Field Address (PFA) of WARM
3031 BODYWARM ; BODY of WARM (default execution of WARM)
3033 ; MOV &SYSSNIV,0(PSP)
3034 ; MOV &SYSUNIV,2(PSP)
3035 MOV &SAVE_SYSRSTIV,TOS ; to display it
3038 .byte 6,13,1Bh,"[7m#" ; CR + cmd "reverse video" + #
3040 .word DOT ; display signed SAVE_SYSRSTIV
3041 ; .word DOT ; display SYSSNIV
3042 ; .word DOT ; display SYSUNIV
3044 .byte 31,"FastForth ",VER," (C)J.M.Thoorens "
3046 .word LIT,FRAM_FULL,HERE,MINUS,UDOT
3048 .byte 11,"bytes free ";
3049 .word QABORTYESNOECHO ; NOECHO state enables any app to execute COLD or WARM without terminal connexion
3053 ;-------------------------------------------------------------------------------
3054 ; RESET : Initialisation limited to FORTH usage : I/O, RAM, RTC
3055 ; all unused I/O are set as input with pullup resistor
3056 ;-------------------------------------------------------------------------------
3058 ;Z COLD -- performs a software reset
3060 COLD MOV #0A500h+PMMSWBOR,&PMMCTL0
3063 .include "Target.asm" ; include target specific init code
3069 JNZ INITRAM ; 6~ loop
3071 ; fill all interrupt VECTors with RESET
3072 MOV #VECT_LEN,X ;2 length of vectors area
3073 RESETINT SUB #2,X ;1
3074 MOV #RESET,VECT_ORG(X) ;4 begin at end of area
3075 JNZ RESETINT ;2 endloop when VECT_ORG(X) = VECT_ORG
3077 ; reset default TERMINAL vector interrupt and LPM0 mode for terminal use
3078 MOV #TERMINAL_INT,&TERMVEC
3079 MOV #CPUOFF+GIE,&LPM_MODE
3081 ;-------------------------------------------------------------------------------
3082 ; RESET : INIT FORTH machine
3083 ;-------------------------------------------------------------------------------
3084 MOV #RSTACK,RSP ; init return stack
3085 MOV #PSTACK,PSP ; init parameter stack
3088 MOV #xdocol,rDOCOL ;
3091 .CASE 3 ; inlined DOCOL, do nothing here
3095 MOV #xdodoes,rDODOES
3097 MOV #10,&BASE ; init BASE
3098 MOV #-1,&CAPS ; init CAPS ON
3100 ;-------------------------------------------------------------------------------
3101 ; RESET : test TERM_TXD before init TERM_UART I/O
3102 ;-------------------------------------------------------------------------------
3103 BIC #LOCKLPM5,&PM5CTL0 ; activate all previous I/O settings before DEEP_RST test
3104 MOV &SAVE_SYSRSTIV,Y ;3
3105 BIT.B #TXD,&TERM_IN ; TERM_TXD wired to GND via 4k7 resistor ?
3107 XOR #-1,Y ;1 yes : force DEEP_RST (WIPE + COLD)
3108 ADD #1,Y ;1 to display SAVE_SYSRSTIV as negative value
3109 MOV Y,&SAVE_SYSRSTIV ;3 save
3112 ;-------------------------------------------------------------------------------
3113 ; RESET : INIT TERM_UART
3114 ;-------------------------------------------------------------------------------
3115 MOV #0081h,&TERMCTLW0 ; Configure TERM_UART UCLK = SMCLK
3116 MOV &TERMBRW_RST,&TERMBRW ; RST value in FRAM
3117 MOV &TERMMCTLW_RST,&TERMMCTLW ; RST value in FRAM
3118 BIS.B #TERM_BUS,&TERM_SEL ; Configure pins TXD & RXD for TERM_UART (PORTx_SEL0 xor PORTx_SEL1)
3119 ; TERM_DIR is controlled by eUSCI_Ax module
3120 BIC #UCSWRST,&TERMCTLW0 ; release from reset...
3121 BIS #UCRXIE,&TERMIE ; ... then enable RX interrupt for wake up on terminal input
3123 ;-------------------------------------------------------------------------------
3124 ; RESET : Select POWER_ON|<reset>|DEEP_RST from Y = SAVE_SYSRSTIV
3125 ;-------------------------------------------------------------------------------
3127 SelectReset MOV #COLD_END,IP ; define return of WIPE,RST_STATE,PWR_STATE
3128 CMP #0Ah,Y ; reset event = security violation BOR ???? not documented...
3129 JZ WIPE ; Add WIPE to this reset to do DEEP_RST --------------
3130 CMP #16h,Y ; reset event > software POR : failure or DEEP_RST request
3131 JHS WIPE ; U>= ; Add WIPE to this reset to do DEEP_RST
3132 CMP #2,Y ; reset event = Brownout ?
3133 JNZ RST_STATE ; else execute RST_STATE, return to COLD_END
3134 JZ PWR_STATE ; yes execute PWR_STATE, return to COLD_END
3136 ;-------------------------------------------------------------------------------
3137 ; RESET : INIT SD_Card option
3138 ;-------------------------------------------------------------------------------
3140 .IFNDEF SD_CARD_LOADER ;
3141 .word WARM ; the next step
3144 .IF RAM_LEN < 2048 ; case of MSP430FR57xx : SD datas are in FRAM
3145 MOV #SD_LEN,X ; so are not initialised by COLD/RESET
3146 ClearSDdata SUB #2,X ;
3150 BIT.B #SD_CD,&SD_CDIN ; SD_memory in SD_Card module ?
3152 .include "forthMSP430FR_SD_INIT.asm";
3156 ;-------------------------------------------------------------------------------
3158 ;-------------------------------------------------------------------------------
3159 .IFDEF MSP430ASSEMBLER
3160 .include "forthMSP430FR_ASM.asm"
3163 ;-------------------------------------------------------------------------------
3164 ; SD CARD FAT OPTIONS
3165 ;-------------------------------------------------------------------------------
3166 .IFDEF SD_CARD_LOADER
3167 .include "forthMSP430FR_SD_LowLvl.asm" ; SD primitives
3168 .include "forthMSP430FR_SD_LOAD.asm" ; SD LOAD driver
3169 ;---------------------------------------------------------------------------
3170 ; SD CARD READ WRITE
3171 ;---------------------------------------------------------------------------
3172 .IFDEF SD_CARD_READ_WRITE
3173 .include "forthMSP430FR_SD_RW.asm" ; SD Read/Write driver
3175 ;-----------------------------------------------------------------------
3177 ;-----------------------------------------------------------------------
3179 .include "ADDON/SD_TOOLS.asm"
3183 ;-------------------------------------------------------------------------------
3184 ; UTILITY WORDS OPTION
3185 ;-------------------------------------------------------------------------------
3187 .include "ADDON/UTILITY.asm"
3190 ;-------------------------------------------------------------------------------
3191 ; FIXED POINT OPERATORS OPTION
3192 ;-------------------------------------------------------------------------------
3194 .include "ADDON/FIXPOINT.asm"
3197 ;-------------------------------------------------------------------------------
3198 ; UART to I2C bridge OPTION
3199 ;-------------------------------------------------------------------------------
3200 .IFDEF UARTtoI2C ; redirects TERMINAL on to I2C address
3201 .include "ADDON/UART2MI2C.asm"
3204 ;-------------------------------------------------------------------------------
3205 ; ADD HERE YOUR PROGRAM TO BE INTEGRATED IN CORE (protected against WIPE)
3206 ;vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
3210 ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3211 ; ADD HERE YOUR PROGRAM TO BE INTEGRATED IN CORE (protected against WIPE)
3212 ;-------------------------------------------------------------------------------
3214 ;-------------------------------------------------------------------------------
3215 ; RESOLVE ASSEMBLY PTR
3216 ;-------------------------------------------------------------------------------
3218 .include "ResolveThreads.mac"