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 + 3974 bytes
48 ;MSP_EXP430FR5969 ; compile for MSP-EXP430FR5969 launchpad ; 26 + 3962 bytes
49 MSP_EXP430FR5994 ;; compile for MSP-EXP430FR5994 launchpad ; 26 + 3980 bytes
50 ;MSP_EXP430FR6989 ; compile for MSP-EXP430FR6989 launchpad ; 26 + 3990 bytes
51 ;MSP_EXP430FR4133 ; compile for MSP-EXP430FR4133 launchpad ; 26 + 4024 bytes
52 ;MSP_EXP430FR2355 ; compile for MSP-EXP430FR2355 launchpad ; 26 + 3956 bytes
53 ;MSP_EXP430FR2433 ; compile for MSP-EXP430FR2433 launchpad ; 26 + 3942 bytes
54 ;CHIPSTICK_FR2433 ; compile for the "CHIPSTICK" of M. Ken BOAK ; 26 + 3934 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 16 ; 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 Q15.16 numbers
73 LOWERCASE ;; + 46 bytes : enables to write strings in lowercase.
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 CODENN (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 (thatcan 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 ; + 452 bytes : add Q15.16 words HOLDS F+ F- F/ F* F#S F. S>F 2@ 2CONSTANT FIXPOINT.f
88 UTILITY ;; + 426/508 bytes : 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 5000000 ; 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 ; ----- RAMSTART
265 LSTACK_SIZE .equ 16 ; | grows up
268 PSTACK_SIZE .equ 48 ; | grows down
270 ;PSTACK=S0 ; ----- RAMSTART + $80
272 RSTACK_SIZE .equ 48 ; | grows down
274 ;RSTACK=R0 ; ----- RAMSTART + $E0
276 ; names bytes ; comments
278 ;PAD ; ----- RAMSTART + $E4
280 PAD_LEN .equ 84 ; | grows up (ans spec. : PAD >= 84 chars)
282 ;PAD_END ; ----- RAMSTART + $138
285 ;TIB ; ----- RAMSTART + $13C
287 TIB_LEN .equ 84 ; | grows up (ans spec. : TIB >= 80 chars)
289 ;HOLDS_ORG ; ------RAMSTART + $190
291 HOLD_SIZE .equ 34 ; | grows down (ans spec. : HOLD_SIZE >= (2*n) + 2 char, with n = 16 bits/cell
293 ;BASE_HOLD ; ----- RAMSTART + $1B2
297 ; ----- RAMSTART + $1E4
301 ; variables system END ; ----- RAMSTART + $1FC
304 ;SD_BUF ; ----- RAMSTART + $200
308 ; ----- RAMSTART + $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 ; RAMSTART + $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 ; RAMSTART + $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 ; RAMSTART + $1EE : free for user ;
359 ; ----------------------------------;
362 ; --------------------------------------------------
363 ; RAMSTART + $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 .IFDEF RAM_1K ; if RAM = 1K (FR57xx) the variables below are in INFO space (FRAM)
424 SD_ORG_DATA .equ INFO_BASE_END+18 ; 8 words free to set some core routines addresses + 1 word guard...
425 ; ...while preserving FRAM area SD_LEN_DATA.
427 .ELSE ; if RAM >= 2k the variables below are in RAM
429 SD_ORG_DATA .equ SD_BUFEND+2 ; 1 word guard
434 ; ---------------------------------------
435 ; FAT FileSystemInfos
436 ; ---------------------------------------
437 FATtype .equ SD_ORG_DATA+0
438 BS_FirstSectorL .equ SD_ORG_DATA+2 ; init by SD_Init, used by RW_Sector_CMD
439 BS_FirstSectorH .equ SD_ORG_DATA+4 ; init by SD_Init, used by RW_Sector_CMD
440 OrgFAT1 .equ SD_ORG_DATA+6 ; init by SD_Init,
441 FATSize .equ SD_ORG_DATA+8 ; init by SD_Init,
442 OrgFAT2 .equ SD_ORG_DATA+10 ; init by SD_Init,
443 OrgRootDIR .equ SD_ORG_DATA+12 ; init by SD_Init, (FAT16 specific)
444 OrgClusters .equ SD_ORG_DATA+14 ; init by SD_Init, Sector of Cluster 0
445 SecPerClus .equ SD_ORG_DATA+16 ; init by SD_Init, byte size
447 SD_LOW_LEVEL .equ SD_ORG_DATA+18
448 ; ---------------------------------------
450 ; ---------------------------------------
451 SD_CMD_FRM .equ SD_LOW_LEVEL ; SD_CMDx inverted frame ${CRC7,ll,LL,hh,HH,CMD}
452 SectorL .equ SD_LOW_LEVEL+6
453 SectorH .equ SD_LOW_LEVEL+8
455 ; ---------------------------------------
457 ; ---------------------------------------
458 BufferPtr .equ SD_LOW_LEVEL+10
459 BufferLen .equ SD_LOW_LEVEL+12
461 SD_FAT_LEVEL .equ SD_LOW_LEVEL+14
462 ; ---------------------------------------
464 ; ---------------------------------------
465 ClusterL .equ SD_FAT_LEVEL ;
466 ClusterH .equ SD_FAT_LEVEL+2 ;
467 NewClusterL .equ SD_FAT_LEVEL+4 ;
468 NewClusterH .equ SD_FAT_LEVEL+6 ;
469 CurFATsector .equ SD_FAT_LEVEL+8 ; current FATSector of last free cluster
471 ; ---------------------------------------
473 ; ---------------------------------------
474 DIRClusterL .equ SD_FAT_LEVEL+10 ; contains the Cluster of current directory ; = 1 as FAT16 root directory
475 DIRClusterH .equ SD_FAT_LEVEL+12 ; contains the Cluster of current directory ; = 1 as FAT16 root directory
476 EntryOfst .equ SD_FAT_LEVEL+14
478 ; ---------------------------------------
480 ; ---------------------------------------
481 CurrentHdl .equ SD_FAT_LEVEL+16 ; contains the address of the last opened file structure, or 0
483 ; ---------------------------------------
484 ; Load file operation
485 ; ---------------------------------------
486 pathname .equ SD_FAT_LEVEL+18 ; start address
487 EndOfPath .equ SD_FAT_LEVEL+20 ; end address
489 ; ---------------------------------------
491 FirstHandle .equ SD_FAT_LEVEL+22
493 ; ---------------------------------------
495 ; ---------------------------------------
496 ; three handle tokens :
497 ; HDLB_Token= 0 : free handle
499 ; = 2 : file updated (write)
500 ; =-1 : LOAD"ed file (source file)
503 HDLW_PrevHDL .equ 0 ; previous handle
504 HDLB_Token .equ 2 ; token
505 HDLB_ClustOfst .equ 3 ; Current sector offset in current cluster (Byte)
506 HDLL_DIRsect .equ 4 ; Dir SectorL
507 HDLH_DIRsect .equ 6 ; Dir SectorH
508 HDLW_DIRofst .equ 8 ; SD_BUF offset of Dir entry
509 HDLL_FirstClus .equ 10 ; File First ClusterLo (identify the file)
510 HDLH_FirstClus .equ 12 ; File First ClusterHi (identify the file)
511 HDLL_CurClust .equ 14 ; Current ClusterLo
512 HDLH_CurClust .equ 16 ; Current ClusterHi
513 HDLL_CurSize .equ 18 ; written size / not yet read size (Long)
514 HDLH_CurSize .equ 20 ; written size / not yet read size (Long)
515 HDLW_BUFofst .equ 22 ; SD_BUF offset ; used by LOAD"
518 .IFDEF RAM_1K ; RAM_Size = 1k: due to the lack of RAM, PAD is SDIB
520 HandleMax .equ 5 ; and not 8 to respect INFO size (FRAM)
522 HandleEnd .equ FirstHandle+handleMax*HandleLenght
524 LOADPTR .equ HandleEnd
525 LOAD_STACK .equ HandleEnd+2
526 LOADSTACK_SIZE .equ HandleMax+1 ; make room for 3 words * handles
527 LoadStackEnd .equ LOAD_STACK+LOADSTACK_SIZE*6
529 SDIB_I2CADR .equ PAD_ORG-4
530 SDIB_I2CCNT .equ PAD_ORG-2
531 SDIB_ORG .equ PAD_ORG
533 SD_END_DATA .equ LoadStackEnd
534 SD_LEN_DATA .equ SD_END_DATA-SD_ORG_DATA
536 .ELSEIF ; RAM_Size > 1k all is in RAM
540 HandleEnd .equ FirstHandle+handleMax*HandleLenght
542 LOADPTR .equ HandleEnd
543 LOAD_STACK .equ HandleEnd+2
544 LOADSTACK_SIZE .equ HandleMax+1 ; make room for 3 words * handles
545 LoadStackEnd .equ LOAD_STACK+LOADSTACK_SIZE*6 ; 3 words by handle
547 SDIB_I2CADR .equ SDIB_ORG-4
548 SDIB_I2CCNT .equ SDIB_ORG-2
549 SDIB_ORG .equ LoadStackEnd+4
550 SDIB_LEN .equ 84 ; = TIB_LEN = PAD_LEN
552 SD_END_DATA .equ SDIB_ORG+SDIB_LEN
557 .ENDIF ; SD_CARD_LOADER
560 ;-------------------------------------------------------------------------------
561 ; DTCforthMSP430FR5xxx program (FRAM) memory
562 ;-------------------------------------------------------------------------------
566 ;-------------------------------------------------------------------------------
567 ; DEFINING EXECUTIVE WORDS - DTC model
568 ;-------------------------------------------------------------------------------
570 ;-------------------------------------------------------------------------------
571 ; very nice FAST FORTH added feature:
572 ;-------------------------------------------------------------------------------
573 ; as IP is always computed from the PC value, we can place low level to high level
574 ; switches "COLON" or "LO2HI" anywhere in a word, i.e. not only at its beginning
575 ; as ITC competitors.
576 ;-------------------------------------------------------------------------------
578 RSP .reg R1 ; RSP = Return Stack Pointer (return stack)
580 ; DOxxx registers ; must be saved before use and restored after use
584 rDOCOL .reg R7 ; COLD defines xdocol as R7 content
587 M .reg r6 ; ex. PUSHM L,N
598 ; Forth virtual machine
599 IP .reg R13 ; interpretative pointer
600 TOS .reg R14 ; first PSP cell
601 PSP .reg R15 ; PSP = Parameters Stack Pointer (stack data)
603 mNEXT .MACRO ; return for low level words (written in assembler)
604 MOV @IP+,PC ; 4 fetch code address into PC, IP=PFA
605 .ENDM ; 4 cycles,1word = ITC -2cycles -1 word
607 NEXT .equ 4D30h ; 4 MOV @IP+,PC
609 FORTHtoASM .MACRO ; compiled by HI2LO
611 .ENDM ; 0 cycle, 1 word
616 ;-------------------------------------------------------------------------------
617 .CASE 1 ; DOCOL = CALL rDOCOL
618 ;-------------------------------------------------------------------------------
621 xdocol MOV @RSP+,W ; 2
622 PUSH IP ; 3 save old IP on return stack
623 MOV W,IP ; 1 set new IP to PFA
624 MOV @IP+,PC ; 4 = NEXT
627 ASMtoFORTH .MACRO ; compiled by LO2HI
628 CALL #EXIT ; 2 words, 10 cycles
631 mDOCOL .MACRO ; compiled by : and by colon
632 CALL rDOCOL ; 1 word, 14 cycles (CALL included) = ITC+4
635 DOCOL1 .equ 1287h ; 4 CALL R7
637 ;-------------------------------------------------------------------------------
638 .CASE 2 ; DOCOL = PUSH IP + CALL rEXIT
639 ;-------------------------------------------------------------------------------
641 rEXIT .reg R7 ; COLD defines EXIT as R7 content
643 ASMtoFORTH .MACRO ; compiled by LO2HI
644 CALL rEXIT ; 1 word, 10 cycles
647 mDOCOL .MACRO ; compiled by : and by COLON
650 .ENDM ; 2 words, 13 cycles = ITC+3
652 DOCOL1 .equ 120Dh ; 3 PUSH IP
653 DOCOL2 .equ 1287h ; 4 CALL rEXIT
655 ;-------------------------------------------------------------------------------
656 .CASE 3 ; inlined DOCOL
657 ;-------------------------------------------------------------------------------
659 R .reg R7 ; Scratch register
661 ASMtoFORTH .MACRO ; compiled by LO2HI
665 .ENDM ; 6 cycles, 3 words
667 mDOCOL .MACRO ; compiled by : and by COLON
672 .ENDM ; 4 words, 9 cycles (ITC-1)
674 DOCOL1 .equ 120Dh ; 3 PUSH IP
675 DOCOL2 .equ 400Dh ; 1 MOV PC,IP
676 DOCOL3 .equ 522Dh ; 1 ADD #4,IP
680 ;-------------------------------------------------------------------------------
681 ; mDOVAR leave on parameter stack the PFA of a VARIABLE definition
682 ;-------------------------------------------------------------------------------
684 mDOVAR .MACRO ; compiled by VARIABLE
685 CALL rDOVAR ; 1 word, 14 cycles (ITC+4)
688 DOVAR .equ 1286h ; CALL rDOVAR ; [rDOVAR] is defined as RFROM by COLD
691 ;-------------------------------------------------------------------------------
692 ; mDOCON leave on parameter stack the [PFA] of a CONSTANT definition
693 ;-------------------------------------------------------------------------------
695 mDOCON .MACRO ; compiled by CONSTANT
696 CALL rDOCON ; 1 word, 16 cycles (ITC+4)
699 DOCON .equ 1285h ; 4 CALL rDOCON ; [rDOCON] is defined as xdocon by COLD
701 xdocon ; -- constant ; 4 for CALL rDOCON
703 MOV TOS,0(PSP) ; 3 save TOS on parameters stack
704 MOV @RSP+,TOS ; 2 TOS = CFA address of master word CONSTANT
705 MOV @TOS,TOS ; 2 TOS = CONSTANT value
706 MOV @IP+,PC ; 4 execute next word
709 ;-------------------------------------------------------------------------------
710 ; mDODOES leave on parameter stack the PFA of a CREATE definition and execute Master word
711 ;-------------------------------------------------------------------------------
713 mDODOES .MACRO ; compiled by DOES>
714 CALL rDODOES ; CALL xdodoes
715 .ENDM ; 1 word, 19 cycles (ITC-2)
717 DODOES .equ 1284h ; 4 CALL rDODOES ; [rDODOES] is defind as xdodoes by COLD
719 xdodoes ; -- a-addr ; 4 for CALL rDODOES
721 MOV TOS,0(PSP) ; 3 save TOS on parameters stack
722 MOV @RSP+,TOS ; 2 TOS = CFA address of master word, i.e. address of its first cell after DOES>
723 PUSH IP ; 3 save IP on return stack
724 MOV @TOS+,IP ; 2 IP = CFA of Master word, TOS = BODY address of created word
725 MOV @IP+,PC ; 4 Execute Master word
727 ;-------------------------------------------------------------------------------
729 ;-------------------------------------------------------------------------------
731 ;https://forth-standard.org/standard/core/EXIT
732 ;C EXIT -- exit a colon definition; CALL #EXIT performs ASMtoFORTH (10 cycles)
733 ; JMP #EXIT performs EXIT
735 EXIT MOV @RSP+,IP ; 2 pop previous IP (or next PC) from return stack
736 MOV @IP+,PC ; 4 = NEXT
739 ;Z lit -- x fetch inline literal to stack
740 ; This is the execution part of LITERAL.
742 lit SUB #2,PSP ; 2 push old TOS..
743 MOV TOS,0(PSP) ; 3 ..onto stack
744 MOV @IP+,TOS ; 2 fetch new TOS value
748 ;-------------------------------------------------------------------------------
750 ;-------------------------------------------------------------------------------
752 ;https://forth-standard.org/standard/core/DUP
753 ;C DUP x -- x x duplicate top of stack
755 DUP SUB #2,PSP ; 2 push old TOS..
756 MOV TOS,0(PSP) ; 3 ..onto stack
759 ;https://forth-standard.org/standard/core/qDUP
760 ;C ?DUP x -- 0 | x x DUP if nonzero
762 QDUP CMP #0,TOS ; 2 test for TOS nonzero
766 ;https://forth-standard.org/standard/core/DROP
767 ;C DROP x -- drop top of stack
769 DROP MOV @PSP+,TOS ; 2
772 ;https://forth-standard.org/standard/core/NIP
773 ;C NIP x1 x2 -- x2 Drop the first item below the top of stack
778 ;https://forth-standard.org/standard/core/SWAP
779 ;C SWAP x1 x2 -- x2 x1 swap top two items
786 ;https://forth-standard.org/standard/core/OVER
787 ;C OVER x1 x2 -- x1 x2 x1
789 OVER MOV TOS,-2(PSP) ; 3 -- x1 (x2) x2
790 MOV @PSP,TOS ; 2 -- x1 (x2) x1
791 SUB #2,PSP ; 2 -- x1 x2 x1
794 ;https://forth-standard.org/standard/core/ROT
795 ;C ROT x1 x2 x3 -- x2 x3 x1
797 ROT MOV @PSP,W ; 2 fetch x2
798 MOV TOS,0(PSP) ; 3 store x3
799 MOV 2(PSP),TOS ; 3 fetch x1
800 MOV W,2(PSP) ; 3 store x2
803 ;https://forth-standard.org/standard/core/toR
804 ;C >R x -- R: -- x push to return stack
810 ;https://forth-standard.org/standard/core/Rfrom
811 ;C R> -- x R: x -- pop from return stack ; CALL #RFROM performs DOVAR
818 ;https://forth-standard.org/standard/core/RFetch
819 ;C R@ -- x R: x -- x fetch from rtn stk
826 ;https://forth-standard.org/standard/core/DEPTH
827 ;C DEPTH -- +n number of items on stack, must leave 0 if stack empty
829 DEPTH MOV TOS,-2(PSP)
831 SUB PSP,TOS ; PSP-S0--> TOS
832 SUB #2,PSP ; post decrement stack...
833 RRA TOS ; TOS/2 --> TOS
836 ;-------------------------------------------------------------------------------
838 ;-------------------------------------------------------------------------------
840 ;https://forth-standard.org/standard/core/Fetch
841 ;C @ a-addr -- x fetch cell from memory
846 ;https://forth-standard.org/standard/core/Store
847 ;C ! x a-addr -- store cell in memory
849 STORE MOV @PSP+,0(TOS) ;4
853 ;https://forth-standard.org/standard/core/CFetch
854 ;C C@ c-addr -- char fetch char from memory
856 CFETCH MOV.B @TOS,TOS ;2
859 ;https://forth-standard.org/standard/core/CStore
860 ;C C! char c-addr -- store char in memory
862 CSTORE MOV.B @PSP+,0(TOS) ;4
867 ;-------------------------------------------------------------------------------
868 ; ARITHMETIC OPERATIONS
869 ;-------------------------------------------------------------------------------
871 ;https://forth-standard.org/standard/core/Plus
872 ;C + n1/u1 n2/u2 -- n3/u3 add n1+n2
877 ;https://forth-standard.org/standard/core/Minus
878 ;C - n1/u1 n2/u2 -- n3/u3 n3 = n1-n2
880 MINUS SUB @PSP+,TOS ;2 -- n2-n1
881 NEGATE XOR #-1,TOS ;1
882 ADD #1,TOS ;1 -- n3 = -(n2-n1)
885 ;https://forth-standard.org/standard/core/OnePlus
886 ;C 1+ n1/u1 -- n2/u2 add 1 to TOS
891 ;https://forth-standard.org/standard/core/OneMinus
892 ;C 1- n1/u1 -- n2/u2 subtract 1 from TOS
897 ;https://forth-standard.org/standard/double/DABS
898 ;C DABS d1 -- |d1| absolute value
900 DABBS AND #-1,TOS ; clear V, set N
901 JGE DABBSEND ; JMP if positive
902 DNEGATE XOR #-1,0(PSP)
908 ;-------------------------------------------------------------------------------
909 ; COMPARAISON OPERATIONS
910 ;-------------------------------------------------------------------------------
912 ;https://forth-standard.org/standard/core/ZeroEqual
913 ;C 0= n/u -- flag return true if TOS=0
915 ZEROEQUAL SUB #1,TOS ; borrow (clear cy) if TOS was 0
916 SUBC TOS,TOS ; TOS=-1 if borrow was set
919 ;https://forth-standard.org/standard/core/Zeroless
920 ;C 0< n -- flag true if TOS negative
922 ZEROLESS ADD TOS,TOS ;1 set carry if TOS negative
923 SUBC TOS,TOS ;1 TOS=-1 if carry was clear
924 XOR #-1,TOS ;1 TOS=-1 if carry was set
927 ;https://forth-standard.org/standard/core/Equal
928 ;C = x1 x2 -- flag test x1=x2
930 EQUAL SUB @PSP+,TOS ;2
931 JNZ TOSFALSE ;2 --> +4
932 TOSTRUE MOV #-1,TOS ;1
935 ;https://forth-standard.org/standard/core/less
936 ;C < n1 n2 -- flag test n1<n2, signed
938 LESS MOV @PSP+,W ;2 W=n1
939 SUB TOS,W ;1 W=n1-n2 flags set
940 LESSNEXT JL TOSTRUE ;2
941 TOSFALSE MOV #0,TOS ;1
944 ;https://forth-standard.org/standard/core/more
945 ;C > n1 n2 -- flag test n1>n2, signed
947 GREATER SUB @PSP+,TOS ;2 TOS=n2-n1
950 ;https://forth-standard.org/standard/core/Zeromore
951 ;C 0> n -- flag true if TOS positive
957 ;https://forth-standard.org/standard/core/Uless
958 ;C U< u1 u2 -- flag test u1<u2, unsigned
961 SUB TOS,W ;1 u1-u2 in W, carry clear if borrow
965 ;-------------------------------------------------------------------------------
966 ; BRANCH and LOOP OPERATORS
967 ;-------------------------------------------------------------------------------
969 ;Z branch -- branch always
973 ;Z ?branch x -- branch if TOS = zero
974 QBRAN CMP #0,TOS ; 1 test TOS value
975 QBRAN1 MOV @PSP+,TOS ; 2 pop new TOS value (doesn't change flags)
976 JZ bran ; 2 if TOS was zero, take the branch = 11 cycles
977 ADD #2,IP ; 1 else skip the branch destination
978 mNEXT ; 4 ==> branch not taken = 10 cycles
980 ;Z 0?branch x -- branch if TOS <> zero
981 QZBRAN SUB #1,TOS ; 1 borrow (clear cy) if TOS was 0
982 SUBC TOS,TOS ; 1 TOS=-1 if borrow was set
986 ;Z (do) n1|u1 n2|u2 -- R: -- sys1 sys2 run-time code for DO
987 ; n1|u1=limit, n2|u2=index
988 xdo MOV #8000h,X ;2 compute 8000h-limit "fudge factor"
990 MOV TOS,Y ;1 loop ctr = index+fudge
991 MOV @PSP+,TOS ;2 pop new TOS
993 PUSHM #2,X ;4 PUSHM X,Y, i.e. PUSHM LIMIT, INDEX
996 ;Z (+loop) n -- R: sys1 sys2 -- | sys1 sys2
997 ; run-time code for +LOOP
998 ; Add n to the loop index. If loop terminates, clean up the
999 ; return stack and skip the branch. Else take the inline branch.
1000 xploop ADD TOS,0(RSP) ;4 increment INDEX by TOS value
1001 MOV @PSP+,TOS ;2 get new TOS, doesn't change flags
1002 xloopnext BIT #100h,SR ;2 is overflow bit set?
1003 JZ bran ;2 no overflow = loop
1004 ADD #2,IP ;1 overflow = loop done, skip branch ofs
1005 UNXLOOP ADD #4,RSP ;1 empty RSP
1006 mNEXT ;4 16~ taken or not taken xloop/loop
1009 ;Z (loop) R: sys1 sys2 -- | sys1 sys2
1010 ; run-time code for LOOP
1011 ; Add 1 to the loop index. If loop terminates, clean up the
1012 ; return stack and skip the branch. Else take the inline branch.
1013 ; Note that LOOP terminates when index=8000h.
1014 xloop ADD #1,0(RSP) ;4 increment INDEX
1017 ;https://forth-standard.org/standard/core/UNLOOP
1018 ;C UNLOOP -- R: sys1 sys2 -- drop loop parms
1022 ;https://forth-standard.org/standard/core/I
1023 ;C I -- n R: sys1 sys2 -- sys1 sys2
1024 ;C get the innermost loop index
1026 II SUB #2,PSP ;1 make room in TOS
1028 MOV @RSP,TOS ;2 index = loopctr - fudge
1032 ;https://forth-standard.org/standard/core/J
1033 ;C J -- n R: 4*sys -- 4*sys
1034 ;C get the second loop index
1036 JJ SUB #2,PSP ; make room in TOS
1038 MOV 4(RSP),TOS ; index = loopctr - fudge
1042 ;-------------------------------------------------------------------------------
1044 ;-------------------------------------------------------------------------------
1046 ;https://forth-standard.org/standard/core/BL
1047 ;C BL -- char an ASCII space
1052 ;-------------------------------------------------------------------------------
1054 ;-------------------------------------------------------------------------------
1056 ;https://forth-standard.org/standard/core/BASE
1057 ;C BASE -- a-addr holds conversion radix
1060 .word BASE ; VARIABLE address in RAM space
1062 ;https://forth-standard.org/standard/core/STATE
1063 ;C STATE -- a-addr holds compiler state
1066 .word STATE ; VARIABLE address in RAM space
1068 ;-------------------------------------------------------------------------------
1069 ; ANS complement OPTION
1070 ;-------------------------------------------------------------------------------
1071 .IFDEF ANS_CORE_COMPLIANT
1072 .include "ADDON\ANS_COMPLEMENT.asm"
1075 ;-------------------------------------------------------------------------------
1076 ; ALIGNMENT OPERATORS OPTION
1077 ;-------------------------------------------------------------------------------
1078 .IFDEF ALIGNMENT ; included in ANS_COMPLEMENT
1079 .include "ADDON\ALIGNMENT.asm"
1082 ;-------------------------------------------------------------------------------
1083 ; PORTABILITY OPERATORS OPTION
1084 ;-------------------------------------------------------------------------------
1086 .include "ADDON\PORTABILITY.asm"
1087 .ENDIF ; PORTABILITY
1089 ;-------------------------------------------------------------------------------
1090 ; DOUBLE OPERATORS OPTION
1091 ;-------------------------------------------------------------------------------
1092 .IFDEF DOUBLE ; included in ANS_COMPLEMENT
1093 .include "ADDON\DOUBLE.asm"
1096 ;-------------------------------------------------------------------------------
1097 ; ARITHMETIC OPERATORS OPTION
1098 ;-------------------------------------------------------------------------------
1099 .IFDEF ARITHMETIC ; included in ANS_COMPLEMENT
1100 .include "ADDON\ARITHMETIC.asm"
1103 .ENDIF ; ANS_COMPLEMENT
1105 ;-------------------------------------------------------------------------------
1107 ;-------------------------------------------------------------------------------
1109 ; Numeric conversion is done last digit first, so
1110 ; the output buffer is built backwards in memory.
1112 ;https://forth-standard.org/standard/core/num-start
1113 ;C <# -- begin numeric conversion (initialize Hold Pointer)
1115 LESSNUM MOV #BASE_HOLD,&HP
1118 ;https://forth-standard.org/standard/core/UMDivMOD
1119 ; UM/MOD udlo|udhi u1 -- r q unsigned 32/16->16
1121 UMSLASHMOD PUSH #DROP ;3 as return address for MU/MOD
1123 ; unsigned 32-BIT DiViDend : 16-BIT DIVisor --> 32-BIT QUOTient, 16-BIT REMainder
1124 ; 2 times faster if DVDhi = 0 (it's the general case)
1126 ; reg division MU/MOD NUM
1127 ; -----------------------------------------
1128 ; S = DVDlo (15-0) = ud1lo = ud1lo
1129 ; TOS = DVDhi (31-16) = ud1hi = ud1hi
1131 ; W = REMlo = REMlo = digit --> char --> -[HP]
1132 ; X = QUOTlo = ud2lo = ud2lo
1133 ; Y = QUOThi = ud2hi = ud2hi
1136 ; MU/MOD DVDlo DVDhi DIVlo -- REMlo QUOTlo QUOThi, used by fixpoint and #
1137 MUSMOD MOV TOS,T ;1 T = DIVlo
1138 MOV @PSP,TOS ;2 TOS = DVDhi
1139 MOV 2(PSP),S ;3 S = DVDlo
1140 MUSMOD1 MOV #0,W ;1 W = REMlo = 0
1141 MUSMOD2 MOV #32,rDODOES ;2 init loop count
1142 CMP #0,TOS ;1 DVDhi=0 ?
1144 RRA rDODOES ;1 yes:loop count / 2
1145 MOV S,TOS ;1 DVDhi <-- DVDlo
1146 MOV #0,S ;1 DVDlo <-- 0
1147 MOV #0,X ;1 QUOTlo <-- 0 (to do QUOThi = 0 at the end of division)
1148 MDIV1 CMP T,W ;1 REMlo U>= DIVlo ?
1149 JNC MDIV2 ;2 no : carry is reset
1150 SUB T,W ;1 yes: REMlo - DIVlo ; carry is set after soustraction!
1151 MDIV2 ADDC X,X ;1 RLC quotLO
1152 ADDC Y,Y ;1 RLC quotHI
1153 SUB #1,rDODOES ;1 Decrement loop counter
1155 ADD S,S ;1 RLA DVDlo
1156 ADDC TOS,TOS ;1 RLC DVDhi
1157 ADDC W,W ;1 RLC REMlo
1159 SUB T,W ;1 REMlo - DIVlo
1162 ENDMDIV MOV #xdodoes,rDODOES;2 restore rDODOES
1163 MOV W,2(PSP) ;3 REMlo in 2(PSP)
1164 MOV X,0(PSP) ;3 QUOTlo in 0(PSP)
1165 MOV Y,TOS ;1 QUOThi in TOS
1166 RET ;4 35 words, about 252/473 cycles, not FORTH executable !
1168 ;https://forth-standard.org/standard/core/num
1169 ;C # ud1lo ud1hi -- ud2lo ud2hi convert 1 digit of output
1171 NUM MOV &BASE,T ;3 T = Divisor
1172 NUM1 MOV @PSP,S ;2 -- DVDlo DVDhi S = DVDlo
1173 SUB #2,PSP ;1 -- DVDlo x DVDhi TOS = DVDhi
1174 CALL #MUSMOD1 ;4 -- REMlo QUOTlo QUOThi
1175 MOV @PSP+,0(PSP) ;4 -- QUOTlo QUOThi
1176 TODIGIT CMP.B #10,W ;2 W = REMlo
1179 TODIGIT1 ADD #30h,W ;2
1180 HOLDW SUB #1,&HP ;3 store W=char --> -[HP]
1185 ;https://forth-standard.org/standard/core/numS
1186 ;C #S udlo:udhi -- udlo:udhi=0 convert remaining digits
1189 .word NUM ; X=QUOTlo
1191 SUB #2,IP ;1 restore NUM return
1192 CMP #0,X ;1 test ud2lo first (generally true)
1194 CMP #0,TOS ;1 then test ud2hi (generally false)
1197 mNEXT ;4 10 words, about 241/417 cycles/char
1199 ;https://forth-standard.org/standard/core/num-end
1200 ;C #> udlo:udhi -- c-addr u end conversion, get string
1202 NUMGREATER MOV &HP,0(PSP)
1207 ;https://forth-standard.org/standard/core/HOLD
1208 ;C HOLD char -- add char to output string
1214 ;https://forth-standard.org/standard/core/SIGN
1215 ;C SIGN n -- add minus sign if n<0
1223 ;https://forth-standard.org/standard/core/Ud
1224 ;C U. u -- display u (unsigned)
1227 .word LESSNUM,lit,0,NUMS,NUMGREATER,TYPE,SPACE,EXIT
1229 ;https://forth-standard.org/standard/double/Dd
1230 ;C D. dlo dhi -- display d (signed)
1233 .word LESSNUM,SWAP,OVER,DABBS,NUMS
1234 .word ROT,SIGN,NUMGREATER,TYPE,SPACE,EXIT
1236 ;https://forth-standard.org/standard/core/d
1237 ;C . n -- display n (signed)
1243 MOV #-1,TOS ; extend sign
1246 ;-------------------------------------------------------------------------------
1247 ; DICTIONARY MANAGEMENT
1248 ;-------------------------------------------------------------------------------
1250 ;https://forth-standard.org/standard/core/HERE
1251 ;C HERE -- addr returns dictionary ptr
1258 ;https://forth-standard.org/standard/core/ALLOT
1259 ;C ALLOT n -- allocate n bytes in dict
1265 ;https://forth-standard.org/standard/core/CComma
1266 ;C C, char -- append char to dict
1274 ; ------------------------------------------------------------------------------
1275 ; TERMINAL I/O, input part
1276 ; ------------------------------------------------------------------------------
1279 ;https://forth-standard.org/standard/core/KEY
1280 ;C KEY -- c wait character from input device ; primary DEFERred word
1284 BODYKEY MOV &TERMRXBUF,Y ; empty buffer
1285 SUB #2,PSP ; 1 push old TOS..
1286 MOV TOS,0(PSP) ; 4 ..onto stack
1288 KEYLOOP BIT #UCRXIFG,&TERMIFG ; loop if bit0 = 0 in interupt flag register
1290 MOV &TERMRXBUF,TOS ;
1294 ;-------------------------------------------------------------------------------
1295 ; INTERPRETER INPUT, the kernel of kernel !
1296 ;-------------------------------------------------------------------------------
1298 .IFDEF SD_CARD_LOADER
1299 .include "forthMSP430FR_SD_ACCEPT.asm"
1300 DEFER_INPUT ; CIB (Current Input Buffer) and ACCEPT must to be redirected for SD_LOAD usage
1305 ; CIB -- addr of Current Input Buffer
1308 .WORD TIB_ORG ; constant, may be DEFERred as SDIB_ORG by OPEN.
1310 ; : REFILL CIB DUP TIB_LEN ACCEPT ; -- CIB CIB len shared by QUIT and [ELSE]
1311 REFILL SUB #6,PSP ;2
1314 MOV &FCIB+2,0(PSP) ;5
1318 ;https://forth-standard.org/standard/core/ACCEPT
1319 ;C ACCEPT addr addr len -- addr len' get line at addr to interpret len' chars
1321 ACCEPT MOV @PC+,PC ;3
1327 ; : REFILL TIB DUP TIB_LEN ACCEPT ; -- TIB TIB len shared by QUIT and [ELSE]
1328 REFILL SUB #6,PSP ;2
1331 MOV #TIB_ORG,0(PSP) ;4
1335 ;https://forth-standard.org/standard/core/ACCEPT
1336 ;C ACCEPT addr addr len -- addr len' get line at addr to interpret len' chars
1340 .ENDIF ; DEFER_INPUT
1342 .IFDEF HALFDUPLEX ; to use FAST FORTH with half duplex input terminal (bluetooth or wifi connexion)
1344 .include "forthMSP430FR_HALFDUPLEX.asm"
1346 .ELSE ; to use FAST FORTH with full duplex terminal (USBtoUART bridge)
1348 ; con speed of TERMINAL link, there are three bottlenecks :
1349 ; 1- time to send XOFF/RTS_high on CR (CR+LF=EOL), first emergency.
1350 ; 2- the char loop time,
1351 ; 3- the time between sending XON/RTS_low and clearing UCRXIFG on first received char,
1352 ; everything must be done to reduce these times, taking into account the necessity of switching to SLEEP (LPMx mode).
1353 ; ----------------------------------;
1354 ; (ACCEPT) I prepare TERMINAL_INT ;
1355 ; ----------------------------------;
1357 .word 1537h ;6 push R7,R6,R5,R4
1359 MOV #ENDACCEPT,S ;2 S = ACCEPT XOFF return
1360 MOV #AKEYREAD1,T ;2 T = default XON return
1361 PUSHM #3,IP ;5 PUSHM IP,S,T, as IP ret, XOFF ret, XON ret
1362 MOV TOS,W ;1 -- addr len
1363 MOV @PSP,TOS ;2 -- org ptr )
1364 ADD TOS,W ;1 -- org ptr W=Bound )
1365 MOV #0Dh,T ;2 T = 'CR' to speed up char loop in part II > prepare stack and registers
1366 MOV #20h,S ;2 S = 'BL' to speed up char loop in part II ) for TERMINAL_INT use
1367 MOV #AYEMIT_RET,IP ;2 IP = return for YEMIT )
1368 BIT #UCRXIFG,&TERMIFG ;3 RX_Int ?
1369 JZ ACCEPTNEXT ;2 no : case of quiet input terminal
1370 MOV &TERMRXBUF,Y ;3 yes: clear RX_Int
1371 CMP #0Ah,Y ;2 received char = LF ? (end of downloading ?)
1372 JNZ RXON ;2 no : RXON return = AKEYREAD1, to process first char of new line.
1373 ACCEPTNEXT ADD #2,RSP ;1 yes: remove AKEYREAD1 as XON return,
1374 MOV #SLEEP,X ;2 and set XON return = SLEEP
1375 PUSHM #5,IP ;7 PUSHM IP,S,T,W,X before SLEEP (and so WAKE on any interrupts)
1376 ; ----------------------------------;
1378 ; ----------------------------------;
1379 .IFDEF TERMINAL3WIRES ;
1380 ; .IF TERMINALBAUDRATE/FREQUENCY <230400 ; Incompatible with baudrate modification on the fly.
1381 RXON_LOOP BIT #UCTXIFG,&TERMIFG ;3 wait the sending end of XON, useless at high baudrates
1384 MOV #17,&TERMTXBUF ;4 move char XON into TX_buf
1386 .IFDEF TERMINAL4WIRES ;
1387 BIC.B #RTS,&HANDSHAKOUT ;4 set RTS low
1389 ; vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv;
1390 ; starts first and 3th stopwatches ;
1391 ; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^;
1392 RET ;4 to BACKGND (End of file download or quiet input) or AKEYREAD1 (get next line of file downloading)
1393 ; ----------------------------------; ...or user defined
1396 ; ----------------------------------;
1398 ; ----------------------------------;
1399 .IFDEF TERMINAL3WIRES ;
1400 MOV #19,&TERMTXBUF ;4 move XOFF char into TX_buf
1402 .IFDEF TERMINAL4WIRES ;
1403 BIS.B #RTS,&HANDSHAKOUT ;4 set RTS high
1405 RET ;4 to ENDACCEPT, ...or user defined
1406 ; ----------------------------------;
1409 ; ----------------------------------;
1410 ASMWORD "SLEEP" ; may be redirected
1411 SLEEP MOV @PC+,PC ;3
1413 BODYSLEEP BIS &LPM_MODE,SR ;3 enter in LPMx sleep mode with GIE=1
1414 ; ----------------------------------; default FAST FORTH mode (for its input terminal use) : LPM0.
1416 ;###############################################################################################################
1417 ;###############################################################################################################
1419 ; ### # # ####### ####### ###### ###### # # ###### ####### ##### # # ####### ###### #######
1420 ; # ## # # # # # # # # # # # # # # # # # # # #
1421 ; # # # # # # # # # # # # # # # # # # # # # #
1422 ; # # # # # ##### ###### ###### # # ###### # ##### ####### ##### ###### #####
1423 ; # # # # # # # # # # # # # # # # # # # # #
1424 ; # # ## # # # # # # # # # # # # # # # # # #
1425 ; ### # # # ####### # # # # ##### # # ##### # # ####### # # #######
1427 ;###############################################################################################################
1428 ;###############################################################################################################
1431 ; here, Fast FORTH sleeps, waiting any interrupt.
1432 ; IP,S,T,W,X,Y registers (R13 to R8) are free for any interrupt routine...
1433 ; ...and so PSP and RSP stacks with their rules of use.
1434 ; remember: in any interrupt routine you must include : BIC #0x78,0(RSP) before RETI
1435 ; to force return to SLEEP.
1436 ; or (bad idea ? previous SR flags are lost) simply : ADD #2 RSP, then RET instead of RETI
1439 ; ==================================;
1440 JMP SLEEP ;2 here is the return for any interrupts, else TERMINAL_INT :-)
1441 ; ==================================;
1444 ; **********************************;
1445 TERMINAL_INT ; <--- TEMR RX interrupt vector, delayed by the LPMx wake up time
1446 ; **********************************; if wake up time increases, max bauds rate decreases...
1447 ; (ACCEPT) part II under interrupt ; Org Ptr -- len'
1448 ; ----------------------------------;
1449 ADD #4,RSP ;1 remove SR and PC from stack, SR flags are lost (unused by FORTH interpreter)
1450 POPM #4,IP ;6 POPM W=buffer_bound, T=0Dh,S=20h, IP=AYEMIT_RET
1451 ; vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv;
1452 ; starts the 2th stopwatch ;
1453 ; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^;
1454 AKEYREAD MOV.B &TERMRXBUF,Y ;3 read character into Y, UCRXIFG is cleared
1455 ; vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv;
1456 ; stops the 3th stopwatch ; 3th bottleneck result : 17~ + LPMx wake_up time ( + 5~ XON loop if F/Bds<230400 )
1457 ; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^;
1459 CMP.B S,Y ;1 printable char ?
1460 JHS ASTORETEST ;2 yes
1461 CMP.B T,Y ;1 char = CR ?
1462 JZ RXOFF ;2 then RET to ENDACCEPT
1463 ; vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv;+ 4 to send RXOFF
1464 ; stops the first stopwatch ;= first bottleneck, best case result: 27~ + LPMx wake_up time..
1465 ; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^; ...or 14~ in case of empty line
1466 CMP.B #8,Y ;1 char = BS ?
1467 JNE WAITaKEY ;2 case of other control chars
1468 ; ----------------------------------;
1469 ; start of backspace ; made only by an human
1470 ; ----------------------------------;
1471 CMP @PSP,TOS ; Ptr = Org ?
1472 JZ WAITaKEY ; yes: do nothing
1473 SUB #1,TOS ; no : dec Ptr
1474 JMP YEMIT1 ; send BS
1475 ; ----------------------------------;
1476 ; end of backspace ;
1477 ; ----------------------------------;
1478 ASTORETEST CMP W,TOS ; 1 Bound is reached ?
1479 JZ YEMIT1 ; 2 yes: send echo then loopback
1480 MOV.B Y,0(TOS) ; 3 no: store char @ Ptr, send echo then loopback
1481 ADD #1,TOS ; 1 increment Ptr
1483 ; .IF TERMINALBAUDRATE/FREQUENCY <230401; Incompatible with baudrate modification on the fly.
1484 BIT #UCTXIFG,&TERMIFG ; 3 wait the sending end of previous char (sent before ACCEPT), useless at high baudrates
1485 JZ YEMIT1 ; 2 but there's no point in wanting to save time here:
1486 ; .ENDIF ; it must be understood that the receiver loses time also when receiving the char.
1488 .IFDEF TERMINAL5WIRES ;
1489 BIT.B #CTS,&HANDSHAKIN ; 3
1492 YEMIT ; hi7/4~ lo:12/9~ send/send_not echo to terminal
1493 .word 4882h ; 4882h = MOV Y,&<next_adr>
1496 ; ----------------------------------;
1497 AYEMIT_RET FORTHtoASM ; 0 YEMII NEXT address; NOP9
1498 SUB #2,IP ; 1 set YEMIT NEXT address to AYEMIT_RET
1499 WAITaKEY BIT #UCRXIFG,&TERMIFG ; 3 new char in TERMRXBUF ?
1500 JNZ AKEYREAD ; 2 yes
1502 ; vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv;
1503 ; stops the 2th stopwatch ; best case result: 26~/22~ (with/without echo) ==> 385/455 kBds/MHz
1504 ; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^;
1506 ; ----------------------------------;
1507 ENDACCEPT ; <--- XOFF return address
1508 ; ----------------------------------;
1509 MOV #LPM0+GIE,&LPM_MODE ; reset LPM_MODE to default mode LPM0 for next line of input stream
1510 CMP #0,&LINE ; if LINE <> 0...
1512 ADD #1,&LINE ; ...increment LINE
1513 ACCEPTEND SUB @PSP+,TOS ; Org Ptr -- len'
1514 MOV @RSP+,IP ; 2 and continue with INTERPRET with GIE=0.
1515 ; So FORTH machine is protected against any interrupt...
1517 POPM #4,R7 ;6 pop R4,R5,R6,R7
1519 mNEXT ; ...until next falling down to LPMx mode of (ACCEPT) part1,
1520 ; **********************************; i.e. when the FORTH interpreter has no more to do.
1522 ; ------------------------------------------------------------------------------
1523 ; TERMINAL I/O, output part
1524 ; ------------------------------------------------------------------------------
1526 ;https://forth-standard.org/standard/core/EMIT
1527 ;C EMIT c -- output character to the output device ; primary DEFERred word
1529 EMIT MOV @PC+,PC ;3 15~
1531 BODYEMIT MOV TOS,Y ; 1
1538 ;Z ECHO -- connect console output (default)
1540 ECHO MOV #4882h,&YEMIT ; 4882h = MOV Y,&<next_adr>
1544 ;Z NOECHO -- disconnect console output
1546 NOECHO MOV #NEXT,&YEMIT ; NEXT = 4030h = MOV @IP+,PC
1550 ;https://forth-standard.org/standard/core/SPACE
1551 ;C SPACE -- output a space
1558 ;https://forth-standard.org/standard/core/SPACES
1559 ;C SPACES n -- output n spaces
1566 SPACESNEXT FORTHtoASM
1569 JNZ SPACE ;25~ ==> 27~ by space ==> 2.963 MBds @ 8 MHz
1570 DROPEXIT MOV @RSP+,IP ;
1571 ONEDROP MOV @PSP+,TOS ; -- drop n
1574 ;https://forth-standard.org/standard/core/TYPE
1575 ;C TYPE adr len -- type line to terminal
1578 JZ TWODROP ; abort fonction
1579 .word 0151Eh ;5 PUSM TOS,IP R-- len,IP
1581 TYPELOOP MOV @PSP,Y ;2 -- adr adr ; 30~ char loop
1583 MOV Y,0(PSP) ;3 -- adr+1 char
1584 SUB #2,PSP ;1 emit consumes one cell
1586 TYPE_NEXT FORTHtoASM
1588 SUB #1,2(RSP) ;4 len-1
1590 POPM #2,TOS ;4 POPM IP,TOS
1591 TWODROP ADD #2,PSP ;
1595 ;https://forth-standard.org/standard/core/CR
1596 ;C CR -- send CR to the output device
1605 ; ------------------------------------------------------------------------------
1606 ; STRINGS PROCESSING
1607 ; ------------------------------------------------------------------------------
1609 ;Z (S") -- addr u run-time code for S"
1610 ; get address and length of string.
1611 XSQUOTE SUB #4,PSP ; 1 -- x x TOS ; push old TOS on stack
1612 MOV TOS,2(PSP) ; 3 -- TOS x x ; and reserve one cell on stack
1613 MOV.B @IP+,TOS ; 2 -- x u ; u = lenght of string
1614 MOV IP,0(PSP) ; 3 -- addr u
1615 ADD TOS,IP ; 1 -- addr u IP=addr+u=addr(end_of_string)
1616 BIT #1,IP ; 1 -- addr u IP=addr+u Carry set/clear if odd/even
1617 ADDC #0,IP ; 1 -- addr u IP=addr+u aligned
1623 CAPS_ON MOV #-1,&CAPS ; state by default
1626 FORTHWORD "CAPS_OFF"
1627 CAPS_OFF MOV #0,&CAPS
1630 ;https://forth-standard.org/standard/core/Sq
1631 ;C S" -- compile in-line string
1632 FORTHWORDIMM "S\34" ; immediate
1634 .word lit,XSQUOTE,COMMA
1635 SQUOTE1 .word CAPS_OFF
1636 .word lit,'"',WORDD ; -- c-addr (= HERE)
1641 ;https://forth-standard.org/standard/core/Sq
1642 ;C S" -- compile in-line string
1643 FORTHWORDIMM "S\34" ; immediate
1645 .word lit,XSQUOTE,COMMA
1646 SQUOTE1 .word lit,'"',WORDD ; -- c-addr (= HERE)
1652 MOV.B @TOS,TOS ; -- u
1653 SUB #1,TOS ; -1 byte
1657 BIT #1,&DDP ;3 carry set if 1
1658 ADDC #2,&DDP ;4 +2 bytes
1661 ;https://forth-standard.org/standard/core/Dotq
1662 ;C ." -- compile string to print
1663 FORTHWORDIMM ".\34" ; immediate
1666 .word lit,TYPE,COMMA,EXIT
1668 ;-------------------------------------------------------------------------------
1670 ;-------------------------------------------------------------------------------
1672 ;https://forth-standard.org/standard/core/WORD
1673 ;C WORD char -- addr Z=1 if len=0
1674 ; parse a word delimited by char separator
1675 ; "word" is capitalized
1676 ; TOIN is the relative displacement in the ascii string
1677 ; separator filled line = 25 cycles + 7 cycles by char
1679 WORDD MOV #SOURCE_LEN,S ;2 -- separator
1680 MOV @S+,X ;2 X = str_len
1681 MOV @S+,W ;2 W = str_org
1682 ADD W,X ;1 W = str_org X = str_org + str_len = str_end
1683 ADD @S+,W ;2 W = str_org + >IN = str_ptr X = str_end
1684 MOV @S,Y ;2 -- separator W = str_ptr X = str_end Y = HERE, as dst_ptr
1685 SKIPCHARLOO CMP W,X ;1 str_ptr = str_end ?
1686 JZ EOL_END ;2 -- separator if yes : End Of Line !
1687 CMP.B @W+,TOS ;2 does char = separator ?
1688 JZ SKIPCHARLOO ;2 -- separator if yes
1689 SCANWORD SUB #1,W ;1
1690 MOV #96,T ;2 T = 96 = ascii(a)-1 (test value set in a register before SCANWORD loop)
1691 SCANWORDLOO ; -- separator 15/23 cycles loop for upper/lower case char... write words in upper case !
1692 MOV.B S,0(Y) ;3 first time make room in dst for word length, then put char @ dst.
1693 CMP W,X ;1 str_ptr = str_end ?
1694 JZ SCANWORDEND ;2 if yes
1696 CMP.B S,TOS ;1 does char = separator ?
1697 JZ SCANWORDEND ;2 if yes
1698 ADD #1,Y ;1 increment dst just before test loop
1699 CMP.B S,T ;1 char U< 'a' ? ('a'-1 U>= char) this condition is tested at each loop
1700 JC SCANWORDLOO ;2 15~ upper case char loop
1702 QCAPS CMP #0,&CAPS ;3 CAPS is OFF ? (case available only for ABORT" ." .( )
1703 JZ SCANWORDLOO ;2 yes
1704 .ENDIF ; LOWERCASE ; here CAPS is ON (other cases)
1705 CMP.B #123,S ;2 char U>= 'z'+1 ?
1706 JC SCANWORDLOO ;2 if yes
1707 SUB.B #32,S ;2 convert lowercase char to uppercase
1710 SCANWORDEND SUB &SOURCE_ADR,W ;3 -- separator W=str_ptr - str_org = new >IN (first char separator next)
1711 MOV W,&TOIN ;3 update >IN
1712 EOL_END MOV &DDP,TOS ;3 -- c-addr
1713 SUB TOS,Y ;1 Y=Word_Length
1715 mNEXT ;4 -- c-addr 40 words Z=1 <==> lenght=0 <==> EOL
1718 ;https://forth-standard.org/standard/core/FIND
1719 ;C FIND c-addr -- c-addr 0 if not found ; flag Z=1
1720 ;C xt -1 if found ; flag Z=0
1721 ;C xt 1 if immediate ; flag Z=0
1722 ; compare WORD at c-addr (HERE) with each of words in each of listed vocabularies in CONTEXT
1723 ; FIND to WORDLOOP : 14/20 cycles,
1724 ; mismatch word loop: 13 cycles on len, +8 cycles on first char,
1725 ; +10 cycles char loop,
1726 ; VOCLOOP : 12/18 cycles,
1727 ; WORDFOUND to end : 21 cycles.
1728 ; note: with 16 threads vocabularies, FIND takes about 75% of CORETEST.4th processing time
1730 FIND SUB #2,PSP ;1 -- ???? c-addr reserve one cell here, not at FINDEND because interacts with flag Z
1731 MOV TOS,S ;1 S=c-addr
1732 MOV.B @S,rDOCON ;2 R5= string count
1733 MOV.B #80h,rDODOES ;2 R4= immediate mask
1735 VOCLOOP MOV @T+,TOS ;2 -- ???? VOC_PFA T=CTXT+2
1736 CMP #0,TOS ;1 no more vocabulary in CONTEXT ?
1737 JZ FINDEND ;2 -- ???? 0 yes ==> exit; Z=1
1740 .ELSECASE ; search thread add 6cycles 5words
1741 MAKETHREAD MOV.B 1(S),Y ;3 -- ???? VOC_PFA0 S=c-addr Y=CHAR0
1742 AND.B #(THREADS-1)*2,Y ;2 -- ???? VOC_PFA0 Y=thread offset
1743 ADD Y,TOS ;1 -- ???? VOC_PFAx
1745 ADD #2,TOS ;1 -- ???? VOC_PFA+2
1746 WORDLOOP MOV -2(TOS),TOS ;3 -- ???? [VOC_PFA] [VOC_PFA] first, then [LFA]
1747 CMP #0,TOS ;1 -- ???? NFA no more word in the thread ?
1748 JZ VOCLOOP ;2 -- ???? NFA yes ==> search next voc in context
1750 MOV.B @X+,Y ;2 TOS=NFA,X=NFA+1,Y=NFA_char
1751 BIC.B rDODOES,Y ;1 hide Immediate bit
1752 LENCOMP CMP.B rDOCON,Y ;1 compare lenght
1753 JNZ WORDLOOP ;2 -- ???? NFA 13~ word loop on lenght mismatch
1755 CHARLOOP ADD #1,W ;1
1756 CHARCOMP CMP.B @X+,0(W) ;4 compare chars
1757 JNZ WORDLOOP ;2 -- ???? NFA 21~ word loop on first char mismatch
1758 SUB.B #1,Y ;1 decr count
1759 JNZ CHARLOOP ;2 -- ???? NFA 10~ char loop
1761 WORDFOUND BIT #1,X ;1
1763 MOV X,S ;1 S=aligned CFA
1764 MOV.B @TOS,W ;2 -- ???? NFA W=NFA_first_char
1765 MOV #1,TOS ;1 -- ???? 1 preset immediate flag
1766 CMP.B #0,W ;1 W is negative if immediate flag
1767 JN FINDEND ;2 -- ???? 1
1768 SUB #2,TOS ;1 -- ???? -1
1769 FINDEND MOV S,0(PSP) ;3 not found: -- c-addr 0 flag Z=1
1770 ; found: -- xt -1|+1 (not immediate|immediate) flag Z=0
1771 MOV #xdocon,rDOCON ;2
1772 MOV #xdodoes,rDODOES ;2
1773 mNEXT ;4 42/47 words
1777 ;https://forth-standard.org/standard/core/toNUMBER
1778 ;C convert a string to double number until count2 = 0 or until not convertible char
1779 ;C >NUMBER ud1lo|ud1hi addr1 count1 -- ud2lo|ud2hi addr2 count2
1780 FORTHWORD ">NUMBER" ; 23 cycles + 32/34 cycles DEC/HEX char loop
1781 TONUMBER MOV @PSP+,S ;2 S = adr
1782 MOV @PSP+,Y ;2 Y = ud1hi
1783 MOV @PSP,X ;2 X = ud1lo
1786 TONUMLOOP MOV.B @S,W ;2 -- ud1lo ud1hi adr count W=char
1787 DDIGITQ SUB.B #30h,W ;2 skip all chars < '0'
1788 CMP.B #10,W ;2 char was U< "10" ?
1789 JLO DDIGITQNEXT ;2 no
1790 SUB.B #7,W ;2 skip all chars between "9" and "A"
1793 DDIGITQNEXT CMP T,W ;1 digit-base
1794 JHS TONUMEND ;2 -- ud1lo ud1hi adr count abort if < 0 or >= base
1795 MOV X,&MPY32L ;3 Load 1st operand (ud1lo)
1796 MOV Y,&MPY32H ;3 Load 1st operand (ud1hi)
1797 MOV T,&OP2 ;3 Load 2nd operand with BASE
1798 MOV &RES0,X ;3 lo result in X (ud2lo)
1799 MOV &RES1,Y ;3 hi result in Y (ud2hi)
1800 ADD W,X ;1 ud2lo + digit
1801 ADDC #0,Y ;1 ud2hi + carry
1802 TONUMPLUS ADD #1,S ;1 -- ud1lo ud1hi adr count S=adr+1
1803 SUB #1,TOS ;1 -- ud1lo ud1hi adr count-1
1804 JNZ TONUMLOOP ;2 if count <>0
1805 MOV Y,2(PSP) ;3 -- ud2lo ud2hi adr count2
1806 TONUMEND MOV S,0(PSP) ;3 -- ud2lo ud2hi addr2 count2
1807 MOV X,4(PSP) ;3 -- ud2lo ud1hi adr count2
1811 ; ?NUMBER makes the interface between >NUMBER and INTERPRET; it's a subset of INTERPRET.
1812 ; convert a string to a signed number; FORTH 2012 prefixes $, %, # are recognized
1813 ; 32 bits numbers (with decimal point) and fixed point signed numbers (with a comma) are recognized.
1814 ; prefixes # % $ - are processed before calling >NUMBER
1815 ; not convertible chars '.' (double) and ',' (fixed point) are processed as >NUMBER exits
1816 ;Z ?NUMBER c-addr -- n -1 if convert ok ; flag Z=0
1817 ;Z c-addr -- c-addr 0 if convert ko ; flag Z=1
1819 MOV &BASE,T ;3 T=BASE
1820 BIC #UF9,SR ;2 reset flag UF9, before use as decimal point flag
1821 .word 152Dh ;5 R-- IP sign base
1824 MOV #QNUMNEXT,IP ;2 return from >NUMBER
1825 SUB #8,PSP ;1 -- x x x x c-addr save TOS and make room for >NUMBER
1826 MOV TOS,6(PSP) ;3 -- c-addr x x x c-addr
1827 MOV TOS,S ;1 S=addrr
1828 MOV.B @S+,TOS ;2 -- c-addr x x x cnt TOS=count
1829 MOV.B @S,W ;2 W=char
1831 JHS QSIGN ;2 for current base, and for ',' or '.' process
1833 QBINARY MOV #2,T ;3 preset base 2
1834 ADD.B #8,W ;1 '%' + 8 = '-' binary number ?
1836 QDECIMAL ADD #8,T ;4
1837 ADD.B #2,W ;1 '#' + 2 = '%' decimal number ?
1840 SUB.B #1,W ;2 '$' - 1 = '#' hex number ?
1841 JNZ TONUMLOOP ;2 -- c-addr ud=0 x x other cases will cause error
1842 PREFIXED ADD #1,S ;1
1843 SUB #1,TOS ;1 -- c-addr ud=0 x count S=adr+1 TOS=count-1
1844 MOV.B @S,W ;2 X=2th char, W=adr
1847 JNZ TONUMLOOP ;2 for positive number and for , or . process
1848 MOV #-1,2(RSP) ;3 R-- IP sign base
1850 ; ----------------------------------; 39
1851 QNUMNEXT FORTHtoASM ; -- c-addr ud2lo-hi addr2 cnt2 R-- IP sign BASE S=addr2
1852 CMP #0,TOS ;1 cnt2=0 : conversion is ok ?
1854 BIT #UF9,SR ;2 already flagged double ?
1855 ; ( test to discard repeated points or repeated commas)
1856 JNZ QNUMNEXT1 ;2 abort
1857 BIS #UF9,SR ;2 set double number flag
1859 .IFDEF FIXPOINT_INPUT
1861 QQNUMDP CMP.B #'.',0(S) ;4 rejected char by >NUMBER = decimal point ?
1863 SUB #2,IP ;1 yes: reset QNUMNEXT address as >NUMBER return
1864 JMP TONUMPLUS ;2 loop back to >NUMBER to terminate conversion
1865 QQcomma CMP.B #',',0(S) ;5 rejected char by >NUMBER is a comma ?
1867 S15Q16 MOV TOS,W ;1 -- c-addr ud2lo x x x yes W=cnt2
1868 MOV #0,X ;1 -- c-addr ud2lo x 0 x init X = ud2lo' = 0
1869 S15Q16LOOP MOV X,2(PSP) ;3 -- c-addr ud2lo ud2lo' ud2lo' x 0(PSP) = ud2lo'
1870 SUB.B #1,W ;1 decrement cnt2
1871 MOV W,X ;1 X = cnt2-1
1872 ADD S,X ;1 X = end_of_string-1, first...
1873 MOV.B @X,X ;2 X = last char of string, first...
1874 SUB #30h,X ;2 char --> digit conversion
1880 QS15Q16DIGI CMP T,X ;1 R-- IP sign BASE is X a digit ?
1881 JHS S15Q16EOC ;2 -- c-addr ud2lo ud2lo' x ud2lo' if no
1882 MOV X,0(PSP) ;3 -- c-addr ud2lo ud2lo' digit x
1883 MOV T,TOS ;1 -- c-addr ud2lo ud2lo' digit base R-- IP sign base
1884 .word 152Ch ;6 PUSH S,T,W: R-- IP sign base addr2 base cnt2
1885 CALL #MUSMOD ;4 -- c-addr ud2lo ur uqlo uqhi
1886 .word 172Ah ;6 restore W,T,S: R-- IP sign BASE
1887 JMP S15Q16LOOP ;2 W=cnt
1888 S15Q16EOC MOV 4(PSP),2(PSP) ;5 -- c-addr ud2lo ud2hi uqlo x ud2lo from >NUMBER part1 becomes here ud2hi=S15 part2
1889 MOV @PSP,4(PSP) ;4 -- c-addr ud2lo ud2hi x x uqlo becomes ud2lo
1890 MOV W,TOS ;1 -- c-addr ud2lo ud2hi x cnt2
1891 CMP.B #0,TOS ;1 TOS = 0 if end of conversion char = ',' (happy end)
1893 .ELSE ; no FIXPOINT_INPUT
1895 QQNUMDP CMP.B #'.',0(S) ;4 rejected char by >NUMBER = decimal point ?
1897 SUB #2,IP ;1 yes: set QNUMNEXT address as >NUMBER return
1898 JMP TONUMPLUS ;2 loop back to >NUMBER to terminate conversion
1902 ; ----------------------------------;88
1903 QNUMNEXT1 POPM #3,IP ;4 -- c-addr ud2lo-hi x cnt2 POPM T,S,IP S = sign flag = {-1;0}
1904 MOV S,TOS ;1 -- c-addr ud2lo-hi x sign
1906 JZ QNUMOK ;2 -- c-addr ud2lo-hi x sign conversion OK
1907 QNUMKO ADD #6,PSP ;1 -- c-addr sign
1908 AND #0,TOS ;1 -- c-addr ff TOS=0 and Z=1 ==> conversion ko
1910 ; ----------------------------------;97
1911 QNUMOK ADD #2,PSP ;1 -- c-addr ud2lo-hi cnt2
1912 MOV 2(PSP),4(PSP) ; -- udlo udlo udhi sign
1913 MOV @PSP+,0(PSP) ;4 -- udlo udhi sign note : PSP is incremented before write back !!!
1914 XOR #-1,TOS ;1 -- udlo udhi inv(sign)
1915 JNZ QDOUBLE ;2 if jump : TOS=-1 and Z=0 ==> conversion ok
1916 Q2NEGATE XOR #-1,TOS ;1 -- udlo udhi tf
1917 XOR #-1,2(PSP) ;3 -- dlo-1 dhi-1 tf
1918 XOR #-1,0(PSP) ;3 -- dlo-1 udhi tf
1919 ADD #1,2(PSP) ;3 -- dlo dhi-1 tf
1920 ADDC #0,0(PSP) ;3 -- dlo dhi tf
1921 QDOUBLE BIT #UF9,SR ;2 decimal point added ?
1922 JNZ QNUMEND ;2 leave double
1923 ADD #2,PSP ;1 leave number
1924 QNUMEND mNEXT ;4 TOS=-1 and Z=0 ==> conversion ok
1925 ; ----------------------------------;119 words
1927 .ELSE ; no hardware HRDWMPY
1929 ; T.I. SIGNED MULTIPLY SUBROUTINE: U1 x U2 -> Ud
1931 ;https://forth-standard.org/standard/core/UMTimes
1932 ;C UM* u1 u2 -- ud unsigned 16x16->32 mult.
1934 UMSTAR MOV @PSP,S ;2 MDlo
1935 UMSTAR1 MOV #0,T ;1 MDhi=0
1938 MOV #1,W ;1 BIT TEST REGISTER
1939 UMSTARLOOP BIT W,TOS ;1 TEST ACTUAL BIT MRlo
1940 JZ UMSTARNEXT ;2 IF 0: DO NOTHING
1941 ADD S,X ;1 IF 1: ADD MDlo TO RES0
1942 ADDC T,Y ;1 ADDC MDhi TO RES1
1943 UMSTARNEXT ADD S,S ;1 (RLA LSBs) MDlo x 2
1944 ADDC T,T ;1 (RLC MSBs) MDhi x 2
1945 ADD W,W ;1 (RLA) NEXT BIT TO TEST
1946 JNC UMSTARLOOP ;2 IF BIT IN CARRY: FINISHED 10~ loop
1947 MOV X,0(PSP) ;3 low result on stack
1948 MOV Y,TOS ;1 high result in TOS
1951 ;https://forth-standard.org/standard/core/toNUMBER
1952 ;C convert a string to double number until count2 = 0 or until not convertible char
1953 ;C >NUMBER ud1lo|ud1hi addr1 count1 -- ud2lo|ud2hi addr2 count2
1955 TONUMBER MOV @PSP,S ; S=adr
1957 TONUMLOOP MOV.B @S,X ; -- ud1lo ud1hi x x X=char
1958 DDIGITQ SUB.B #30h, X ;2 skip all chars < '0'
1959 CMP.B #10,X ; char was > "9" ?
1960 JLO DDIGITQNEXT ; -- ud1lo ud1hi x x no: good end
1961 SUB.B #07,X ;2 skip all chars between "9" and "A"
1962 CMP.B #10,X ;2 char was < "A" ?
1963 JLO TONUMEND ;2 yes: bad end
1964 DDIGITQNEXT CMP &BASE,X ; -- ud1lo ud1hi x x digit-base
1966 UDSTAR .word 154Dh ; -- ud1lo ud1hi x x R-- IP adr count x digit PSUHM IP,S,T,W,X
1967 MOV 2(PSP),S ; -- ud1lo ud1hi x x S=ud1hi
1968 MOV &BASE,TOS ; -- ud1lo ud1hi x base
1969 MOV #UMSTARNEXT1,IP ;
1970 UMSTARONE JMP UMSTAR1 ; ud1hi * base -- x ud3hi X=ud3lo
1971 UMSTARNEXT1 FORTHtoASM ; -- ud1lo ud1hi x ud3hi
1972 MOV X,2(RSP) ; R-- IP adr count ud3lo digit
1973 MOV 4(PSP),S ; -- ud1lo ud1hi x ud3hi S=ud1lo
1974 MOV &BASE,TOS ; -- ud1lo ud1hi x base
1975 MOV #UMSTARNEXT2,IP ;
1976 UMSTARTWO JMP UMSTAR1 ; ud1lo * base -- x ud4hi X=ud4lo
1977 UMSTARNEXT2 FORTHtoASM ; -- ud1lo ud1hi x ud4hi r-- IP adr count ud3lo digit
1978 ADD @RSP+,X ; -- ud1lo ud1hi x ud4hi X = ud4lo+digit = ud2lo
1979 MPLUS ADDC @RSP+,TOS ; -- ud1lo ud1hi x ud2hi TOS = ud4hi+ud3lo+carry = ud2hi
1980 MOV X,4(PSP) ; -- ud2lo ud1hi x ud2hi
1981 MOV TOS,2(PSP) ; -- ud2lo ud2hi x x R-- IP adr count
1982 POPM #3,IP ; -- ud2lo ud2hi x x T=count, S=adr POPM T,S,IP
1983 TONUMPLUS ADD #1,S ;
1985 JNZ TONUMLOOP ; -- ud2lo ud2hi x x S=adr+1, T=count-1, X=ud2lo
1986 TONUMEND MOV S,0(PSP) ; -- ud2lo ud2hi adr2 count2
1987 MOV T,TOS ; -- ud2lo ud2hi adr2 count2
1990 ; convert a string to a signed number
1991 ;Z ?NUMBER c-addr -- n -1 if convert ok ; flag Z=0
1992 ;Z c-addr -- c-addr 0 if convert ko ; flag Z=1
1993 ; FORTH 2012 prefixes $, %, # are recognised
1994 ; 32 bits numbers (with decimal point) are recognised
1995 ; with FIXPOINT_INPUT switched ON, fixed point signed numbers (with a comma) are recognised.
1996 ; prefixes # % $ - are processed before calling >NUMBER, decimal point and comma are >NUMBER exits
1997 ; FORTHWORD "?NUMBER"
1999 MOV &BASE,T ;3 T=BASE
2000 BIC #UF9,SR ;2 reset flag UF9 used here as decimal point flag
2001 .word 152Dh ;5 R-- IP sign base
2002 MOV #QNUMNEXT,IP ;2 define >NUMBER return
2003 SUB #8,PSP ;1 -- x x x x c-addr
2004 MOV TOS,6(PSP) ;3 -- c-addr x x x c-addr
2006 MOV #0,2(PSP) ;3 -- c-addr ud=0 x c-addr
2008 MOV.B @S+,T ;2 -- c-addr ud=0 x x S=adr, T=count
2009 MOV.B @S,X ;2 X=char
2011 JHS QSIGN ;2 for current base, and for ',' or '.' process
2013 QBINARY MOV #2,&BASE ;3 preset base 2
2014 ADD.B #8,X ;1 '%' + 8 = '-' binary number ?
2016 QDECIMAL ADD #8,&BASE ;4
2017 ADD.B #2,X ;1 '#' + 2 = '%' decimal number ?
2019 QHEXA MOV #16,&BASE ;4
2020 SUB.B #1,X ;2 '$' - 1 = '#' hex number ?
2021 JNZ TONUMLOOP ;2 -- c-addr ud=0 x x other cases will cause error
2022 PREFIXED ADD #1,S ;1
2023 SUB #1,T ;1 -- c-addr ud=0 x x S=adr+1 T=count-1
2024 MOV.B @S,X ;2 X=2th char, W=adr
2027 JNZ TONUMLOOP ;2 for positive number and for , or . process
2028 MOV #-1,2(RSP) ;3 R-- IP sign base
2030 ; ----------------------------------;45
2031 QNUMNEXT FORTHtoASM ; -- c-addr ud2lo-hi addr2 cnt2 R-- IP sign BASE S=addr2,T=cnt2
2032 CMP #0,TOS ;1 cnt2=0 ? conversion is ok ?
2034 BIT #UF9,SR ;2 already flagged double ?
2035 ; ( test to discard repeated points or repeated commas)
2036 JNZ QNUMNEXT1 ;2 abort
2037 BIS #UF9,SR ;2 set double number flag
2038 ; ----------------------------------;
2040 .IFDEF FIXPOINT_INPUT
2042 QNUMDP CMP.B #'.',0(S) ;4 rejected char by >NUMBER is a decimal point ?
2044 QNUMDPFOUND SUB #2,IP ;1 set >NUMBER return address
2045 JMP TONUMPLUS ;2 to terminate conversion
2046 QS15Q16 CMP.B #',',0(S) ;5 rejected char by >NUMBER is a comma ?
2048 S15Q16 MOV T,W ;1 -- c-addr ud2lo x x x W=cnt2
2049 MOV &BASE,T ;3 T=current base
2050 MOV #0,X ;1 -- c-addr ud2lo x 0 x init ud2lo' = 0
2051 S15Q16LOOP MOV X,2(PSP) ;3 -- c-addr ud2lo ud2lo' ud2lo' x X = 0(PSP) = ud2lo'
2052 SUB.B #1,W ;1 decrement cnt2
2053 MOV W,X ;1 X = cnt2-1
2054 ADD S,X ;1 X = end_of_string-1, first...
2055 MOV.B @X,X ;2 X = last char of string, first...
2056 SUB #30h,X ;2 char --> digit conversion
2062 QS15Q16DIGI CMP T,X ;1 R-- IP sign BASE is X a digit ?
2063 JHS S15Q16EOC ;2 -- c-addr ud2lo ud2lo' x ud2lo' if no
2064 MOV X,0(PSP) ;3 -- c-addr ud2lo ud2lo' digit x
2065 MOV T,TOS ;1 -- c-addr ud2lo ud2lo' digit base R-- IP sign base
2066 .word 152Ch ;6 PUSH S,T,W: R-- IP sign base addr2 base cnt2
2067 CALL #MUSMOD ;4 -- c-addr ud2lo ur uqlo uqhi
2068 .word 172Ah ;6 restore W,T,S: R-- IP sign BASE
2069 JMP S15Q16LOOP ;2 W=cnt
2070 S15Q16EOC MOV 4(PSP),2(PSP) ;5 -- c-addr ud2lo ud2lo uqlo x ud2lo from >NUMBER part1 becomes here ud2hi=S15 part2
2071 MOV @PSP,4(PSP) ;4 -- c-addr ud2lo ud2hi x x uqlo becomes ud2lo
2072 MOV W,TOS ;1 -- c-addr ud2lo ud2hi x cnt2
2073 CMP.B #0,TOS ;1 TOS = 0 if end of conversion char = ',' (happy end)
2075 .ELSE ; no FIXPOINT_INPUT
2077 QNUMDP CMP.B #'.',0(S) ;4 rejected char by >NUMBER is a decimal point ?
2079 QNUMDPFOUND SUB #2,IP ;1 set >NUMBER return address
2080 JMP TONUMPLUS ;2 to terminate conversion
2084 ; ----------------------------------;97
2085 QNUMNEXT1 POPM #3,IP ;4 -- c-addr ud2lo-hi x cnt2 POPM T,S,IP S = sign flag = {-1;0}
2086 MOV S,TOS ;1 -- c-addr ud2lo-hi x sign
2088 JZ QNUMOK ;2 -- c-addr ud2lo-hi x sign conversion OK
2089 QNUMKO ADD #6,PSP ;1 -- c-addr sign
2090 AND #0,TOS ;1 -- c-addr ff TOS=0 and Z=1 ==> conversion ko
2092 ; ----------------------------------;
2093 QNUMOK ADD #2,PSP ;1 -- c-addr ud2lo-hi sign
2094 MOV 2(PSP),4(PSP) ; -- udlo udlo udhi sign
2095 MOV @PSP+,0(PSP) ;4 -- udlo udhi sign note : PSP is incremented before write back !!!
2096 XOR #-1,TOS ;1 -- udlo udhi inv(sign)
2097 JNZ QDOUBLE ;2 if jump : TOS=-1 and Z=0 ==> conversion ok
2098 Q2NEGATE XOR #-1,TOS ;1 -- udlo udhi tf
2099 XOR #-1,2(PSP) ;3 -- dlo-1 dhi-1 tf
2100 XOR #-1,0(PSP) ;3 -- dlo-1 udhi tf
2101 ADD #1,2(PSP) ;3 -- dlo dhi-1 tf
2102 ADDC #0,0(PSP) ;3 -- dlo dhi tf
2103 QDOUBLE BIT #UF9,SR ;2 decimal point added ?
2104 JNZ QNUMEND ;2 leave double
2105 ADD #2,PSP ;1 leave number
2106 QNUMEND mNEXT ;4 TOS=-1 and Z=0 ==> conversion ok
2107 ; ----------------------------------;128 words
2111 ;https://forth-standard.org/standard/core/EXECUTE
2112 ;C EXECUTE i*x xt -- j*x execute Forth word at 'xt'
2114 EXECUTE MOV TOS,W ; 1 put word address into W
2115 MOV @PSP+,TOS ; 2 fetch new TOS
2116 MOV W,PC ; 3 fetch code address into PC
2118 ;https://forth-standard.org/standard/core/Comma
2119 ;C , x -- append cell to dict
2127 ;https://forth-standard.org/standard/core/LITERAL
2128 ;C LITERAL (n|d) -- append single numeric literal if compiling state
2129 ; (n|d) -- append double numeric literal if compiling state and if UF9<>0 (not ANS)
2130 FORTHWORDIMM "LITERAL" ; immediate
2131 LITERAL CMP #0,&STATE ;3
2132 JZ LITERALEND ;2 if not immediate, leave n|d on the stack
2133 LITERAL1 MOV &DDP,W ;3
2141 LITERALEND mNEXT ;4 30~
2143 ;https://forth-standard.org/standard/core/COUNT
2144 ;C COUNT c-addr1 -- adr len counted->adr/len
2149 MOV.B -1(TOS),TOS ;3
2152 ; : SETIB SOURCE 2! 0 >IN ! ; ; org len -- set Input Buffer, shared by INTERPRET and [ELSE]
2153 SETIB MOV #0,&TOIN ;
2154 MOV TOS,&SOURCE_LEN ; -- org len
2155 MOV @PSP+,&SOURCE_ADR ; -- len
2159 ;C INTERPRET i*x addr u -- j*x interpret given buffer
2160 ; This is the common factor of EVALUATE and QUIT.
2161 ; set addr u as input buffer then parse it word by word
2163 .word SETIB ; set Input buffer pointers SOURCE_LEN, SOURCE_ORG clear >IN
2164 INTLOOP .word FBLANK,WORDD ; -- c-addr Z = End Of Line
2166 MOV #INTFINDNEXT,IP ;2 define INTFINDNEXT as FIND return
2167 JNZ FIND ;2 if EOL not reached
2168 JMP DROPEXIT ; if EOL reached
2170 INTFINDNEXT FORTHtoASM ; -- c-addr fl Z = not found
2171 MOV TOS,W ; W = flag =(-1|0|+1) as (normal|not_found|immediate)
2172 MOV @PSP+,TOS ; -- c-addr
2173 MOV #INTQNUMNEXT,IP ;2 define QNUMBER return
2174 JZ QNUMBER ;2 c-addr -- if not found search a number
2175 MOV #INTLOOP,IP ;2 define (EXECUTE | COMMA) return
2177 JZ COMMA ;2 c-addr -- if W xor STATE = 0 compile xt then loop back to INTLOOP
2178 JNZ EXECUTE ;2 c-addr -- if W xor STATE <>0 execute xt then loop back to INTLOOP
2180 INTQNUMNEXT FORTHtoASM ; -- n|c-addr fl Z = not a number, SR(UF9) double number request
2182 MOV #INTLOOP,IP ;2 -- n|c-addr define LITERAL return
2183 JNZ LITERAL ;2 n -- execute LITERAL then loop back to INTLOOP
2184 NotFoundExe ADD.B #1,0(TOS) ;3 c-addr -- Not a Number : incr string count to add '?'
2187 MOV.B #'?',0(Y) ;5 add '?' to end of word string
2188 MOV #FQABORTYES,IP ;2 define COUNT return
2189 JMP COUNT ;2 -- addr len 36 words
2191 ;https://forth-standard.org/standard/core/EVALUATE
2192 ; EVALUATE \ i*x c-addr u -- j*x interpret string
2193 FORTHWORD "EVALUATE"
2194 EVALUATE MOV #SOURCE_LEN,X ;2
2195 MOV @X+,S ;2 S = SOURCE_LEN
2196 MOV @X+,T ;2 T = SOURCE_ADR
2197 MOV @X+,W ;2 W = TOIN
2198 PUSHM #4,IP ;6 PUSHM IP,S,T,W
2203 MOV @RSP+,&SOURCE_ADR ;4
2204 MOV @RSP+,&SOURCE_LEN ;4
2209 PREQUIT0 MOV #0,&SAVE_SYSRSTIV ;
2210 PREQUIT1 MOV #RSTACK,RSP
2211 MOV #LSTACK,&LEAVEPTR
2215 .IFDEF BOOTLOAD ; Boot loader requires Conditional Compilation
2216 ;c BOOT -- jump to bootstrap then continues with (QUIT)
2219 .word PREQUIT1 ; doesn't reset SAVE_SYSRSTIV before testing !
2221 ; ----------------------------------;
2223 ; ----------------------------------;
2224 CMP #0,&SAVE_SYSRSTIV ; if WARM
2225 JZ QUIT0 ; no boostrap
2226 BIT.B #SD_CD,&SD_CDIN ; SD_memory in SD_Card module ?
2227 JNZ QUIT0 ; if not, no bootstrap
2228 ; ----------------------------------;
2229 ; BOOTSTRAP ; on SYSRSTIV <> 0
2230 ; ----------------------------------;
2233 MOV &SAVE_SYSRSTIV,TOS ;
2234 MOV #0,&SAVE_SYSRSTIV ;
2237 .word NOECHO ; warning ! your BOOT.4TH must to be finished with ECHO command!
2239 .word XSQUOTE ; -- addr u
2240 .byte 15,"LOAD\34 BOOT.4TH\34" ; issues error 2 if no such file...
2241 .word BRAN,QUIT4 ; to interpret this string
2242 ; ----------------------------------;
2244 ;https://forth-standard.org/standard/core/QUIT
2245 ;c QUIT -- interpret line by line the input stream, primary DEFERred word
2248 .word BODYQUIT ; this word may be replaced by BOOT
2251 .ELSE ; if no BOOTLOADER, QUIT is not DEFERred
2253 ;https://forth-standard.org/standard/core/QUIT
2254 ;c QUIT -- interpret line by line the input stream
2263 .byte 5,13,10,"ok " ; CR+LF + Forth prompt
2264 QUIT2 .word TYPE ; display it
2267 QUIT4 .word INTERPRET
2268 .word DEPTH,ZEROLESS
2270 .byte 13,"stack empty! "
2272 .word lit,FRAM_FULL,HERE,ULESS
2274 .byte 11,"FRAM full! "
2277 .word QBRAN,QUIT1 ; case of interpretion state
2278 .word XSQUOTE ; case of compilation state
2279 .byte 5,13,10," " ; CR+LF + 3 blanks
2282 ;https://forth-standard.org/standard/core/ABORT
2283 ;C ABORT i*x -- R: j*x -- clear stack & QUIT
2285 ABORT MOV #PSTACK,PSP
2288 WIP_DEFER ; WIPE resets ALL factory primary DEFERred words
2289 MOV #BODYWARM,&WARM+2 ; (WARM) is WARM kill user interrupts init
2290 MOV #BODYSLEEP,&SLEEP+2 ; (SLEEP) is SLEEP kill user background task
2291 QAB_DEFER ; QABORT resets some primary DEFERred words
2292 MOV #BODYEMIT,&EMIT+2 ;4 (EMIT) is EMIT default console output
2293 MOV #BODYCR,&CR+2 ;4 (CR) is CR default CR
2294 MOV #BODYKEY,&KEY+2 ;4 (KEY) is KEY default KEY
2296 .IFDEF DEFER_INPUT ; true if SD_LOADER
2297 MOV #BODYACCEPT,&ACCEPT+2 ;4 (ACCEPT) is ACCEPT
2298 MOV #TIB_ORG,&FCIB+2 ;4 TIB is CIB (Current Input Buffer)
2300 .IFDEF MSP430ASSEMBLER ; reset all 6 branch labels
2303 RAZASM MOV #0,ASMFW1(Y)
2311 RefillUSBtime .equ int(frequency*2730) ; 2730*frequency ==> 65520 @ max freq (24MHz)
2313 ;Z ?ABORT f c-addr u -- abort & print msg
2314 ; FORTHWORD "?ABORT"
2315 QABORT CMP #0,2(PSP) ; -- f c-addr u flag test
2317 THREEDROP ADD #4,PSP
2321 QABORTYES MOV #4882h,&YEMIT ; restore default YEMIT = set ECHO
2322 .IFDEF SD_CARD_LOADER ; close all handles
2324 QABORTCLOSE CMP #0,T
2326 MOV.B #0,HDLB_Token(T)
2331 ; ----------------------------------;
2332 QABORTYESNOECHO ; <== WARM jumps here, thus, if NOECHO, TERMINAL can be disconnected without freezing the app
2333 ; ----------------------------------;
2334 CALL #QAB_DEFER ; restore default part of primary DEFERred words ....except WARM and SLEEP.
2335 ; ----------------------------------;
2336 QABORTTERM ; wait the end of source file downloading
2337 ; ----------------------------------;
2338 .IFDEF TERMINAL3WIRES ;
2339 BIT #UCTXIFG,&TERMIFG ; TX buffer empty ?
2341 MOV #17,&TERMTXBUF ; yes move XON char into TX_buf
2343 .IFDEF TERMINAL4WIRES ;
2344 BIC.B #RTS,&HANDSHAKOUT ; set /RTS low (connected to /CTS pin of UARTtoUSB bridge)
2346 QABORTLOOP BIC #UCRXIFG,&TERMIFG ; reset TERMIFG(UCRXIFG)
2347 MOV #RefillUSBtime,Y ; 2730*36 = 98 ms : PL2303TA seems to be the slower USB device to refill its TX buffer.
2348 QABUSBLOOPJ MOV #8,X ; 1~ <-------+
2349 QABUSBLOOPI NOP ; 1~ <---+ |
2351 JNZ QABUSBLOOPI ; 2~ > 4~ loop -+ |
2353 JNZ QABUSBLOOPJ ; 2~ --> 36~ loop --+
2354 BIT #UCRXIFG,&TERMIFG ; 4 new char in TERMXBUF after refill time out ?
2355 JNZ QABORTLOOP ; 2 yes, the input stream (download source file) is still active
2356 ; ----------------------------------;
2357 ; Display WARM/ABORT message ; no, the input stream is quiet (end of download source file)
2358 ; ----------------------------------;
2360 .word XSQUOTE ; -- c-addr u c-addr1 u1
2362 .word TYPE ; -- c-addr u set reverse video
2363 ERRLINE .word lit,LINE,FETCH,QDUP; if LINE <> 0
2364 .word QBRAN,ERRLINE_END
2365 .word XSQUOTE ; displays the line where error occured
2368 .word ONEMINUS,UDOT ;
2370 ERRLINE_END .word TYPE ; -- type abort message
2371 .word XSQUOTE ; -- c-addr2 u2
2373 .word TYPE ; -- set normal video
2374 ; ----------------------------------;
2375 .word PWR_STATE ; remove all words beyond PWR_HERE
2379 .word ABORT ; no return
2380 ; ----------------------------------;
2382 ;https://forth-standard.org/standard/core/ABORTq
2383 ;C ABORT" i*x flag -- i*x R: j*x -- j*x flag=0
2384 ;C i*x flag -- R: j*x -- flag<>0
2385 FORTHWORDIMM "ABORT\34" ; immediate
2388 .word lit,QABORT,COMMA
2391 ;https://forth-standard.org/standard/core/Tick
2392 ;C ' -- xt find word in dictionary and leave on stack its execution address
2394 TICK mDOCOL ; separator -- xt
2395 .word FBLANK,WORDD,FIND ; Z=1 if not found
2396 .word QBRAN,NotFound
2398 NotFound .word NotFoundExe ; in INTERPRET
2400 ;https://forth-standard.org/standard/block/bs
2402 ; everything up to the end of the current line is a comment.
2403 FORTHWORDIMM "\\" ; immediate
2404 BACKSLASH MOV &SOURCE_LEN,&TOIN ;
2407 ;-------------------------------------------------------------------------------
2409 ;-------------------------------------------------------------------------------
2411 ;https://forth-standard.org/standard/core/Bracket
2412 ;C [ -- enter interpretative state
2413 FORTHWORDIMM "[" ; immediate
2414 LEFTBRACKET MOV #0,&STATE
2417 ;https://forth-standard.org/standard/core/right-bracket
2418 ;C ] -- enter compiling state
2420 RIGHTBRACKET MOV #-1,&STATE
2423 ;https://forth-standard.org/standard/core/BracketTick
2424 ;C ['] <name> -- find word & compile it as literal
2425 FORTHWORDIMM "[']" ; immediate word, i.e. word executed during compilation
2427 .word TICK ; get xt of <name>
2428 .word lit,lit,COMMA ; append LIT action
2429 .word COMMA,EXIT ; append xt literal
2431 ;https://forth-standard.org/standard/core/DEFERStore
2432 ;C DEFER! xt CFA_DEFER -- ; store xt to the address after DODEFER
2433 ; FORTHWORD "DEFER!"
2434 DEFERSTORE MOV @PSP+,2(TOS) ; -- CFA_DEFER xt --> [CFA_DEFER+2]
2438 ;https://forth-standard.org/standard/core/IS
2441 ; DEFER DISPLAY create a "do nothing" definition (2 CELLS)
2442 ; inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY
2443 ; or in a definition : ... ['] U. IS DISPLAY ...
2444 ; KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words
2446 ; as IS replaces the PFA value of a "PFA word", it may be also used with VARIABLE and CONSTANT words...
2448 FORTHWORDIMM "IS" ; immediate
2452 IS_COMPILE .word BRACTICK ; find the word, compile its CFA as literal
2453 .word lit,DEFERSTORE,COMMA ; compile DEFERSTORE
2455 IS_EXEC .word TICK,DEFERSTORE ; find the word, leave its CFA on the stack and execute DEFERSTORE
2458 ;https://forth-standard.org/standard/core/IMMEDIATE
2459 ;C IMMEDIATE -- make last definition immediate
2460 FORTHWORD "IMMEDIATE"
2461 IMMEDIATE MOV &LAST_NFA,W
2465 ;https://forth-standard.org/standard/core/RECURSE
2466 ;C RECURSE -- recurse to current definition (compile current definition)
2467 FORTHWORDIMM "RECURSE" ; immediate
2468 RECURSE MOV &DDP,X ;
2469 MOV &LAST_CFA,0(X) ;
2473 ;https://forth-standard.org/standard/core/POSTPONE
2474 FORTHWORDIMM "POSTPONE" ; immediate
2476 .word FBLANK,WORDD,FIND,QDUP
2477 .word QBRAN,NotFound
2478 .word ZEROLESS ; immediate ?
2479 .word QBRAN,POST1 ; yes
2480 .word lit,lit,COMMA,COMMA
2482 POST1 .word COMMA,EXIT
2484 ;;Z ?REVEAL -- if no stack mismatch, link this created word in the CURRENT vocabulary
2485 ; FORTHWORD "REVEAL"
2486 QREVEAL CMP PSP,&LAST_PSP ; Check SP with its saved value by :
2487 JZ GOOD_CSP ; if no stack mismatch.
2490 .byte 15,"stack mismatch!"
2491 FQABORTYES .word QABORTYES
2493 ;https://forth-standard.org/standard/core/Semi
2494 ;C ; -- end a colon definition
2495 FORTHWORDIMM ";" ; immediate
2496 SEMICOLON CMP #0,&STATE ; in interpret mode semicolon becomes a comment separator
2497 JZ BACKSLASH ; tip: ";" is transparent to the preprocessor, so semicolon comments are kept in file.4th
2498 mDOCOL ; compile mode
2499 .word lit,EXIT,COMMA
2500 .word QREVEAL,LEFTBRACKET,EXIT
2503 ;https://forth-standard.org/standard/core/ColonNONAME
2506 COLONNONAME SUB #2,PSP
2510 MOV #PAIN,X ; PAIN is a read only register in all MSP430FRxxxx devices...
2511 MOV X,Y ; so, MOV Y,0(X) writes to a read only register = lure for semicolon LAST_THREAD REVEAL...
2512 ADD #2,Y ; so, MOV @X,-2(Y) writes to same register = lure for semicolon LAST_NFA REVEAL...
2513 CALL #HEADEREND ; ...because we don't want write preamble of word in dictionnary!
2518 MOV #DOCOL1,-4(W) ; compile CALL rDOCOL
2521 MOV #DOCOL1,-4(W) ; compile PUSH IP 3~
2522 MOV #DOCOL2,-2(W) ; compile CALL rEXIT
2523 .CASE 3 ; inlined DOCOL
2524 MOV #DOCOL1,-4(W) ; compile PUSH IP 3~
2525 MOV #DOCOL2,-2(W) ; compile MOV PC,IP 1~
2526 MOV #DOCOL3,0(W) ; compile ADD #4,IP 1~
2527 MOV #NEXT,+2(W) ; compile MOV @IP+,PC 4~
2530 MOV #-1,&STATE ; enter compiling state
2531 SAVE_PSP MOV PSP,&LAST_PSP ; save PSP for check compiling, used by QREVEAL
2534 ;https://forth-standard.org/standard/core/Colon
2535 ;C : <name> -- begin a colon definition
2537 COLON PUSH #COLONNEXT ; define COLONNEXT as RET for HEADER
2539 ; HEADER create an header for a new word. Max count of chars = 126
2540 ; common code for VARIABLE, CONSTANT, CREATE, DEFER, :, MARKER, CODE, ASM.
2541 ; don't link created word in vocabulary.
2543 .word CELLPLUSALIGN ; ALIGN then make room for LFA
2544 .word FBLANK,WORDD ;
2545 FORTHtoASM ; -- HERE HERE is the NFA of this new word
2547 MOV.B @TOS+,W ; -- xxx W=Count_of_chars Y=NFA
2548 BIS.B #1,W ; -- xxx W=count is always odd
2549 ADD.B #1,W ; -- xxx W=add one byte for length
2550 ADD Y,W ; -- xxx W=Aligned_CFA
2551 MOV &CURRENT,X ; -- xxx X=VOC_BODY of CURRENT Y=NFA
2553 .CASE 1 ; nothing to do
2554 .ELSECASE ; multithreading add 5~ 4words
2555 MOV.B @TOS,TOS ; -- xxx TOS=first CHAR of new word
2556 AND #(THREADS-1)*2,TOS ; -- xxx TOS= Thread offset
2557 ADD TOS,X ; -- xxx TOS= Thread X=VOC_PFAx = thread x of VOC_PFA of CURRENT
2561 MOV #4030h,0(W) ;4 by default, HEADER create a DEFERred word: CFA = MOV @PC+,PC = BR...
2562 MOV #PFA_DEFER,2(W) ;4 by default, HEADER create a DEFERred word: PFA = address of NEXT to do nothing.
2564 HEADEREND MOV Y,&LAST_NFA ; -- NFA --> LAST_NFA used by QREVEAL, IMMEDIATE
2565 MOV X,&LAST_THREAD ; -- VOC_PFAx --> LAST_THREAD used by QREVEAL
2566 MOV W,&LAST_CFA ; -- HERE=CFA --> LAST_CFA used by DOES>, RECURSE
2567 ADD #4,W ; -- by default make room for two words...
2569 RET ; 23 words, W is the new DDP value )
2570 ; X is LAST_THREAD > used by VARIABLE, CONSTANT, CREATE, DEFER and :
2573 ;https://forth-standard.org/standard/core/VARIABLE
2574 ;C VARIABLE <name> -- define a Forth VARIABLE
2575 FORTHWORD "VARIABLE"
2576 VARIABLE CALL #HEADER ; W = DDP = CFA + 2 words
2577 MOV #DOVAR,-4(W) ; CFA = DOVAR
2578 JMP REVEAL ; PFA is undefined
2580 ;https://forth-standard.org/standard/core/CONSTANT
2581 ;C CONSTANT <name> n -- define a Forth CONSTANT (it's also an alias of VALUE)
2582 FORTHWORD "CONSTANT"
2583 CONSTANT CALL #HEADER ; W = DDP = CFA + 2 words
2584 MOV #DOCON,-4(W) ; CFA = DOCON
2585 MOV TOS,-2(W) ; PFA = n
2589 ;;https://forth-standard.org/standard/core/VALUE
2590 ;;( x "<spaces>name" -- ) define a Forth VALUE
2591 ;;Skip leading space delimiters. Parse name delimited by a space.
2592 ;;Create a definition for name with the execution semantics defined below,
2593 ;;with an initial value equal to x.
2595 ;;name Execution: ( -- x )
2596 ;;Place x on the stack. The value of x is that given when name was created,
2597 ;;until the phrase x TO name is executed, causing a new value of x to be assigned to name.
2599 ; FORTHWORD "VALUE" ; VALUE is an alias of CONSTANT
2602 ;;TO name Run-time: ( x -- )
2603 ;;Assign the value x to name.
2605 ; FORTHWORDIMM "TO" ; TO is an alias of IS
2608 ; usage : SDIB_ORG IS CIB ; modify Current_Input_Buffer address to read a SD file sector
2610 ; TIB_ORG IS CIB ; restore Terminal_Input_Buffer address as Current_Input_Buffer address
2612 ;https://forth-standard.org/standard/core/CREATE
2613 ;C CREATE <name> -- define a CONSTANT with its next address
2614 ; Execution: ( -- a-addr ) ; a-addr is the address of name's data field
2615 ; ; the execution semantics of name may be extended by using DOES>
2617 CREATE CALL #HEADER ; -- W = DDP
2618 MOV #DOCON,-4(W) ;4 CFA = DOCON
2619 MOV W,-2(W) ;3 PFA = next address
2622 ;https://forth-standard.org/standard/core/DOES
2623 ;C DOES> -- set action for the latest CREATEd definition
2625 DOES MOV &LAST_CFA,W ; W = CFA of CREATEd word
2626 MOV #DODOES,0(W) ; replace CFA (DOCON) by new CFA (DODOES)
2627 MOV IP,2(W) ; replace PFA by the address after DOES> as execution address
2628 MOV @RSP+,IP ; exit of the new created word
2631 ;https://forth-standard.org/standard/core/DEFER
2632 ;C DEFER "<spaces>name" --
2633 ;Skip leading space delimiters. Parse name delimited by a space.
2634 ;Create a definition for name with the execution semantics defined below.
2637 ;Execute the xt that name is set to execute, i.e. NEXT (nothing),
2638 ;until the phrase ' word IS name is executed, causing a new value of xt to be assigned to name.
2641 DEFER CALL #HEADER ; that create a secondary DEFERred word (whithout subsequent code)
2644 ;https://forth-standard.org/standard/core/toBODY
2645 ; >BODY -- PFA leave BODY of a CREATEd or a primary DEFERred word
2652 ; ------------------------------------------------------------------------------
2653 ; forthMSP430FR : CONDITIONNAL COMPILATION
2654 ; ------------------------------------------------------------------------------
2655 .include "forthMSP430FR_CONDCOMP.asm"
2657 ; compile the words: COMPARE [THEN] [ELSE] [IF] [UNDEFINED] [DEFINED] MARKER
2661 GOOD_CSP MOV &LAST_NFA,Y ; GOOD_CSP is the end of word MARKER
2662 MOV &LAST_THREAD,X ;
2663 REVEAL MOV @X,-2(Y) ; [LAST_THREAD] --> LFA
2664 MOV Y,0(X) ; LAST_NFA --> [LAST_THREAD]
2667 ; ------------------------------------------------------------------------------
2668 ; CONTROL STRUCTURES
2669 ; ------------------------------------------------------------------------------
2670 ; THEN and BEGIN compile nothing
2671 ; DO compile one word
2672 ; IF, ELSE, AGAIN, UNTIL, WHILE, REPEAT, LOOP & +LOOP compile two words
2673 ; LEAVE compile three words
2675 ;https://forth-standard.org/standard/core/IF
2676 ;C IF -- IFadr initialize conditional forward branch
2677 FORTHWORDIMM "IF" ; immediate
2680 MOV &DDP,TOS ; -- HERE
2681 ADD #4,&DDP ; compile one word, reserve one word
2682 MOV #QBRAN,0(TOS) ; -- HERE compile QBRAN
2683 CELLPLUS ADD #2,TOS ; -- HERE+2=IFadr
2686 ;https://forth-standard.org/standard/core/ELSE
2687 ;C ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack
2688 FORTHWORDIMM "ELSE" ; immediate
2689 ELSS ADD #4,&DDP ; make room to compile two words
2690 MOV &DDP,W ; W=HERE+4
2692 MOV W,0(TOS) ; HERE+4 ==> [IFadr]
2694 MOV W,TOS ; -- ELSEadr
2697 ;https://forth-standard.org/standard/core/THEN
2698 ;C THEN IFadr -- resolve forward branch
2699 FORTHWORDIMM "THEN" ; immediate
2700 THEN MOV &DDP,0(TOS) ; -- IFadr
2704 ;https://forth-standard.org/standard/core/BEGIN
2705 ;C BEGIN -- BEGINadr initialize backward branch
2706 FORTHWORDIMM "BEGIN" ; immediate
2707 BEGIN MOV #HERE,PC ; BR HERE
2709 ;https://forth-standard.org/standard/core/UNTIL
2710 ;C UNTIL BEGINadr -- resolve conditional backward branch
2711 FORTHWORDIMM "UNTIL" ; immediate
2713 UNTIL1 ADD #4,&DDP ; compile two words
2714 MOV &DDP,W ; W = HERE
2715 MOV X,-4(W) ; compile Bran or qbran at HERE
2716 MOV TOS,-2(W) ; compile bakcward adr at HERE+2
2720 ;https://forth-standard.org/standard/core/AGAIN
2721 ;X AGAIN BEGINadr -- resolve uncondionnal backward branch
2722 FORTHWORDIMM "AGAIN" ; immediate
2726 ;https://forth-standard.org/standard/core/WHILE
2727 ;C WHILE BEGINadr -- WHILEadr BEGINadr
2728 FORTHWORDIMM "WHILE" ; immediate
2732 ;https://forth-standard.org/standard/core/REPEAT
2733 ;C REPEAT WHILEadr BEGINadr -- resolve WHILE loop
2734 FORTHWORDIMM "REPEAT" ; immediate
2736 .word AGAIN,THEN,EXIT
2738 ;https://forth-standard.org/standard/core/
2740 ;C DO -- DOadr L: -- 0
2741 FORTHWORDIMM "DO" ; immediate
2744 ADD #2,&DDP ; make room to compile xdo
2745 MOV &DDP,TOS ; -- HERE+2
2746 MOV #xdo,-2(TOS) ; compile xdo
2747 ADD #2,&LEAVEPTR ; -- HERE+2 LEAVEPTR+2
2749 MOV #0,0(W) ; -- HERE+2 L-- 0
2752 ;https://forth-standard.org/standard/core/LOOP
2753 ;C LOOP DOadr -- L-- an an-1 .. a1 0
2754 FORTHWORDIMM "LOOP" ; immediate
2756 ENDLOOP ADD #4,&DDP ; make room to compile two words
2758 MOV X,-4(W) ; xloop --> HERE
2759 MOV TOS,-2(W) ; DOadr --> HERE+2
2760 ; resolve all "leave" adr
2761 LEAVELOOP MOV &LEAVEPTR,TOS ; -- Adr of top LeaveStack cell
2762 SUB #2,&LEAVEPTR ; --
2763 MOV @TOS,TOS ; -- first LeaveStack value
2764 CMP #0,TOS ; -- = value left by DO ?
2766 MOV W,0(TOS) ; move adr after loop as UNLOOP adr
2768 ENDLOOPEND MOV @PSP+,TOS
2771 ;https://forth-standard.org/standard/core/PlusLOOP
2772 ;C +LOOP adrs -- L-- an an-1 .. a1 0
2773 FORTHWORDIMM "+LOOP" ; immediate
2774 PLUSLOOP MOV #xploop,X
2777 ;https://forth-standard.org/standard/core/LEAVE
2778 ;C LEAVE -- L: -- adrs
2779 FORTHWORDIMM "LEAVE" ; immediate
2780 LEAV MOV &DDP,W ; compile three words
2781 MOV #UNLOOP,0(W) ; [HERE] = UNLOOP
2782 MOV #BRAN,2(W) ; [HERE+2] = BRAN
2783 ADD #6,&DDP ; [HERE+4] = take word for AfterLOOPadr
2787 MOV W,0(X) ; leave HERE+4 on LEAVEPTR stack
2790 ;https://forth-standard.org/standard/core/MOVE
2791 ;C MOVE addr1 addr2 u -- smart move
2792 ; VERSION FOR 1 ADDRESS UNIT = 1 CHAR
2795 MOV @PSP+,Y ; dest adrs
2796 MOV @PSP+,X ; src adrs
2797 MOV @PSP+,TOS ; pop new TOS
2799 JZ MOVE_X ; already made !
2800 CMP X,Y ; Y-X ; dst - src
2801 JZ MOVE_X ; already made !
2802 JC MOVEUP ; U>= if dst > src
2803 MOVEDOWN MOV.B @X+,0(Y) ; if X=src > Y=dst copy W bytes down
2808 MOVEUP ADD W,Y ; start at end
2812 MOVUP2 MOV.B @X,0(Y) ; if X=src < Y=dst copy W bytes up
2817 ;-------------------------------------------------------------------------------
2818 ; WORDS SET for VOCABULARY, not ANS compliant
2819 ;-------------------------------------------------------------------------------
2821 ;X VOCABULARY -- create a vocabulary
2823 .IFDEF VOCABULARY_SET
2825 FORTHWORD "VOCABULARY"
2830 .word lit,0,COMMA ; will keep the NFA of the last word of the future created vocabularies
2832 .word lit,THREADS,lit,0,xdo
2833 VOCABULOOP .word lit,0,COMMA
2834 .word xloop,VOCABULOOP
2836 .word HERE ; link via LASTVOC the future created vocabularies
2837 .word LIT,LASTVOC,DUP
2838 .word FETCH,COMMA ; compile [LASTVOC] to HERE+
2839 .word STORE ; store (HERE - CELL) to LASTVOC
2840 .word DOES ; compile CFA and PFA for the future defined vocabulary
2842 .ENDIF ; VOCABULARY_SET
2844 VOCDOES .word LIT,CONTEXT,STORE
2847 ;X FORTH -- ; set FORTH the first context vocabulary; FORTH is and must be the first vocabulary
2848 .IFDEF VOCABULARY_SET
2850 .ENDIF ; VOCABULARY_SET
2851 FORTH mDODOES ; leave BODYFORTH on the stack and run VOCDOES
2853 BODYFORTH .word lastforthword
2856 .word lastforthword1
2858 .word lastforthword1
2859 .word lastforthword2
2860 .word lastforthword3
2862 .word lastforthword1
2863 .word lastforthword2
2864 .word lastforthword3
2865 .word lastforthword4
2866 .word lastforthword5
2867 .word lastforthword6
2868 .word lastforthword7
2870 .word lastforthword1
2871 .word lastforthword2
2872 .word lastforthword3
2873 .word lastforthword4
2874 .word lastforthword5
2875 .word lastforthword6
2876 .word lastforthword7
2877 .word lastforthword8
2878 .word lastforthword9
2879 .word lastforthword10
2880 .word lastforthword11
2881 .word lastforthword12
2882 .word lastforthword13
2883 .word lastforthword14
2884 .word lastforthword15
2886 .word lastforthword1
2887 .word lastforthword2
2888 .word lastforthword3
2889 .word lastforthword4
2890 .word lastforthword5
2891 .word lastforthword6
2892 .word lastforthword7
2893 .word lastforthword8
2894 .word lastforthword9
2895 .word lastforthword10
2896 .word lastforthword11
2897 .word lastforthword12
2898 .word lastforthword13
2899 .word lastforthword14
2900 .word lastforthword15
2901 .word lastforthword16
2902 .word lastforthword17
2903 .word lastforthword18
2904 .word lastforthword19
2905 .word lastforthword20
2906 .word lastforthword21
2907 .word lastforthword22
2908 .word lastforthword23
2909 .word lastforthword24
2910 .word lastforthword25
2911 .word lastforthword26
2912 .word lastforthword27
2913 .word lastforthword28
2914 .word lastforthword29
2915 .word lastforthword30
2916 .word lastforthword31
2918 .ELSECASE ; = CASE 1
2920 .word voclink ; here, voclink = 0
2923 ;X ALSO -- make room to put a vocabulary as first in context
2924 .IFDEF VOCABULARY_SET
2926 .ENDIF ; VOCABULARY_SET
2927 ALSO MOV #12,W ; -- move up 6 words, 8th word of CONTEXT area must remain to 0
2928 MOV #CONTEXT,X ; X=src
2929 MOV #CONTEXT+2,Y ; Y=dst
2930 JMP MOVEUP ; src < dst
2932 ;X PREVIOUS -- pop last vocabulary out of context
2933 .IFDEF VOCABULARY_SET
2934 FORTHWORD "PREVIOUS"
2935 .ENDIF ; VOCABULARY_SET
2936 PREVIOUS MOV #14,W ; move down 7 words, with recopy of the 8th word equal to 0
2937 MOV #CONTEXT+2,X ; X=src
2938 MOV #CONTEXT,Y ; Y=dst
2939 JMP MOVEDOWN ; src > dst
2941 ;X ONLY -- cut context list to access only first vocabulary, ex.: FORTH ONLY
2942 .IFDEF VOCABULARY_SET
2944 .ENDIF ; VOCABULARY_SET
2945 ONLY MOV #0,&CONTEXT+2
2948 ;X DEFINITIONS -- set last context vocabulary as entry for further defining words
2949 .IFDEF VOCABULARY_SET
2950 FORTHWORD "DEFINITIONS"
2951 .ENDIF ; VOCABULARY_SET
2952 DEFINITIONS MOV &CONTEXT,&CURRENT
2955 ;-------------------------------------------------------------------------------
2956 ; IMPROVED ON/OFF AND RESET
2957 ;-------------------------------------------------------------------------------
2959 STATE_DOES ; execution part of PWR_STATE ; sorry, doesn't restore search order pointers
2960 .word FORTH,ONLY,DEFINITIONS
2961 FORTHtoASM ; -- BODY IP is free
2962 MOV @TOS+,W ; -- BODY+2 W = old VOCLINK = VLK
2963 MOV W,&LASTVOC ; -- BODY+2 restore LASTVOC
2964 MOV @TOS,TOS ; -- OLD_DP
2965 MOV TOS,&DDP ; -- DP restore DP
2966 ; then restore words link(s) with it value < old DP
2968 .CASE 1 ; mono thread vocabularies
2969 MARKALLVOC MOV W,Y ; -- DP W=VLK Y=VLK
2970 MRKWORDLOOP MOV -2(Y),Y ; -- DP W=VLK Y=NFA
2971 CMP Y,TOS ; -- DP CMP = TOS-Y : OLD_DP-NFA
2972 JNC MRKWORDLOOP ; loop back if TOS<Y : OLD_DP<NFA
2973 MOV Y,-2(W) ; W=VLK X=THD Y=NFA refresh thread with good NFA
2974 MOV @W,W ; -- DP W=[VLK] = next voclink
2975 CMP #0,W ; -- DP W=[VLK] = next voclink end of vocs ?
2976 JNZ MARKALLVOC ; -- DP W=VLK no : loopback
2978 .ELSECASE ; multi threads vocabularies
2979 MARKALLVOC MOV #THREADS,IP ; -- DP W=VLK
2980 MOV W,X ; -- DP W=VLK X=VLK
2981 MRKTHRDLOOP MOV X,Y ; -- DP W=VLK X=VLK Y=VLK
2982 SUB #2,X ; -- DP W=VLK X=THD (thread ((case-2)to0))
2983 MRKWORDLOOP MOV -2(Y),Y ; -- DP W=VLK Y=NFA
2984 CMP Y,TOS ; -- DP CMP = TOS-Y : DP-NFA
2985 JNC MRKWORDLOOP ; loop back if TOS<Y : DP<NFA
2986 MARKTHREAD MOV Y,0(X) ; W=VLK X=THD Y=NFA refresh thread with good NFA
2987 SUB #1,IP ; -- DP W=VLK X=THD Y=NFA IP=CFT-1
2988 JNZ MRKTHRDLOOP ; loopback to compare NFA in next thread (thread-1)
2989 MOV @W,W ; -- DP W=[VLK] = next voclink
2990 CMP #0,W ; -- DP W=[VLK] = next voclink end of vocs ?
2991 JNZ MARKALLVOC ; -- DP W=VLK no : loopback
2993 .ENDCASE ; of THREADS ; -- DP
2998 FORTHWORD "PWR_STATE" ; executed by power ON, reinitializes dictionary in state defined by PWR_HERE
2999 PWR_STATE mDODOES ; DOES part of MARKER : resets pointers DP, voclink and latest
3000 .word STATE_DOES ; execution vector of PWR_STATE
3001 MARKVOC .word lastvoclink ; initialised by forthMSP430FR.asm as voclink value
3002 MARKDP .word ROMDICT ; initialised by forthMSP430FR.asm as DP value
3004 FORTHWORD "RST_STATE" ; executed by <reset>, reinitializes dictionary in state defined by RST_HERE;
3005 RST_STATE MOV &INIVOC,&MARKVOC ; INI value saved in FRAM
3006 MOV &INIDP,&MARKDP ; INI value saved in FRAM
3009 FORTHWORD "PWR_HERE" ; define dictionnary bound for power ON
3010 PWR_HERE MOV &LASTVOC,&MARKVOC
3014 FORTHWORD "RST_HERE" ; define dictionnary bound for <reset>...
3015 RST_HERE MOV &LASTVOC,&INIVOC
3017 JMP PWR_HERE ; ...and also for power ON...
3019 FORTHWORD "WIPE" ; restore the program as it was in forthMSP430FR.txt file
3020 WIPE ; reset JTAG and BSL signatures ; unlock JTAG, SBW and BSL
3021 MOV #16,X ; max known SIGNATURES length = 10
3023 MOV #-1,SIGNATURES(X) ; reset signature; WARNING ! DON'T CHANGE THIS IMMEDIATE VALUE !
3025 CALL #WIP_DEFER ; set default execute part of all factory primary DEFERred words
3026 MOV #ROMDICT,&INIDP ; reinit this 2 factory values
3027 MOV #lastvoclink,&INIVOC
3028 JMP RST_STATE ; then execute RST_STATE and PWR_STATE
3030 ; ------------------------------------------------------------------------------
3031 ; forthMSP430FR : WARM
3032 ; ------------------------------------------------------------------------------
3034 ;Z WARM -- ; deferred word used to init your application
3035 ; define this word: : START ...init app here... LIT RECURSE IS WARM (WARM) ;
3041 ; MOV &SYSSNIV,0(PSP)
3042 ; MOV &SYSUNIV,2(PSP)
3043 MOV &SAVE_SYSRSTIV,TOS ; to display it
3046 .byte 6,13,1Bh,"[7m#" ; CR + cmd "reverse video" + #
3048 .word DOT ; display signed SAVE_SYSRSTIV
3049 ; .word DOT ; display SYSSNIV
3050 ; .word DOT ; display SYSUNIV
3052 .byte 31,"FastForth ",VER," (C)J.M.Thoorens "
3054 .word LIT,FRAM_FULL,HERE,MINUS,UDOT
3056 .byte 11,"bytes free ";
3057 .word QABORTYESNOECHO ; NOECHO state enables any app to execute COLD or WARM without terminal connexion
3061 ;-------------------------------------------------------------------------------
3062 ; RESET : Initialisation limited to FORTH usage : I/O, RAM, RTC
3063 ; all unused I/O are set as input with pullup resistor
3064 ;-------------------------------------------------------------------------------
3066 ;Z COLD -- performs a software reset
3068 COLD MOV #0A500h+PMMSWBOR,&PMMCTL0
3071 .include "Target.asm" ; include target specific init code
3074 ; fill all interrupt vectors with RESET
3075 MOV #VECTLEN,X ; length of vectors area
3077 MOV #RESET,INTVECT(X) ; begin at end of area
3078 JNZ RESETINT ; endloop when INTVECT(X) = INTVECT
3080 ; reset default TERMINAL vector interrupt and LPM0 mode for terminal use
3081 MOV #TERMINAL_INT,&TERMVEC
3082 MOV #CPUOFF+GIE,&LPM_MODE
3088 JNZ INITRAM ; 6~ loop
3090 ;-------------------------------------------------------------------------------
3091 ; RESET : INIT FORTH machine
3092 ;-------------------------------------------------------------------------------
3093 MOV #RSTACK,RSP ; init return stack
3094 MOV #PSTACK,PSP ; init parameter stack
3097 MOV #xdocol,rDOCOL ;
3100 .CASE 3 ; inlined DOCOL, do nothing here
3104 MOV #xdodoes,rDODOES
3106 MOV #10,&BASE ; init BASE
3107 MOV #-1,&CAPS ; init CAPS ON
3109 ;-------------------------------------------------------------------------------
3110 ; RESET : test TERM_TXD before init TERM_UART I/O
3111 ;-------------------------------------------------------------------------------
3112 BIC #LOCKLPM5,&PM5CTL0 ; activate all previous I/O settings before DEEP_RST test
3113 MOV &SAVE_SYSRSTIV,Y ;3
3114 BIT.B #TXD,&TERM_IN ; TERM_TXD wired to GND via 4k7 resistor ?
3116 XOR #-1,Y ;1 yes : force DEEP_RST (WIPE + COLD)
3117 ADD #1,Y ;1 to display SAVE_SYSRSTIV as negative value
3118 MOV Y,&SAVE_SYSRSTIV ;3 save
3121 ;-------------------------------------------------------------------------------
3122 ; RESET : INIT TERM_UART
3123 ;-------------------------------------------------------------------------------
3124 MOV #0081h,&TERMCTLW0 ; Configure TERM_UART UCLK = SMCLK
3125 MOV &TERMBRW_RST,&TERMBRW ; RST value in FRAM
3126 MOV &TERMMCTLW_RST,&TERMMCTLW ; RST value in FRAM
3127 BIS.B #TERM_BUS,&TERM_SEL ; Configure pins TXD & RXD for TERM_UART (PORTx_SEL0 xor PORTx_SEL1)
3128 ; TERM_DIR is controlled by eUSCI_Ax module
3129 BIC #UCSWRST,&TERMCTLW0 ; release from reset...
3130 BIS #UCRXIE,&TERMIE ; ... then enable RX interrupt for wake up on terminal input
3132 ;-------------------------------------------------------------------------------
3133 ; RESET : Select POWER_ON|<reset>|DEEP_RST from Y = SAVE_SYSRSTIV
3134 ;-------------------------------------------------------------------------------
3136 SelectReset MOV #COLD_END,IP ; define return of WIPE,RST_STATE,PWR_STATE
3137 CMP #0Ah,Y ; reset event = security violation BOR ???? not documented...
3138 JZ WIPE ; Add WIPE to this reset to do DEEP_RST --------------
3139 CMP #16h,Y ; reset event > software POR : failure or DEEP_RST request
3140 JHS WIPE ; U>= ; Add WIPE to this reset to do DEEP_RST
3141 CMP #2,Y ; reset event = Brownout ?
3142 JNZ RST_STATE ; else execute RST_STATE, return to COLD_END
3143 JZ PWR_STATE ; yes execute PWR_STATE, return to COLD_END
3145 ;-------------------------------------------------------------------------------
3146 ; RESET : INIT SD_Card option
3147 ;-------------------------------------------------------------------------------
3149 .IFNDEF SD_CARD_LOADER ;
3150 .word WARM ; the next step
3153 .IFDEF RAM_1K ; case of MSP430FR57xx : SD datas are in FRAM
3154 MOV #0,&CurrentHDL ; init this FRAM area to pass QABORT
3156 BIT.B #SD_CD,&SD_CDIN ; SD_memory in SD_Card module ?
3158 .include "forthMSP430FR_SD_INIT.asm";
3162 ;-------------------------------------------------------------------------------
3164 ;-------------------------------------------------------------------------------
3165 .IFDEF MSP430ASSEMBLER
3166 .include "forthMSP430FR_ASM.asm"
3169 ;-------------------------------------------------------------------------------
3170 ; SD CARD FAT OPTIONS
3171 ;-------------------------------------------------------------------------------
3172 .IFDEF SD_CARD_LOADER
3173 .include "forthMSP430FR_SD_LowLvl.asm" ; SD primitives
3174 .include "forthMSP430FR_SD_LOAD.asm" ; SD LOAD driver
3175 ;---------------------------------------------------------------------------
3176 ; SD CARD READ WRITE
3177 ;---------------------------------------------------------------------------
3178 .IFDEF SD_CARD_READ_WRITE
3179 .include "forthMSP430FR_SD_RW.asm" ; SD Read/Write driver
3181 ;-----------------------------------------------------------------------
3183 ;-----------------------------------------------------------------------
3185 .include "ADDON/SD_TOOLS.asm"
3189 ;-------------------------------------------------------------------------------
3190 ; UTILITY WORDS OPTION
3191 ;-------------------------------------------------------------------------------
3193 .include "ADDON/UTILITY.asm"
3196 ;-------------------------------------------------------------------------------
3197 ; FIXED POINT OPERATORS OPTION
3198 ;-------------------------------------------------------------------------------
3200 .include "ADDON/FIXPOINT.asm"
3203 ;-------------------------------------------------------------------------------
3204 ; UART to I2C bridge OPTION
3205 ;-------------------------------------------------------------------------------
3206 .IFDEF UARTtoI2C ; redirects TERMINAL on to I2C address
3207 .include "ADDON/UART2MI2C.asm"
3210 ;-------------------------------------------------------------------------------
3211 ; ADD HERE YOUR PROGRAM TO BE INTEGRATED IN CORE (protected against WIPE)
3212 ;vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
3214 ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3216 ;-------------------------------------------------------------------------------
3217 ; RESOLVE ASSEMBLY PTR
3218 ;-------------------------------------------------------------------------------
3220 .include "ResolveThreads.mac"