1 ; -*- coding: utf-8 -*-
3 ;-------------------------------------------------------------------------------
4 ; Vingt fois sur le métier remettez votre ouvrage,
5 ; Polissez-le sans cesse, et le repolissez,
6 ; Ajoutez quelquefois, et souvent effacez. Boileau, L'Art poétique
7 ;-------------------------------------------------------------------------------
9 ;-------------------------------------------------------------------------------
10 ; SCITE editor: copy https://www.scintilla.org/Sc4xx.exe to \prog\scite.exe
11 ;-------------------------------------------------------------------------------
13 ; unzip http://john.ccac.rwth-aachen.de:8000/ftp/as/precompiled/i386-unknown-win32/aswcurr.zip
14 ;-------------------------------------------------------------------------------
15 .listing purecode ; reduce listing to true conditionnal parts
16 MACEXP_DFT noif ; reduce macros listing to true part
18 ;-------------------------------------------------------------------------------
20 VER .equ "V308" ; FORTH version
22 ;===============================================================================
23 ; before assembling or programming you must set TARGET in scite param1 (SHIFT+F8)
24 ; according to the selected (uncommented) TARGET below
25 ;===============================================================================
27 ;===============================================================================
28 ; FAST FORTH has a minimalistic footprint to enable its use from 8k FRAM devices
29 ; kernel size below are for 8MHz, DTC=1, THREADS=1, 4WIRES (RTS) options
30 ;===============================================================================
31 ; TARGET ; ;INFO+VECTORS+ MAIN bytes
32 ;MSP_EXP430FR5739 ; compile for MSP-EXP430FR5739 launchpad ; 64 + 128 + 2768 bytes
33 ;MSP_EXP430FR5969 ; compile for MSP-EXP430FR5969 launchpad ; 64 + 128 + 2760 bytes
34 ;MSP_EXP430FR5994 ; compile for MSP-EXP430FR5994 launchpad ; 64 + 128 + 2780 bytes
35 ;MSP_EXP430FR6989 ; compile for MSP-EXP430FR6989 launchpad ; 64 + 128 + 2782 bytes
36 ;MSP_EXP430FR4133 ; compile for MSP-EXP430FR4133 launchpad ; 64 + 128 + 2822 bytes
37 ;MSP_EXP430FR2355 ; compile for MSP-EXP430FR2355 launchpad ; 64 + 128 + 2756 bytes
38 ;MSP_EXP430FR2433 ; compile for MSP-EXP430FR2433 launchpad ; 64 + 128 + 2746 bytes
39 ;LP_MSP430FR2476 ; compile for LP_MSP430FR2476 launchpad ; 64 + 128 + 2760 bytes
40 CHIPSTICK_FR2433; ; compile for "CHIPSTICK" of M. Ken BOAK ; 64 + 128 + 2748 bytes
42 ; choose DTC model (Direct Threaded Code); if you don't know, choose 2, because DOCOL routine without using scratch register
43 DTC .equ 2 ; DTC model 1 : DOCOL = CALL rDOCOL 14 cycles 1 word shortest DTC model
44 ; DTC model 2 : DOCOL = PUSH IP, CALL rEXIT 13 cycles 2 words best compromize to mix FORTH/ASM code
45 ; DTC model 3 : inlined DOCOL 9 cycles 4 words fastest
47 THREADS .equ 16 ; 1, 2 , 4 , 8 , 16, 32 search entries in dictionnary.
48 ; +0, +28, +48, +56, +90, +154 bytes, usefull to speed up compilation;
49 ; the FORTH interpreter is speed up by about a square root factor of THREADS.
51 FREQUENCY .equ 1 ; fully tested at 1,2,4,8,16,24 MHz (24 MHz for MSP430FR57xx,MSP430FR2355)
53 ;===============================================================================
54 TERMINAL_I2C ; uncomment to select I2C_Master TERMINAL instead of UART TERMINAL
55 ;===============================================================================
58 ;===============================================================================
60 ;===============================================================================
61 TERMINALBAUDRATE .equ 115200 ; choose value considering the frequency and the UART2USB bridge, see explanations below.
62 ;-------------------------------------------------------------------------------
63 TERMINAL3WIRES ; + 18 bytes enable 3 wires (GND,TX,RX) with XON/XOFF software flow control (PL2303TA/HXD, CP2102)
64 TERMINAL4WIRES ; + 12 bytes enable 4 wires with hardware flow control on RX with RTS (PL2303TA/HXD, FT232RL)
65 ;TERMINAL5WIRES ; + 10 bytes enable 5 wires with hardware flow control on RX/TX with RTS/CTS (PL2303TA/HXD, FT232RL)...
66 ;-------------------------------------------------------------------------------
67 ;HALFDUPLEX ; switch to UART half duplex TERMINAL input
68 ;===============================================================================
70 ;===============================================================================
71 ; MINIMAL ADDONS if you want a canonical FORTH: CORE_COMPLEMENT + CONDCOMP + PROMPT
72 ;===============================================================================
73 ; MINIMAL ADDONS for FAST FORTH: MSP430ASSEMBLER + CONDCOMP
74 ;===============================================================================
76 ;-------------------------------------------------------------------------------
77 ; KERNEL ADDONs that can't be added later
78 ;-------------------------------------------------------------------------------
79 MSP430ASSEMBLER ; + 1812 bytes : adds embedded assembler with TI syntax; without, you can do all but bigger and slower...
80 CONDCOMP ; + 306 bytes : adds conditionnal compilation [IF] [ELSE] [THEN] [DEFINED] [UNDEFINED]
81 DOUBLE_INPUT ; + 56 bytes : adds the interpretation engine for double numbers (numbers with dot)
82 FIXPOINT_INPUT ; + 74 bytes : adds the interpretation engine for Q15.16 numbers (numbers with comma)
83 ;DEFERRED ; + 124 bytes : adds DEFER IS :NONAME CODENNM (CODE_No_NaMe), useful for interrupts start and stop.
84 ;EXTENDED_MEM ; + 740 bytes : allows assembler to execute code up to 1MB (LARGE_CODE).
85 ;EXTENDED_ASM ; + 1260 bytes : extended assembler to 20 bits datas (LARGE_DATA + LARGE_CODE).
86 ;SD_CARD_LOADER ; + 1766 bytes : to load source files from SD_card
87 ;SD_CARD_READ_WRITE ; + 1148 bytes : to read, create, write and del files + copy text files from PC to target SD_Card
88 ;BOOTLOADER ; + 132 bytes : includes in WARM process the bootloader SD_CARD\BOOT.4TH.
89 ;VOCABULARY_SET ; + 174 bytes : adds words: VOCABULARY FORTH ASSEMBLER ALSO PREVIOUS ONLY DEFINITIONS (FORTH83)
90 ;PROMPT ; + 22 bytes : to display prompt "ok "
91 ;-------------------------------------------------------------------------------
93 ;-------------------------------------------------------------------------------
94 ; OPTIONS that can be added later by downloading their source file >-----------------------+
95 ; however, added here, they are protected against WIPE and Deep Reset. |
96 ;------------------------------------------------------------------------------- v
97 ;CORE_COMPLEMENT ; + 1974 bytes : MINIMAL OPTIONS if you want a conventional FORTH CORECOMP.f
98 ;FIXPOINT ; + 422/528 bytes add HOLDS F+ F- F/ F* F#S F. S>F FIXPOINT.f
99 ;UTILITY ; + 434/524 bytes (1/16threads) : add .S .RS WORDS U.R DUMP ? UTILITY.f
100 ;SD_TOOLS ; + 142 bytes for trivial DIR, FAT, CLUSTR. and SECTOR. view, (adds UTILITY) SD_TOOLS.f
103 ;===============================================================================
104 ; Software control flow XON/XOFF configuration:
105 ;===============================================================================
106 ; Launchpad <-> UARTtoUSB device <-> TeraTerm TERMINAL
111 ; TERATERM config terminal: NewLine receive : LF,
112 ; NewLine transmit : CR+LF
113 ; Size : 96 chars x 49 lines (adjust lines according to your display)
115 ; TERATERM config serial port: TERMINALBAUDRATE value,
116 ; 8 bits, no parity, 1 Stop bit,
117 ; XON/XOFF flow control,
118 ; delay = 0ms/line, 0ms/char
120 ; don't forget to save always new TERATERM configuration !
122 ; ------------------------------------------------------------------------------
123 ; Only two usb2uart bridges correctly handle XON / XOFF: cp2102 and pl2303.
124 ; ------------------------------------------------------------------------------
125 ; the best and cheapest: UARTtoUSB cable with Prolific PL2303HXD (or PL2303TA)
126 ; works well in 3 WIRES (XON/XOFF) and 4WIRES (GND,RX,TX,RTS) config
127 ; ------------------------------------------------------------------------------
128 ; PL2303TA 4 wires CABLE PL2303HXD 6 wires CABLE
129 ; pads upside: 3V3,txd,rxd,gnd,5V pads upside: gnd, 3V3,txd,rxd,5V
130 ; downside: cts,dcd,dsr,rts,dtr downside: rts,cts
131 ; ------------------------------------------------------------------------------
132 ; WARNING ! if you use PL2303TA/HXD cable as supply, open the box before to weld red wire on 3v3 pad !
133 ; ------------------------------------------------------------------------------
134 ; up to 115200 Bds (500kHz)
135 ; up to 230400 Bds (1MHz)
136 ; up to 460800 Bds (2MHz)
137 ; up to 921600 Bds (4MHz)
138 ; up to 1843200 Bds (8MHz)
139 ; up to 3 MBds (12MHz,PL2303HXD with shortened cable < 20cm)
140 ; up to 4 MBds (16MHz,PL2303HXD with shortened cable < 20cm)
141 ; up to 5 MBds (20MHz,PL2303HXD with shortened cable < 20cm)
142 ; up to 6 MBds (24MHz,PL2303HXD with shortened cable < 20cm)
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)
149 ; + 57600, 115200 (500kHz)
150 ; + 134400,230400 (1MHz)
152 ; + 921600 (4MHz,8MHz,16MHz,24MHz)
154 ;===============================================================================
155 ; Hardware control flow configuration: RTS is wired on UART2USB CTS pin
156 ;===============================================================================
158 ; Launchpad <-> UARTtoUSB
161 ; RTS --> CTS (see launchpad.asm for RTS selected pin)
164 ; RTS pin may be permanently wired on SBWTCK/TEST pin without disturbing SBW 2 wires programming
166 ; TERATERM config terminal : NewLine receive : LF,
167 ; NewLine transmit : CR+LF
168 ; Size : 96 chars x 49 lines (adjust lines to your display)
170 ; TERATERM config serial port : TERMINALBAUDRATE value,
171 ; 8bits, no parity, 1Stopbit,
172 ; Hardware flow control,
173 ; delay = 0ms/line, 0ms/char
175 ; don't forget : save new TERATERM configuration !
177 ; notice that the control flow seems not necessary for TX (CTS <-- RTS)
179 ; UARTtoUSB module with PL2303TA/HXD
180 ; ------------------------------------------------------------------------------
181 ; WARNING ! if you use PL2303TA/HXD cable as supply, open the box before to weld red wire on 3v3 pad !
182 ; ------------------------------------------------------------------------------
183 ; up to 250 kbds / MHz
184 ; ----------------------------------
185 ; 9600,19200,38400,57600 (250kHz)
187 ; + 201600,230400,250000 (1MHz)
188 ; + 403200,460800 (2MHz)
189 ; + 806400,921600 (4MHz)
196 ; UARTtoUSB module with FTDI FT232RL (FT230X don't work correctly)
197 ; ------------------------------------------------------------------------------
198 ; WARNING ! buy a FT232RL module with a switch 5V/3V3 and select 3V3 !
199 ; ------------------------------------------------------------------------------
200 ; 9600,19200,38400,57600,115200 (500kHz)
203 ; + 921600 (4,8,16 MHz)
205 ; ------------------------------------------------------------------------------
206 ; UARTtoBluetooth 2.0 module (RN42 sparkfun bluesmirf) at 921600bds
207 ; ------------------------------------------------------------------------------
208 ; 9600,19200,38400,57600,115200 (500kHz)
211 ; + 921600 (4,8,16 MHz)
213 ; RN42 config : connect RN41/RN42 module on teraterm, via USBtoUART bridge,
214 ; ----------- 8n1, 115200 bds, no flow control, echo on
215 ; $$$ // enter control mode, response: AOK
216 ; SU,92 // set 921600 bds, response: AOK
217 ; R,1 // reset module to take effect
219 ; connect RN42 module on FastForth target
220 ; add new bluetooth device on windows, password=1234
221 ; open the created output COMx port with TERATERM at 921600bds
224 ; TERATERM config terminal : NewLine receive : LF,
225 ; NewLine transmit : CR+LF
226 ; Size : 128 chars x 49 lines (adjust lines to your display)
228 ; TERATERM config serial port : TERMINALBAUDRATE value,
229 ; 8bits, no parity, 1Stopbit,
230 ; Hardware flow control or software flow control or ...no flow control!
231 ; delay = 0ms/line, 0ms/char
233 ; don't forget : save new TERATERM configuration !
235 ; in fact, compared to using a UART USB bridge, only the COMx port is to be updated.
236 ; ------------------------------------------------------------------------------
238 .include "ThingsInFirst.inc" ; macros, target definitions, init FORTH variables...
239 ;-------------------------------------------------------------------------------
240 ; DTCforthMSP430FR5xxx RAM memory map:
241 ;-------------------------------------------------------------------------------
243 ;---------------------------;---------
244 ; name words ; comment
245 ;---------------------------;---------
246 ;LSTACK = L0 = LEAVEPTR ; ----- RAM_ORG
248 LSTACK_LEN .equ 16 ; | grows up
251 PSTACK_LEN .equ 48 ; | grows down
253 ;PSTACK=S0 ; ----- RAM_ORG + $80
255 RSTACK_LEN .equ 48 ; | grows down
257 ;RSTACK=R0 ; ----- RAM_ORG + $E0
259 ;---------------------------;---------
260 ; names bytes ; comments
261 ;---------------------------;---------
262 ; PAD_I2CADR ; ----- RAM_ORG + $E0
264 ; PAD < ----- RAM_ORG + $E4
266 PAD_LEN .equ 84 ; | grows up (ans spec. : PAD >= 84 chars)
268 ; TIB_I2CADR ; ----- RAM_ORG + $138
270 ; TIB < ----- RAM_ORG + $13C
272 TIB_LEN .equ 84 ; | grows up (ans spec. : TIB >= 80 chars)
274 ; HOLDS_ORG < ------RAM_ORG + $190
276 HOLD_LEN .equ 34 ; | grows down (ans spec. : HOLD_LEN >= (2*n) + 2 char, with n = 16 bits/cell
278 ; HOLD_BASE < ----- RAM_ORG + $1B2
282 ; ----- RAM_ORG + $1E0
286 ; SD_BUF_I2CADR < ----- RAM_ORG + $1FC
288 ; SD_BUF < ----- RAM_ORG + $200
290 SD_BUF_LEN .equ 200h ; 512 bytes buffer
292 ; SD_BUF_END < ----- RAM_ORG + $400
295 LEAVEPTR .equ LSTACK ; Leave-stack pointer
296 PSTACK .equ LSTACK+(LSTACK_LEN*2)+(PSTACK_LEN*2)
297 RSTACK .equ PSTACK+(RSTACK_LEN*2)
298 PAD_I2CADR .equ PAD_ORG-4
299 PAD_I2CCNT .equ PAD_ORG-2
300 PAD_ORG .equ RSTACK+4
301 TIB_I2CADR .equ TIB_ORG-4
302 TIB_I2CCNT .equ TIB_ORG-2
303 TIB_ORG .equ PAD_ORG+PAD_LEN+4
304 HOLDS_ORG .equ TIB_ORG+TIB_LEN
306 HOLD_BASE .equ HOLDS_ORG+HOLD_LEN
308 ; ----------------------------------------------------
309 ; RAM_ORG + $1B2 : RAM VARIABLES
310 ; ----------------------------------------------------
311 HP .equ HOLD_BASE ; HOLD ptr
312 CAPS .equ HOLD_BASE+2 ; CAPS ON = 32, CAPS OFF = 0
313 LAST_NFA .equ HOLD_BASE+4 ; NFA, VOC_PFA, CFA, PSP of last created word
314 LAST_THREAD .equ HOLD_BASE+6 ; used by QREVEAL
315 LAST_CFA .equ HOLD_BASE+8
316 LAST_PSP .equ HOLD_BASE+10
317 STATE .equ HOLD_BASE+12 ; Interpreter state
318 SOURCE .equ HOLD_BASE+14 ; len, org of input stream
319 SOURCE_LEN .equ HOLD_BASE+14
320 SOURCE_ORG .equ HOLD_BASE+16
321 TOIN .equ HOLD_BASE+18 ; CurrentInputBuffer pointer
322 DDP .equ HOLD_BASE+20 ; dictionnary pointer
323 LASTVOC .equ HOLD_BASE+22 ; keep VOC-LINK
324 CONTEXT .equ HOLD_BASE+24 ; CONTEXT dictionnary space (8 CELLS)
325 CURRENT .equ HOLD_BASE+40 ; CURRENT dictionnary ptr
326 BASE .equ HOLD_BASE+42
327 LINE .equ HOLD_BASE+44 ; line in interpretation (see NOECHO, ECHO)
329 ; --------------------------;
330 ; RAM_ORG + $1E0 : free use ;
331 ; --------------------------;
332 .IFDEF SD_CARD_LOADER
333 ; --------------------------------------------------
334 ; RAM_ORG + $1FC : RAM SD_CARD SD_BUF 4 + 512 bytes
335 ; --------------------------------------------------
336 SD_BUF_I2CADR .equ SD_BUF-4
337 SD_BUF_I2CCNT .equ SD_BUF-2
338 SD_BUF .equ HOLD_BASE+78
339 SD_BUF_END .equ SD_BUF + 200h ; 512bytes
343 ;-------------------------------------------------------------------------------
344 ; INFO(DCBA) >= 256 bytes memory map (FRAM) :
345 ;-------------------------------------------------------------------------------
346 ; FRAM INFO: KERNEL INIT CONSTANTS and VARIABLES
347 ; ----------------------------------------------
348 FREQ_KHZ .word FREQUENCY*1000 ; used to stabilize MCLK before start, see MSP430FRxxxx.asm
350 I2CSLAVEADR .word MYSLAVEADR ; on MSP430FR2xxx devices with BSL I2C, Slave address is FFA0h
352 LPM_MODE .word GIE+LPM4 ; LPM4 is the default mode for I2C TERMINAL
353 .ELSE ; TERMINAL_UART
354 TERMBRW_RST .word TERMBRW_INI ; set by TERMINALBAUDRATE.inc
355 TERMMCTLW_RST .word TERMMCTLW_INI ; set by TERMINALBAUDRATE.inc
356 LPM_MODE .word GIE+LPM0 ; LPM0 is the default mode for UART TERMINAL
358 RSTIV_MEM .word -7 ; to do RESET = -3 when compiling new kernel
359 RST_DP .word ROMDICT ; define RST_STATE
360 RST_VOC .word lastvoclink ; define RST_STATE
361 FORTHVERSION .word VAL(SUBSTR(VER,1,0)); used by WARM
362 INI_THREAD .word THREADS ; used by FF_SPECS.f, UTILITY.f
363 FORTHADDON .word FADDON ; used by FF_SPECS.f and to secure donwloading of any application.f files.
364 ; --------------------------------------;
365 WIPE_INI ; MOV #WIPE_INI,X ; WIPE_INI constants are in FRAM INFO= DEEP_RESET init
366 ; --------------------------------------;
367 .IFNDEF SD_CARD_LOADER
368 WIPE_COLD .word COLD_TERM ; MOV @X+,&PFACOLD ; COLD_TERM --> PFACOLD
369 WIPE_INI_FORTH .word RET_ADR ; MOV @X+,&PFA_INI_FORTH; RET_ADR --> PFA_INI_FORTH
370 WIPE_SLEEP .word RXON ; MOV @X+,&PFASLEEP ; RXON --> PFASLEEP
371 WIPE_WARM .word INIT_TERM ; MOV @X+,&PFAWARM ; INIT_TERM --> PFAWARM
373 WIPE_COLD .word COLD_TERM ; MOV @X+,&PFACOLD ; COLD_TERM --> PFACOLD
374 WIPE_INI_FORTH .word INI_SOFT_SD ; MOV @X+,&PFA_INI_FORTH; INI_SOFT_SD --> PFA_INI_FORTH
375 WIPE_SLEEP .word RXON ; MOV @X+,&PFASLEEP ; RXON --> PFASLEEP
376 WIPE_WARM .word INI_HARD_SD ; MOV @X+,&PFAWARM ; INI_HARD_SD --> PFAWARM
378 WIPE_TERM_INT .word TERMINAL_INT ; MOV @X+,&TERM_VEC ; TERMINAL_INT --> TERM_VEC
379 WIPE_DP .word ROMDICT ; MOV @X+,&RST_DP ; ROMDICT --> RST_DP
380 WIPE_VOC .word lastvoclink ; MOV @X+,&RST_VOC ; lastvoclink --> RST_VOC
381 ; --------------------------------------;
382 INI_FORTH_INI ; MOV #INI_FORTH_INI,X, to reset all kernel variables
383 ; --------------------------------------;
384 INI_FORTH_ACCEPT .word BODYACCEPT ; MOV @X+,&PFAACCEPT ; BODYACCEPT --> PFAACCEPT
385 INI_FORTH_CR .word BODYCR ; MOV @X+,&PFACR ; BODYCR --> PFACR
386 INI_FORTH_EMIT .word BODYEMIT ; MOV @X+,&PFAEMIT ; BODYEMIT --> PFAEMIT
387 INI_FORTH_KEY .word BODYKEY ; MOV @X+,&PFAKEY ; BODYKEY --> PFAKEY
388 INI_FORTH_CIB .word TIB_ORG ; MOV @X+,&CIB_ADR ; TIB_ORG --> CIB_ADR
389 ; --------------------------------------;
390 HALF_FORTH_INI ; MOV #HALF_FORTH_INI,X to preserve defered words
391 ; --------------------------------------;
394 INI_FORTH_COL .word xDOCOL ; MOV @X+,rDOCOL ; init rDOCOL (R4)
396 INI_FORTH_COL .word EXIT ; MOV @X+,rDOCOL ; init rDOCOL (R4)
398 .word 0 ; MOV @X+,R4 ; rDOCOL doesn't exist
400 INI_FORTH_DOES .word xDODOES ; MOV @X+,rDODOES ; init rDODOES (R5)
401 INI_FORTH_CON .word xDOCON ; MOV @X+,rDOCON ; init rDOCON (R6)
402 INI_FORTH_VAR .word RFROM ; MOV @X+,rDOVAR ; init rDOVAR (R7)
403 INI_FORTH_CAPS .word 32 ; MOV @X+,&CAPS ; 32 --> CAPS
404 INI_FORTH_BASE .word 10 ; MOV @X+,&BASE ; 10 --> BASE
405 ; --------------------------------------;
412 .IFDEF SD_CARD_LOADER
413 ; ---------------------------------------
414 ; VARIABLES that should be in RAM
415 ; ---------------------------------------
416 .IF RAM_LEN < 2048 ; if RAM < 2K (FR57xx) the variables below are in INFO space (FRAM)
417 SD_ORG .equ INFO_ORG+5Ah ;
418 .ELSE ; if RAM >= 2k the variables below are in RAM
419 SD_ORG .equ SD_BUF_END+2 ; 1 word guard
423 ; ---------------------------------------
424 ; FAT FileSystemInfos
425 ; ---------------------------------------
426 FATtype .equ SD_ORG+0
427 BS_FirstSectorL .equ SD_ORG+2 ; init by SD_Init, used by RW_Sector_CMD
428 BS_FirstSectorH .equ SD_ORG+4 ; init by SD_Init, used by RW_Sector_CMD
429 OrgFAT1 .equ SD_ORG+6 ; init by SD_Init,
430 FATSize .equ SD_ORG+8 ; init by SD_Init,
431 OrgFAT2 .equ SD_ORG+10 ; init by SD_Init,
432 OrgRootDIR .equ SD_ORG+12 ; init by SD_Init, (FAT16 specific)
433 OrgClusters .equ SD_ORG+14 ; init by SD_Init, Sector of Cluster 0
434 SecPerClus .equ SD_ORG+16 ; init by SD_Init, byte size
436 ; ---------------------------------------
438 ; ---------------------------------------
439 SD_LOW_LEVEL .equ SD_ORG+18
440 SD_CMD_FRM .equ SD_LOW_LEVEL ; SD_CMDx inverted frame ${CRC7,ll,LL,hh,HH,CMD}
441 SectorL .equ SD_LOW_LEVEL+6
442 SectorH .equ SD_LOW_LEVEL+8
443 ; ---------------------------------------
445 ; ---------------------------------------
446 BufferPtr .equ SD_LOW_LEVEL+10
447 BufferLen .equ SD_LOW_LEVEL+12
448 ; ---------------------------------------
450 ; ---------------------------------------
451 SD_FAT_LEVEL .equ SD_LOW_LEVEL+14
452 ClusterL .equ SD_FAT_LEVEL ;
453 ClusterH .equ SD_FAT_LEVEL+2 ;
454 NewClusterL .equ SD_FAT_LEVEL+4 ;
455 NewClusterH .equ SD_FAT_LEVEL+6 ;
456 CurFATsector .equ SD_FAT_LEVEL+8 ; current FATSector of last free cluster
457 ; ---------------------------------------
459 ; ---------------------------------------
460 DIRClusterL .equ SD_FAT_LEVEL+10 ; contains the Cluster of current directory ; = 1 as FAT16 root directory
461 DIRClusterH .equ SD_FAT_LEVEL+12 ; contains the Cluster of current directory ; = 1 as FAT16 root directory
462 EntryOfst .equ SD_FAT_LEVEL+14
463 ; ---------------------------------------
465 ; ---------------------------------------
466 CurrentHdl .equ SD_FAT_LEVEL+16 ; contains the address of the last opened file structure, or 0
467 ; ---------------------------------------
468 ; Load file operation
469 ; ---------------------------------------
470 pathname .equ SD_FAT_LEVEL+18 ; start address
471 EndOfPath .equ SD_FAT_LEVEL+20 ; end address
472 ; ---------------------------------------
474 ; ---------------------------------------
475 FirstHandle .equ SD_FAT_LEVEL+22
476 ; three handle tokens :
477 ; HDLB_Token= 0 : free handle
479 ; = 2 : file updated (write)
480 ; =-1 : LOAD"ed file (source file)
483 HDLW_PrevHDL .equ 0 ; previous handle
484 HDLB_Token .equ 2 ; token
485 HDLB_ClustOfst .equ 3 ; Current sector offset in current cluster (Byte)
486 HDLL_DIRsect .equ 4 ; Dir SectorL
487 HDLH_DIRsect .equ 6 ; Dir SectorH
488 HDLW_DIRofst .equ 8 ; SD_BUF offset of Dir entry
489 HDLL_FirstClus .equ 10 ; File First ClusterLo (identify the file)
490 HDLH_FirstClus .equ 12 ; File First ClusterHi (identify the file)
491 HDLL_CurClust .equ 14 ; Current ClusterLo
492 HDLH_CurClust .equ 16 ; Current ClusterHi
493 HDLL_CurSize .equ 18 ; written size / not yet read size (Long)
494 HDLH_CurSize .equ 20 ; written size / not yet read size (Long)
495 HDLW_BUFofst .equ 22 ; SD_BUF offset ; used by LOAD"
496 HDLW_PrevLEN .equ 24 ; previous LEN
497 HDLW_PrevORG .equ 26 ; previous ORG
499 .IF RAM_LEN < 2048 ; due to the lack of RAM, only 4 handles and PAD replaces SDIB
500 HandleMax .equ 4 ; and not 8 to respect INFO size (FRAM)
502 HandlesLen .equ handleMax*HandleLenght
503 HandleEnd .equ FirstHandle+handleMax*HandleLenght
504 SD_END .equ HandleEnd
505 SDIB_I2CADR .equ PAD_ORG-4
506 SDIB_I2CCNT .equ PAD_ORG-2
507 SDIB_ORG .equ PAD_ORG
508 .ELSE ; RAM_Size >= 2k all is in RAM
511 HandlesLen .equ handleMax*HandleLenght
512 HandleEnd .equ FirstHandle+handleMax*HandleLenght
513 SDIB_I2CADR .equ SDIB_ORG-4
514 SDIB_I2CCNT .equ SDIB_ORG-2
515 SDIB_ORG .equ HandleEnd+4
516 SDIB_LEN .equ 84 ; = TIB_LEN = PAD_LEN
517 SD_END .equ SDIB_ORG+SDIB_LEN
519 SD_LEN .equ SD_END-SD_ORG
520 .ENDIF ; SD_CARD_LOADER
521 ; --------------------------;
522 ; INFO_ORG + $40 : free use ;
523 ; --------------------------;
526 ;-------------------------------------------------------------------------------
527 ; DTCforthMSP430FR5xxx program (FRAM) memory
528 ;-------------------------------------------------------------------------------
529 ; here we place the FORTH primitives without name.
530 ; Users can access them via declarations made in \inc\MSP430FRxxxx.pat
532 ;###############################################################################
533 ; ╦┌┐┌┌┬┐┌─┐┬─┐┬─┐┬ ┬┌─┐┌┬┐┌─┐ ┌─┐┌─┐┬ ┬ ┌┬┐┌─┐┬ ┬┌┐┌ ┬ ┬┌─┐┬─┐┌─┐
534 ; ║│││ │ ├┤ ├┬┘├┬┘│ │├─┘ │ └─┐ ├┤ ├─┤│ │ │││ │││││││ ├─┤├┤ ├┬┘├┤
535 ; ╩┘└┘ ┴ └─┘┴└─┴└─└─┘┴ ┴ └─┘ └ ┴ ┴┴─┘┴─┘ ─┴┘└─┘└┴┘┘└┘ ┴ ┴└─┘┴└─└─┘
536 ;###############################################################################
538 ; here, FAST FORTH sleeps, waiting any interrupt. With LPM4, supply current is below 1uA.
539 ; IP,S,T,W,X,Y registers (R13 to R8) are free...
540 ; ...and so TOS, PSP and RSP stacks within their rules of use.
542 ; remember: to force SLEEP execution, you must end any interrupt routine with :
544 ; BIC #%1111_1000,SR ; 2~
547 ; or faster (but return SR flags will be lost) with:
551 CALL @PC+ ;4 SLEEP first calls BACKGND_APP
552 PFASLEEP .word RXON ; BACKGND_DEF = RXON as default BACKGND_APP; value set by WIPE.
553 BIS &LPM_MODE,SR ;2 enter in LPMx mode with GIE=1
554 JMP SLEEP ;2 instruction always executed before CPU asleeping.
556 ;###############################################################################
558 ; ------------------------------------------------------------------------------
559 ; COMPILING OPERATORS
560 ; ------------------------------------------------------------------------------
561 ; Primitive LIT; compiled by LITERAL
562 ; lit -- x fetch inline literal to stack
563 ; This is the run-time code of LITERAL.
565 LIT SUB #2,PSP ; 2 push old TOS..
566 MOV TOS,0(PSP) ; 3 ..onto stack
567 MOV @IP+,TOS ; 2 fetch new TOS value
570 ; Primitive XSQUOTE; compiled by SQUOTE
571 ; (S") -- addr u run-time code to get address and length of a compiled string.
572 XSQUOTE SUB #4,PSP ; 1 -- x x TOS ; push old TOS on stack
573 MOV TOS,2(PSP) ; 3 -- TOS x x ; and reserve one cell on stack
574 MOV.B @IP+,TOS ; 2 -- x u ; u = lenght of string
575 MOV IP,0(PSP) ; 3 -- addr u IP is odd...
576 ADD TOS,IP ; 1 -- addr u IP=addr+u=addr(end_of_string)
577 BIT #1,IP ; 1 -- addr u IP=addr+u Carry set/clear if odd/even
578 ADDC #0,IP ; 1 -- addr u IP=addr+u aligned
581 ; https://forth-standard.org/standard/core/HERE
582 ; HERE -- addr returns memory ptr
587 ;-------------------------------------------------------------------------------
589 ;-------------------------------------------------------------------------------
590 ; Primitive QFBRAN; compiled by IF UNTIL
591 ;Z ?FalseBranch x -- ; branch if TOS is FALSE (TOS = 0)
592 QFBRAN CMP #0,TOS ; 1 test TOS value
593 MOV @PSP+,TOS ; 2 pop new TOS value (doesn't change flags)
594 JNZ SKIPBRANCH ; 2 if TOS was <> 0, skip the branch; 10 cycles
597 BRAN MOV @IP,IP ; 2 take the branch destination
598 MOV @IP+,PC ; 4 ==> branch taken
600 ;-------------------------------------------------------------------------------
602 ;-------------------------------------------------------------------------------
603 ; Primitive XDO; compiled by DO
604 ;Z (do) n1|u1 n2|u2 -- R: -- sys1 sys2 run-time code for DO
605 ; n1|u1=limit, n2|u2=index
606 XDO MOV #8000h,X ;2 compute 8000h-limit = "fudge factor"
608 MOV TOS,Y ;1 loop ctr = index+fudge
611 PUSHM #2,X ;4 PUSHM X,Y, i.e. PUSHM LIMIT, INDEX
614 ; Primitive XPLOOP; compiled by +LOOP
615 ;Z (+loop) n -- R: sys1 sys2 -- | sys1 sys2
616 ; run-time code for +LOOP
617 ; Add n to the loop index. If loop terminates, clean up the
618 ; return stack and skip the branch. Else take the inline branch.
619 XPLOOP ADD TOS,0(RSP) ;4 increment INDEX by TOS value
620 MOV @PSP+,TOS ;2 get new TOS, doesn't change flags
621 XLOOPNEXT BIT #100h,SR ;2 is overflow bit set?
622 JZ BRAN ;2 no overflow = loop
623 ADD #4,RSP ;1 empty RSP
624 SKIPBRANCH ADD #2,IP ;1 overflow = loop done, skip branch ofs
625 MOV @IP+,PC ;4 16~ taken or not taken xloop/loop
627 ; Primitive XLOOP; compiled by LOOP
628 ;Z (loop) R: sys1 sys2 -- | sys1 sys2
629 ; run-time code for LOOP
630 ; Add 1 to the loop index. If loop terminates, clean up the
631 ; return stack and skip the branch. Else take the inline branch.
632 ; Note that LOOP terminates when index=8000h.
633 XLOOP ADD #1,0(RSP) ;4 increment INDEX
636 ; primitive MUSMOD; compiled by ?NUMBER UM/MOD
637 ; MUSMOD UDVDlo UDVDhi UDIVlo -- UREMlo UQUOTlo UQUOThi
638 ;-------------------------------------------------------------------------------
639 ; unsigned 32-BIT DiViDend : 16-BIT DIVisor --> 32-BIT QUOTient, 16-BIT REMainder
640 ;-------------------------------------------------------------------------------
642 ; 2 times faster if DVDhi = 0 (it's the general case)
644 ; reg division MU/MOD NUM
645 ; ---------------------------------------------
646 ; S = DVD(15-0) = ud1lo = ud1lo
647 ; TOS = DVD(31-16) = ud1hi = ud1hi
648 ; W = DVD(47-32)/REM = rem = digit --> char --> -[HP]
649 ; T = DIV(15-0) = BASE = BASE
650 ; X = QUOTlo = ud2lo = ud2lo
651 ; Y = QUOThi = ud2hi = ud2hi
654 MUSMOD MOV TOS,T ;1 T = DIVlo
655 MOV 2(PSP),S ;3 S = DVDlo
656 MOV @PSP,TOS ;2 TOS = DVDhi
657 MUSMOD1 MOV #0,W ;1 W = REMlo = 0
658 MOV #32,rDODOES ;2 init loop count
659 CMP #0,TOS ;1 DVDhi=0 ?
661 ; -----------------------------------------
662 MDIV1DIV2 RRA rDODOES ;1 yes:loop count / 2
663 MOV S,TOS ;1 DVDhi <-- DVDlo
664 MOV #0,S ;1 DVDlo <-- 0
665 MOV #0,X ;1 QUOTlo <-- 0 (to do QUOThi = 0 at the end of division)
666 ; -----------------------------------------
667 MDIV1 CMP T,W ;1 REMlo U>= DIVlo ?
668 JNC MDIV2 ;2 no : carry is reset
669 SUB T,W ;1 yes: REMlo - DIVlo ; carry is set
670 MDIV2 ADDC X,X ;1 RLC quotLO
671 ADDC Y,Y ;1 RLC quotHI
672 SUB #1,rDODOES ;1 Decrement loop counter
675 ADDC TOS,TOS ;1 RLC DVDhi
676 ADDC W,W ;1 RLC REMlo
678 SUB T,W ;1 REMlo - DIVlo
681 ENDMDIV MOV #XDODOES,rDODOES ;2 restore rDODOES
682 MOV W,2(PSP) ;3 REMlo in 2(PSP)
683 MOV X,0(PSP) ;3 QUOTlo in 0(PSP)
684 MOV Y,TOS ;1 QUOThi in TOS
685 RET_ADR MOV @RSP+,PC ;4 35 words, about 473 cycles, not FORTH executable !
687 ; : SETIB SOURCE 2! 0 >IN ! ;
688 ; SETIB org len -- set Input Buffer, shared by INTERPRET and [ELSE]
689 SETIB MOV TOS,&SOURCE_LEN ; -- org len
690 MOV @PSP+,&SOURCE_ORG ; -- len
695 ; REFILL accept one line to input buffer and leave org len' of the filled input buffer
696 ; as it has no more host OS and as waiting command is done by ACCEPT, REFILL's flag is useless
697 ; : REFILL TIB DUP TIB_LEN ACCEPT ; -- org len' shared by QUIT and [ELSE]
700 MOV #TIB_LEN,TOS ;2 -- x x len
701 .word 40BFh ; MOV #imm,index(PSP)
702 CIB_ADR .word TIB_ORG ; imm=TIB_ORG
703 .word 0 ;4 -- x org len index=0 ==> MOV #TIB_ORG,0(PSP)
704 MOV @PSP,2(PSP) ;4 -- org org len
705 JMP ACCEPT ;2 org org len -- org len'
707 XDODOES ; -- addr ; 4 for CALL rDODOES S-- BODY PFA R--
709 MOV TOS,0(PSP) ;+3 save TOS on parameters stack
710 MOV @RSP+,TOS ;+2 TOS = PFA address of master word, i.e. address of its first cell after DOES>
711 PUSH IP ;+3 save IP on return stack
712 MOV @TOS+,IP ;+2 IP = CFA of Master word, TOS = BODY address of created word
713 MOV @IP+,PC ;+4 = 19~ = ITC-2
715 XDOCON ; 4 for CALL rDOCON S-- CTE PFA R--
717 MOV TOS,0(PSP) ;+3 save TOS on parameters stack
718 MOV @RSP+,TOS ;+2 TOS = PFA address of master word CONSTANT
719 MOV @TOS,TOS ;+2 TOS = CONSTANT value
720 MOV @IP+,PC ;+4 = 16~ = ITC+4
722 ; https://forth-standard.org/standard/core/Rfrom
723 ; R> -- x R: x -- pop from return stack
725 XDOVAR ; 4 for CALL rDOVAR ADR -- VAR
729 MOV @IP+,PC ;+4 = 14~ = ITC+4
731 ;-----------------------------------;
732 ; PUC 6.1: init Forth engine ; common part of QABORT|WARM
733 ;-----------------------------------;
737 .IFNDEF SD_CARD_LOADER
738 .word RET_ADR ; INI_SOFT_APP default value
740 .word INI_SOFT_SD ; init software SD_Card : close all handles
742 MOV #INI_FORTH_INI,X ; in FRAM INFO
743 MOV @X+,&PFAACCEPT ; BODYACCEPT --> PFAACCEPT
744 MOV @X+,&PFACR ; BODYCR --> PFACR
745 MOV @X+,&PFAEMIT ; BODYEMIT --> PFAEMIT
746 MOV @X+,&PFAKEY ; BODYKEY --> PFAKEY
747 MOV @X+,&CIB_ADR ; TIB_ORG --> CIB_ADR
748 MOV @X+,rDOCOL ; --> rDOCOL
749 MOV @X+,rDODOES ; xDODOES --> rDODOES
750 MOV @X+,rDOCON ; xDOCON --> rDOCON
751 MOV @X+,rDOVAR ; RFROM --> rDOVAR
752 MOV @X+,&CAPS ; 32 --> CAPS init CAPS ON
753 MOV @X+,&BASE ; 10 --> BASE init decimal base
754 MOV @RSP+,IP ; init IP with RET_ADR = LIT|WARM from resp. QABORT|RESET
755 MOV #SEL_P_R_D,PC ; goto PUC 6.2 to select PWR_STATE|RST_STATE|DEEP_RESET
758 .include "forthMSP430FR_TERM_I2C.asm"
761 .include "forthMSP430FR_TERM_HALF.asm"
763 .include "forthMSP430FR_TERM_UART.asm"
766 .IFDEF SD_CARD_LOADER
767 .include "forthMSP430FR_SD_ACCEPT.asm"
770 .IF DTC = 1 ; DOCOL = CALL rDOCOL, [rDOCOL] = xdocol
771 XDOCOL MOV @RSP+,W ; 2
772 PUSH IP ; 3 save old IP on return stack
773 MOV W,IP ; 1 set new IP to PFA
774 MOV @IP+,PC ; 4 = NEXT
778 ;https://forth-standard.org/standard/core/TYPE
779 ;C TYPE adr len -- type string to terminal
781 JZ TWODROP ;2 abort fonction
784 TYPELOOP MOV @PSP,Y ;2 -- adr len Y = adr
785 SUB #2,PSP ;1 -- adr x len
786 MOV TOS,0(PSP) ;3 -- adr len len
787 MOV.B @Y+,TOS ;2 -- adr len char
788 MOV Y,2(PSP) ;3 -- adr+1 len char
789 MOV &PFAEMIT,PC ;5+17 all scratch registers must be and are free
790 TYPE_NEXT .word $+2 ; -- adr+1 len
791 SUB #2,IP ;1 [IP] = TYPE_NEXT
792 SUB #1,TOS ;1 -- adr+1 len-1
793 JNZ TYPELOOP ;2 37~ EMIT loop
794 MOV @RSP+,IP ;3 -- adr+len 0
795 TWODROP ADD #2,PSP ;1 -- 0
796 DROP MOV @PSP+,TOS ;2 --
800 ; https://forth-standard.org/standard/core/CR
801 ; CR -- send CR to the output device
802 CR MOV @PC+,PC ;3 Code Field Address (CFA) of CR
803 PFACR .word BODYCR ; Parameter Field Address (PFA) of CR, with its default value
804 BODYCR mDOCOL ; send CR+LF to the default output device
809 ;-------------------------------------------------------------------------------
811 ;-------------------------------------------------------------------------------
812 .IFDEF CORE_COMPLEMENT
815 ; https://forth-standard.org/standard/core/DUP
816 ; DUP x -- x x duplicate top of stack
817 DUP SUB #2,PSP ; 2 push old TOS..
818 MOV TOS,0(PSP) ; 3 ..onto stack
821 .IFDEF CORE_COMPLEMENT
824 ; https://forth-standard.org/standard/core/qDUP
825 ; ?DUP x -- 0 | x x DUP if nonzero
826 QDUP CMP #0,TOS ; 2 test for TOS nonzero
830 .IFDEF CORE_COMPLEMENT
833 ; https://forth-standard.org/standard/core/TwoDUP
834 ; 2DUP x1 x2 -- x1 x2 x1 x2 dup top 2 cells
835 TWODUP MOV TOS,-2(PSP) ; 3
840 .IFDEF CORE_COMPLEMENT
843 ; https://forth-standard.org/standard/core/SWAP
844 ; SWAP x1 x2 -- x2 x1 swap top two items
850 .IFDEF CORE_COMPLEMENT
852 ; https://forth-standard.org/standard/core/DROP
853 ; DROP x -- drop top of stack
858 ; https://forth-standard.org/standard/core/NIP
859 ; NIP x1 x2 -- x2 Drop the first item below the top of stack
865 ;https://forth-standard.org/standard/core/OVER
866 ;C OVER x1 x2 -- x1 x2 x1
867 MOV TOS,-2(PSP) ; 3 -- x1 (x2) x2
868 MOV @PSP,TOS ; 2 -- x1 (x2) x1
869 SUB #2,PSP ; 1 -- x1 x2 x1
874 ;https://forth-standard.org/standard/core/ROT
875 ;C ROT x1 x2 x3 -- x2 x3 x1
876 MOV @PSP,W ; 2 fetch x2
877 MOV TOS,0(PSP) ; 3 store x3
878 MOV 2(PSP),TOS ; 3 fetch x1
879 MOV W,2(PSP) ; 3 store x2
884 ; https://forth-standard.org/standard/core/DEPTH
885 ; DEPTH -- +n number of items on stack, must leave 0 if stack empty
886 DEPTH MOV TOS,-2(PSP)
888 SUB PSP,TOS ; PSP-S0--> TOS
889 RRA TOS ; TOS/2 --> TOS
890 SUB #2,PSP ; post decrement stack...
893 .IFDEF CORE_COMPLEMENT
895 ;https://forth-standard.org/standard/core/RFetch
896 ;C R@ -- x R: x -- x fetch from rtn stk
903 ; https://forth-standard.org/standard/core/toR
904 ; >R x -- R: -- x push to return stack
910 ; https://forth-standard.org/standard/core/Rfrom
911 ; R> -- x R: x -- pop from return stack
918 ;-------------------------------------------------------------------------------
919 ; ARITHMETIC OPERATIONS
920 ;-------------------------------------------------------------------------------
921 .IFDEF CORE_COMPLEMENT
923 ; https://forth-standard.org/standard/core/OnePlus
924 ; 1+ n1/u1 -- n2/u2 add 1 to TOS
929 ; https://forth-standard.org/standard/core/OneMinus
930 ; 1- n1/u1 -- n2/u2 subtract 1 from TOS
935 ;https://forth-standard.org/standard/core/Plus
936 ;C + n1/u1 n2/u2 -- n3/u3 add n1+n2
942 ; https://forth-standard.org/standard/core/Minus
943 ; - n1/u1 n2/u2 -- n3/u3 n3 = n1-n2
944 MINUS SUB @PSP+,TOS ;2 -- n2-n1
945 NEGATE XOR #-1,TOS ;1
946 ONEPLUS ADD #1,TOS ;1 -- n3 = -(n2-n1) = n1-n2
949 ;-------------------------------------------------------------------------------
951 ;-------------------------------------------------------------------------------
953 ; https://forth-standard.org/standard/core/Fetch
954 ; @ a-addr -- x fetch cell from memory
959 ; https://forth-standard.org/standard/core/Store
960 ; ! x a-addr -- store cell in memory
961 STORE MOV @PSP+,0(TOS);4
965 ;-------------------------------------------------------------------------------
966 ; COMPARAISON OPERATIONS
967 ;-------------------------------------------------------------------------------
968 .IFDEF CORE_COMPLEMENT
971 ; https://forth-standard.org/standard/core/ZeroEqual
972 ; 0= n/u -- flag return true if TOS=0
973 ZEROEQUAL SUB #1,TOS ;1 borrow (clear cy) if TOS was 0
974 SUBC TOS,TOS ;1 TOS=-1 if borrow was set
977 .IFDEF CORE_COMPLEMENT
980 ; https://forth-standard.org/standard/core/Zeroless
981 ; 0< n -- flag true if TOS negative
982 ZEROLESS ADD TOS,TOS ;1 set carry if TOS negative
983 SUBC TOS,TOS ;1 TOS=-1 if carry was clear
984 INVERT XOR #-1,TOS ;1 TOS=-1 if carry was set
987 .IFDEF CORE_COMPLEMENT
990 ; https://forth-standard.org/standard/core/Uless
991 ; U< u1 u2 -- flag test u1<u2, unsigned
992 ULESS SUB @PSP+,TOS ;2
993 JZ ULESSEND ;2 flag Z = 1
994 MOV #-1,TOS ;1 flag Z = 0
995 JC ULESSEND ;2 unsigned jump
996 AND #0,TOS ;1 flag Z = 1
997 ULESSEND MOV @IP+,PC ;4
999 .IFDEF CORE_COMPLEMENT
1001 ; https://forth-standard.org/standard/core/Equal
1002 ; = x1 x2 -- flag test x1=x2
1003 EQUAL SUB @PSP+,TOS ;2
1004 JZ INVERT ;2 flag Z will be = 0
1005 AND #0,TOS ;1 flag Z = 1
1009 ;https://forth-standard.org/standard/core/less
1010 ;C < n1 n2 -- flag test n1<n2, signed
1011 SUB @PSP+,TOS ;1 TOS=n2-n1
1012 JZ LESSEND ;2 flag Z = 1
1013 JL TOSFALSE ;2 signed jump
1014 TOSTRUE MOV #-1,TOS ;1 flag Z = 0
1015 LESSEND MOV @IP+,PC ;4
1018 ;https://forth-standard.org/standard/core/more
1019 ;C > n1 n2 -- flag test n1>n2, signed
1020 SUB @PSP+,TOS ;2 TOS=n2-n1
1021 JL TOSTRUE ;2 --> +5
1022 TOSFALSE AND #0,TOS ;1 flag Z = 1
1025 ;-------------------------------------------------------------------------------
1026 ; CORE ANS94 complement OPTION
1027 ;-------------------------------------------------------------------------------
1028 .include "ADDON/CORE_ANS.asm"
1029 .ENDIF ; CORE_COMPLEMENT
1031 ;-------------------------------------------------------------------------------
1033 ;-------------------------------------------------------------------------------
1034 ; Numeric conversion is done last digit first, so
1035 ; the output buffer is built backwards in memory.
1038 ; https://forth-standard.org/standard/core/num-start
1039 ; <# -- begin numeric conversion (initialize Hold Pointer)
1040 LESSNUM MOV #HOLD_BASE,&HP
1044 ; https://forth-standard.org/standard/core/num
1045 ; # ud1lo ud1hi -- ud2lo ud2hi convert 1 digit of output
1046 NUM MOV &BASE,T ;3 T = Divisor
1047 NUM1 MOV @PSP,S ;2 -- DVDlo DVDhi S = DVDlo
1048 SUB #2,PSP ;1 -- x x DVDhi TOS = DVDhi
1049 CALL #MUSMOD1 ;4 -- REMlo QUOTlo QUOThi T is unchanged
1050 MOV @PSP+,0(PSP) ;4 -- QUOTlo QUOThi
1051 TODIGIT CMP.B #10,W ;2 W = REMlo
1052 JNC TODIGIT1 ;2 jump if U<
1054 TODIGIT1 ADD.B #30h,W ;2
1055 HOLDW SUB #1,&HP ;4 store W=char --> -[HP]
1058 MOV @IP+,PC ;4 23 words
1061 ; https://forth-standard.org/standard/core/numS
1062 ; #S udlo udhi -- 0 0 convert remaining digits
1064 .word NUM ; X=QUOTlo
1065 NUM_RETURN .word $+2 ; next adr
1066 SUB #2,IP ;1 restore NUM return
1067 CMP #0,X ;1 test ud2lo first (generally <>0)
1069 CMP #0,TOS ;1 then test ud2hi (generally =0)
1072 MOV @IP+,PC ;6 10 words, about 241/417 cycles/char
1075 ; https://forth-standard.org/standard/core/num-end
1076 ; #> udlo:udhi -- c-addr u end conversion, get string
1077 NUMGREATER MOV &HP,0(PSP)
1083 ; https://forth-standard.org/standard/core/HOLD
1084 ; HOLD char -- add char to output string
1090 ; https://forth-standard.org/standard/core/SIGN
1091 ; SIGN n -- add minus sign if n<0
1095 JN HOLDW ; jump if 0<
1099 ; https://forth-standard.org/standard/core/Ud
1100 ; U. u -- display u (unsigned)
1101 ; note: DDOT = UDOT + 10
1103 DOTTODDOT SUB #2,PSP ; 1 convert n|u to d|ud with Y = -1|0
1106 DDOT PUSH IP ; paired with EXIT R-- IP
1107 PUSH TOS ; paired with RFROM R-- IP sign
1108 AND #-1,TOS ; clear V, set N
1109 JGE DDOTNEXT ; if positive (N=0)
1114 DDOTNEXT ASMTOFORTH ;10
1116 .word RFROM,SIGN,NUMGREATER,TYPE
1117 .word FBLANK,EMIT,EXIT
1120 ; https://forth-standard.org/standard/core/d
1121 ; . n -- display n (signed)
1127 ; ------------------------------------------------------------------------------
1128 ; STRINGS PROCESSING
1129 ; ------------------------------------------------------------------------------
1130 FORTHWORDIMM "S\34" ; immediate
1131 ; https://forth-standard.org/standard/core/Sq
1132 ; S" -- compile in-line string
1133 SQUOTE MOV #0,&CAPS ; CAPS OFF
1135 .word lit,XSQUOTE,COMMA
1136 SQUOTE1 .word lit,'"' ; separator for WORD
1137 .word WORDD ; -- c-addr (= HERE)
1139 MOV #32,&CAPS ; CAPS ON
1140 MOV.B @TOS,TOS ; -- u
1142 BIT #1,TOS ;1 C = ~Z
1144 DROPEXIT MOV @PSP+,TOS
1148 FORTHWORDIMM ".\34" ; immediate
1149 ; https://forth-standard.org/standard/core/Dotq
1150 ; ." -- compile string to print
1153 .word lit,TYPE,COMMA,EXIT
1155 ;-------------------------------------------------------------------------------
1157 ;-------------------------------------------------------------------------------
1159 ; https://forth-standard.org/standard/core/WORD
1160 ; WORD char -- addr Z=1 if len=0
1161 ; parse a word delimited by char separator; by default (CAPS=$20), this word is capitalized.
1162 ; if first char is TICK, the entire word is not capitalized.
1163 WORDD MOV #SOURCE_LEN,S ;2 -- separator
1164 MOV @S+,X ;2 X = src_len
1165 MOV @S+,W ;2 W = src_org
1166 ADD W,X ;1 X = src_end
1167 ADD @S+,W ;2 W = src_org + >IN = src_ptr
1168 MOV @S,Y ;2 Y = HERE = dst_ptr
1169 SKIPCHARLOO CMP W,X ;1 src_ptr = src_end ?
1170 JZ SKIPCHAREND ;2 if yes : End Of Line !
1171 CMP.B @W+,TOS ;2 does char = separator ?
1172 JZ SKIPCHARLOO ;2 if yes; 7~ loop
1173 SUB #1,W ;1 move back one the (post incremented) pointer
1174 SCANWORD MOV #96,T ;2 T = 96 = ascii(a)-1 (test value set in a register before SCANWORD loop)
1175 MOV &CAPS,rDODOES ;3 CAPS OFF = 0, CAPS ON = $20.
1176 QSCANTICK CMP.B #27h,0(W) ;4 first char = TICK ?
1177 JNZ SCANWORDLOO ;2 no
1178 MOV #0,rDODOES ;1 yes, don't change to upper case
1179 SCANWORDLOO MOV.B S,0(Y) ;3 first time make room in dst for word length; next, put char @ dst.
1180 CMP W,X ;1 src_ptr = src_end ?
1181 JZ SCANWORDEND ;2 if yes
1183 CMP.B S,TOS ;1 does char = separator ?
1184 JZ SCANWORDEND ;2 if yes
1185 ADD #1,Y ;1 increment dst just before test loop
1186 CMP.B S,T ;1 char U< 'a' ? ('a'-1 U>= char) this condition is tested at each loop
1187 JC SCANWORDLOO ;2 15~ upper case char loop
1188 CMP.B #123,S ;2 char U>= 'z'+1 ?
1189 JC SCANWORDLOO ;2 loopback if yes
1190 SUB.B rDODOES,S ;1 convert a...z to A...Z if CAPS ON (rDODOES=$20)
1191 JMP SCANWORDLOO ;2 22~ lower case char loop
1192 SCANWORDEND MOV #XDODOES,rDODOES ;2
1193 SKIPCHAREND SUB &SOURCE_ORG,W ;3 -- separator W=src_ptr - src_org = new >IN (first char separator next)
1194 MOV W,&TOIN ;3 update >IN
1195 MOV &DDP,TOS ;3 -- c-addr
1196 SUB TOS,Y ;1 Y=Word_Length
1198 MOV @IP+,PC ;4 -- c-addr 48 words Z=1 <==> lenght=0 <==> EOL, Z is tested by INTERPRET
1201 ; https://forth-standard.org/standard/core/FIND
1202 ; FIND c-addr -- c-addr 0 if not found ; flag Z=1 c-addr at transient RAM area (HERE)
1203 ; CFA -1 if found ; flag Z=0
1204 ; CFA 1 if immediate ; flag Z=0
1205 ; compare WORD at c-addr (HERE) with each of words in each of listed vocabularies in CONTEXT
1206 ; FIND to WORDLOOP : 14/20 cycles,
1207 ; mismatch word loop: 13 cycles on len, +7 cycles on first char,
1208 ; +10 cycles char loop,
1209 ; VOCLOOP : 12/18 cycles,
1210 ; WORDFOUND to end : 21 cycles.
1211 ; note: with 16 threads vocabularies, FIND takes only! 75% of CORETEST.4th processing time
1212 FIND SUB #2,PSP ;1 -- ???? c-addr reserve one cell, not at FINDEND because kill flag Z
1213 MOV TOS,S ;1 S=c-addr
1214 MOV.B @S,rDOCON ;2 rDOCON= string count
1215 MOV.B #80h,rDODOES ;2 rDODOES= immediate mask
1217 VOCLOOP MOV @T+,TOS ;2 -- ???? VOC_PFA T=CTXT+2
1218 CMP #0,TOS ;1 no more vocabulary in CONTEXT ?
1219 JZ FINDEND ;2 -- ???? 0 yes ==> exit; Z=1
1222 .ELSECASE ; search thread add 6cycles 5words
1223 MOV.B 1(S),Y ;3 -- ???? VOC_PFA0 S=c-addr Y=first char of c-addr string
1224 AND.B #(THREADS-1)*2,Y ;2 -- ???? VOC_PFA0 Y=thread offset
1225 ADD Y,TOS ;1 -- ???? VOC_PFAx TOS = words set entry
1227 ADD #2,TOS ;1 -- ???? VOC_PFA+2
1228 WORDLOOP MOV -2(TOS),TOS ;3 -- ???? NFA [VOC_PFA] first, then [LFA]
1229 CMP #0,TOS ;1 -- ???? NFA no more word in the thread ?
1230 JZ VOCLOOP ;2 -- ???? NFA yes ==> search next voc in context
1232 MOV.B @X+,Y ;2 TOS=NFA,X=NFA+1,Y=NFA_char
1233 BIC.B rDODOES,Y ;1 hide Immediate bit
1234 LENCOMP CMP.B rDOCON,Y ;1 compare lenght
1235 JNZ WORDLOOP ;2 -- ???? NFA 13~ word loop on lenght mismatch
1237 CHARCOMP CMP.B @X+,1(W) ;4 compare chars
1238 JNZ WORDLOOP ;2 -- ???? NFA 20~ word loop on first char mismatch
1240 SUB.B #1,Y ;1 decr count
1241 JNZ CHARCOMP ;2 -- ???? NFA 10~ char loop
1243 WORDFOUND BIT #1,X ;1
1245 MOV X,S ;1 S=aligned CFA
1246 CMP.B #0,0(TOS) ;3 -- ???? NFA 0(TOS)=NFA_first_char
1247 MOV #1,TOS ;1 -- ???? 1 preset immediate flag
1248 JN FINDEND ;2 -- ???? 1 jump if negative: NFA have immediate bit set
1249 SUB #2,TOS ;1 -- ???? -1
1250 FINDEND MOV S,0(PSP) ;3 not found: -- c-addr 0 flag Z=1
1251 MOV #xdocon,rDOCON ;2 found: -- xt -1|+1 (not immediate|immediate) flag Z=0
1252 MOV #xdodoes,rDODOES ;2
1253 MOV @IP+,PC ;4 42/47 words
1255 .IFDEF MPY_32 ; if 32 bits hardware multiplier
1258 ; >NUMBER ud1lo ud1hi addr1 cnt1 -- ud2lo ud2hi addr2 cnt2
1259 ; https://forth-standard.org/standard/core/toNUMBER
1260 ; ud2 is the unsigned result of converting the characters within the string specified by c-addr1 u1 into digits,
1261 ; using the number in BASE, and adding each into ud1 after multiplying ud1 by the number in BASE.
1262 ; Conversion continues left-to-right until a character that is not convertible (including '.' ',' '_')
1263 ; is encountered or the string is entirely converted. c-addr2 is the location of the first unconverted character
1264 ; or the first character past the end of the string if the string was entirely converted.
1265 ; u2 is the number of unconverted characters in the string.
1266 ; An ambiguous condition exists if ud2 overflows during the conversion.
1267 TONUMBER MOV @PSP+,S ;2 -- ud1lo ud1hi cnt1 S = addr1
1268 MOV @PSP+,Y ;2 -- ud1lo cnt1 Y = ud1hi
1269 MOV @PSP,X ;2 -- x cnt1 X = ud1lo
1270 SUB #4,PSP ;1 -- x x x cnt
1272 TONUMLOOP MOV.B @S,W ;2 -- x x x cnt S=adr, T=base, W=char, X=udlo, Y=udhi
1273 DDIGITQ SUB.B #30h,W ;2 skip all chars < '0'
1274 CMP.B #10,W ;2 char was U< 58 (U< ':') ?
1275 JNC DDIGITQNEXT ;2 no
1278 JNC TONUMEND ;2 -- x x x cnt if '9' < char < 'A', then return to QNUMBER with Z=0
1279 DDIGITQNEXT CMP T,W ;1 digit-base
1280 BIC #Z,SR ;1 reset Z before return to QNUMBER because
1281 JC TONUMEND ;2 with Z=1, QNUMBER conversion would be true :-(
1282 UDSTAR MOV X,&MPY32L ;3 Load 1st operand (ud1lo)
1283 MOV Y,&MPY32H ;3 Load 1st operand (ud1hi)
1284 MOV T,&OP2 ;3 Load 2nd operand with BASE
1285 MOV &RES0,X ;3 lo result in X (ud2lo)
1286 MOV &RES1,Y ;3 hi result in Y (ud2hi)
1287 MPLUS ADD W,X ;1 ud2lo + digit
1288 ADDC #0,Y ;1 ud2hi + carry
1289 TONUMPLUS ADD #1,S ;1 adr+1
1290 SUB #1,TOS ;1 -- x x x cnt cnt-1
1291 JNZ TONUMLOOP ;2 if count <>0
1292 TONUMEND MOV S,0(PSP) ;3 -- x x addr2 cnt2
1293 MOV Y,2(PSP) ;3 -- x ud2hi addr2 cnt2
1294 MOV X,4(PSP) ;3 -- ud2lo ud2hi addr2 cnt2
1295 MOV @IP+,PC ;4 42 words
1297 ; ?NUMBER makes the interface between INTERPRET and >NUMBER; it's a subset of INTERPRET.
1298 ; convert a string to a signed number; FORTH 2012 prefixes $ % # are recognized,
1299 ; FORTH 2012 'char' numbers also, digits separator '_' also.
1300 ; with DOUBLE_INPUT switched ON, 32 bits signed numbers (with decimal point) are recognized,
1301 ; with FIXPOINT_INPUT switched ON, Q15.16 signed numbers (with comma) are recognized.
1302 ; prefixes ' # % $ - are processed before calling >NUMBER
1303 ; chars . , _ are processed as >NUMBER exits.
1304 ;Z ?NUMBER addr -- n|d -1 if convert ok ; flag Z=0, UF9=1 if double
1305 ;Z addr -- addr 0 if convert ko ; flag Z=1
1307 .IFDEF DOUBLE_NUMBERS ; DOUBLE_NUMBERS = DOUBLE_INPUT | FIXPOINT_INPUT
1308 BIC #UF9,SR ;2 reset UF9 used as double number flag
1310 MOV &BASE,T ;3 T=BASE
1311 MOV #0,S ;1 S=sign of result
1312 PUSHM #3,IP ;5 R-- IP sign base PUSH IP,S,T
1313 MOV #TONUMEXIT,IP ;2 set TONUMEXIT as return from >NUMBER
1316 SUB #8,PSP ;1 -- x x x x addr make room for TOS and >NUMBER
1317 MOV TOS,6(PSP) ;3 -- addr x x x addr
1319 MOV.B @S+,TOS ;2 -- addr x x x cnt TOS=count
1320 QTICK CMP.B #027h,0(S) ;4 prefix = ' ?
1321 JNZ QNUMLDCHAR ;2 no
1323 MOV S,4(PSP) ;3 -- addr ud2lo x x cnt ud2lo = ASCII code of 'char'
1324 CMP.B #3,TOS ;2 string must be 3 chars long
1326 QNUMLDCHAR MOV.B @S,W ;2 W=char
1327 QMINUS SUB.B #'-',W ;2 sign minus ?
1328 JNC QBINARY ;2 jump if char < '-'
1329 JNZ TONUMLOOP ;2 -- addr x x x cnt jump if char > '-'
1330 MOV #-1,2(RSP) ;3 R-- IP sign base set sign flag
1332 QBINARY MOV #2,T ;1 preset base 2
1333 ADD.B #8,W ;1 binary '%' prefix ?
1335 QDECIMAL ADD #8,T ;1 preset base 10
1336 ADD.B #2,W ;1 decimal '#' prefix ?
1338 QHEXA MOV #16,T ;2 preset base 16
1339 ADD.B #-1,W ;1 hex '$' prefix ?
1340 JNZ QNUMNEXT ;2 -- addr x x x cnt abort if not recognized prefix
1341 PREFIXED ADD #1,S ;1
1342 SUB #1,TOS ;1 -- addr x x x cnt-1 S=adr+1 TOS=count-1
1344 ; ----------------------------------;
1346 TONUMEXIT .word $+2 ; -- addr ud2lo-hi addr2 cnt2 R-- IP sign BASE S=addr2
1347 ; ----------------------------------;
1348 JZ QNUMNEXT ;2 TOS=cnt2, Z=1 if conversion is ok
1349 ; ----------------------------------;
1350 SUB #2,IP ; redefines TONUMEXIT as >NUMBER return, if loopback applicable
1351 CMP.B #28h,W ; rejected char by >NUMBER is a underscore ? ('_'-30h-7 = 28h)
1352 JZ TONUMPLUS ; yes: loopback to >NUMBER to skip char
1353 ; ----------------------------------;
1354 .IFDEF DOUBLE_NUMBERS ; DOUBLE_NUMBERS = DOUBLE_INPUT | FIXPOINT_INPUT
1355 BIT #UF9,SR ; UF9 already set ? ( when you have typed .. )
1356 JNZ QNUMNEXT ; yes, goto QNUMKO
1357 BIS #UF9,SR ;2 set double number flag
1359 ; ----------------------------------;
1360 .IFDEF DOUBLE_INPUT ;
1361 CMP.B #0F7h,W ;2 rejected char by >NUMBER is a decimal point ? ('.'-37h = -9)
1362 JZ TONUMPLUS ;2 yes, loopback to >NUMBER to skip char
1364 ; ----------------------------------;
1365 .IFDEF FIXPOINT_INPUT ;
1366 CMP.B #0F5h,W ;2 rejected char by >NUMBER is a comma ? (','-37h = -0Bh)
1367 JNZ QNUMNEXT ;2 no: with Z=0 ==> goto QNUMKO
1368 ; ----------------------------------;
1369 S15Q16 MOV TOS,W ;1 -- addr ud2lo x x x W=cnt2
1370 MOV #0,X ;1 -- addr ud2lo x 0 x init X = ud2lo' = 0
1371 S15Q16LOOP MOV X,2(PSP) ;3 -- addr ud2lo ud2lo' ud2lo' x 0(PSP) = ud2lo'
1372 SUB.B #1,W ;1 decrement cnt2
1373 MOV W,X ;1 X = cnt2-1
1374 ADD S,X ;1 X = end_of_string-1,-2,-3...
1375 MOV.B @X,X ;2 X = last char of string first (reverse conversion)
1376 SUB.B #30h,X ;2 char --> digit conversion
1378 JNC QS15Q16DIGI ;2 if 0 <= digit < 10
1380 CMP.B #10,X ;2 to skip all chars between "9" and "A"
1382 QS15Q16DIGI CMP T,X ;1 R-- IP sign BASE is X a digit ?
1383 JC S15Q16EOC ;2 -- addr ud2lo ud2lo' x ud2lo' if X>=base
1384 MOV X,0(PSP) ;3 -- addr ud2lo ud2lo' digit x
1385 MOV T,TOS ;1 -- addr ud2lo ud2lo' digit base R-- IP sign base
1386 PUSHM #3,S ;5 PUSH S,T,W: R-- IP sign base addr2 base cnt2
1387 CALL #MUSMOD ;4 -- addr ud2lo ur uqlo uqhi CALL MU/MOD
1388 POPM #3,S ;5 restore W,T,S: R-- IP sign BASE
1389 JMP S15Q16LOOP ;2 W=cnt
1390 S15Q16EOC MOV 4(PSP),2(PSP) ;5 -- addr ud2lo ud2hi uqlo x ud2lo from >NUMBER becomes here ud2hi part of Q15.16
1391 MOV @PSP,4(PSP) ;4 -- addr ud2lo ud2hi x x uqlo becomes ud2lo part of Q15.16
1392 CMP.B #0,W ;1 count = 0 if end of conversion ok
1393 .ENDIF ; FIXPOINT_INPUT ;
1394 ; ----------------------------------;
1395 QNUMNEXT POPM #3,IP ;5 -- addr ud2lo-hi x x POPM T,S,IP S = sign flag = {-1;0}
1396 MOV S,TOS ;1 -- addr ud2lo-hi x sign
1398 JZ QNUMOK ;2 -- addr ud2lo-hi x sign conversion OK if Z=1
1400 .IFDEF DOUBLE_NUMBERS ;
1401 BIC #UF9,SR ;2 reset flag UF9, before next use as double number flag
1403 ADD #6,PSP ;1 -- addr sign
1404 AND #0,TOS ;1 -- addr ff TOS=0 and Z=1 ==> conversion ko
1406 ; ----------------------------------;
1407 .IFDEF DOUBLE_NUMBERS ; -- addr ud2lo-hi x sign
1408 QNUMOK ADD #2,PSP ;1 -- addr ud2lo-hi sign
1409 MOV 2(PSP),4(PSP) ;5 -- udlo udlo udhi sign
1410 MOV @PSP+,0(PSP) ;4 -- udlo udhi sign note : PSP is incremented before write back.
1411 XOR #-1,TOS ;1 -- udlo udhi inv(sign)
1412 JNZ QDOUBLE ;2 if jump : TOS=-1 and Z=0 ==> conversion ok
1413 XOR #-1,TOS ;1 -- udlo udhi tf
1414 QDNEGATE XOR #-1,2(PSP) ;3
1415 XOR #-1,0(PSP) ;3 -- (dlo dhi)-1 tf
1418 QDOUBLE BIT #UF9,SR ;2 -- dlo dhi tf decimal point or comma fixpoint ?
1419 JNZ QNUMEND ;2 leave double
1420 ADD #2,PSP ;1 -- n tf leave number
1421 QNUMEND MOV @IP+,PC ;4 TOS<>0 and Z=0 ==> conversion ok
1423 QNUMOK ADD #4,PSP ;1 -- addr ud2lo sign
1424 MOV @PSP+,0(PSP) ;4 -- udlo sign note : PSP is incremented before write back !!!
1425 XOR #-1,TOS ;1 -- udlo inv(sign)
1426 JNZ QNUMEND ;2 if jump : TOS=-1 and Z=0 ==> conversion ok
1427 XOR #-1,TOS ;1 -- udlo tf TOS=-1 and Z=0
1428 QNEGATE XOR #-1,0(PSP) ;3
1429 ADD #1,0(PSP) ;3 -- n tf
1430 QNUMEND MOV @IP+,PC ;4 TOS=-1 and Z=0 ==> conversion ok
1431 .ENDIF ; DOUBLE_NUMBERS ;
1433 .ELSE ; no hardware MPY
1436 ; T.I. UNSIGNED MULTIPLY SUBROUTINE: U1 x U2 -> Ud
1437 ; https://forth-standard.org/standard/core/UMTimes
1438 ; UM* u1 u2 -- ud unsigned 16x16->32 mult.
1439 UMSTAR MOV @PSP,S ;2 MDlo
1440 UMSTAR1 MOV #0,T ;1 MDhi=0
1443 MOV #1,W ;1 BIT TEST REGISTER
1444 UMSTARLOOP BIT W,TOS ;1 TEST ACTUAL BIT MRlo
1445 JZ UMSTARNEXT ;2 IF 0: DO NOTHING
1446 ADD S,X ;1 IF 1: ADD MDlo TO RES0
1447 ADDC T,Y ;1 ADDC MDhi TO RES1
1448 UMSTARNEXT ADD S,S ;1 (RLA LSBs) MDlo x 2
1449 ADDC T,T ;1 (RLC MSBs) MDhi x 2
1450 ADD W,W ;1 (RLA) NEXT BIT TO TEST
1451 JNC UMSTARLOOP ;2 IF BIT IN CARRY: FINISHED 10~ loop
1452 MOV X,0(PSP) ;3 low result on stack
1453 MOV Y,TOS ;1 high result in TOS
1454 MOV @IP+,PC ;4 17 words
1457 ; https://forth-standard.org/standard/core/toNUMBER
1458 ; ud2 is the unsigned result of converting the characters within the string specified by c-addr1 u1 into digits,
1459 ; using the number in BASE, and adding each into ud1 after multiplying ud1 by the number in BASE.
1460 ; Conversion continues left-to-right until a character that is not convertible, including '.', ',' or '_',
1461 ; is encountered or the string is entirely converted. c-addr2 is the location of the first unconverted character
1462 ; or the first character past the end of the string if the string was entirely converted.
1463 ; u2 is the number of unconverted characters in the string.
1464 ; An ambiguous condition exists if ud2 overflows during the conversion.
1465 ; >NUMBER ud1lo|ud1hi addr1 count1 -- ud2lo|ud2hi addr2 count2
1466 TONUMBER MOV @PSP,S ;2 S=adr
1467 MOV TOS,T ;1 T=count
1469 TONUMLOOP MOV.B @S,Y ;2 -- ud1lo ud1hi x x S=adr, T=count, W=BASE, Y=char
1470 DDIGITQ SUB.B #30h,Y ;2 skip all chars < '0'
1471 CMP.B #10,Y ;2 char was > "9" ?
1472 JNC DDIGITQNEXT ;2 -- ud1lo ud1hi x x no: good end
1473 SUB.B #07,Y ;2 skip all chars between "9" and "A"
1474 CMP.B #10,Y ;2 char was < "A" ?
1475 JNC TONUMEND ;2 yes: for bad end
1476 DDIGITQNEXT CMP W,Y ;1 -- ud1lo ud1hi x x digit-base
1477 BIC #Z,SR ;1 reset Z before jmp TONUMEND because...
1478 JC TONUMEND ;2 ...QNUMBER conversion will be true if Z = 1 :-(
1479 UDSTAR PUSHM #6,IP ;8 -- ud1lo ud1hi x x save IP S T W X Y used by UM* r-- IP adr count base x digit
1480 MOV 2(PSP),S ;3 -- ud1lo ud1hi x x S=ud1hi
1481 MOV W,TOS ;1 -- ud1lo ud1hi x base
1482 MOV #UMSTARNEXT1,IP ;2
1483 UMSTARONE JMP UMSTAR1 ;2 ud1hi * base -- x ud3hi X=ud3lo
1484 UMSTARNEXT1 .word $+2 ; -- ud1lo ud1hi x ud3hi
1485 MOV X,2(RSP) ;3 r-- IP adr count base ud3lo digit
1486 MOV 4(PSP),S ;3 -- ud1lo ud1hi x ud3hi S=ud1lo
1487 MOV 4(RSP),TOS ;3 -- ud1lo ud1hi x base
1488 MOV #UMSTARNEXT2,IP ;2
1489 UMSTARTWO JMP UMSTAR1 ;2 -- ud1lo ud1hi x ud4hi X=ud4lo
1490 UMSTARNEXT2 .word $+2 ; -- ud1lo ud1hi x ud4hi
1491 MPLUS ADD @RSP+,X ;2 -- ud1lo ud1hi x ud4hi X=ud4lo+digit=ud2lo r-- IP adr count base ud3lo
1492 ADDC @RSP+,TOS ;2 -- ud1lo ud1hi x ud2hi TOS=ud4hi+ud3lo+carry=ud2hi r-- IP adr count base
1493 MOV X,4(PSP) ;3 -- ud2lo ud1hi x ud2hi
1494 MOV TOS,2(PSP) ;3 -- ud2lo ud2hi x x r-- IP adr count base
1495 POPM #4,IP ;6 -- ud2lo ud2hi x x W=base, T=count, S=adr, IP=prevIP r--
1496 TONUMPLUS ADD #1,S ;1
1498 JNZ TONUMLOOP ;2 -- ud2lo ud2hi x x S=adr+1, T=count-1, W=base 68 cycles char loop
1499 TONUMEND MOV S,0(PSP) ;3 -- ud2lo ud2hi adr2 count2
1500 MOV T,TOS ;1 -- ud2lo ud2hi adr2 count2
1501 MOV @IP+,PC ;4 50/82 words/cycles, W = BASE
1503 ; ?NUMBER makes the interface between >NUMBER and INTERPRET; it's a subset of INTERPRET.
1504 ; convert a string to a signed number; FORTH 2012 prefixes ' $, %, # are recognized
1505 ; digits separator '_' also.
1506 ; with DOUBLE_INPUT switched ON, 32 bits signed numbers (with decimal point) are recognized
1507 ; with FIXPOINT_INPUT switched ON, Q15.16 signed numbers (with comma) are recognized.
1508 ; prefixes ' # % $ - are processed before calling >NUMBER
1509 ; chars . , _ are processed as >NUMBER exits
1510 ;Z ?NUMBER addr -- n|d -1 if convert ok ; flag Z=0, UF9=1 if double
1511 ;Z addr -- addr 0 if convert ko ; flag Z=1
1513 .IFDEF DOUBLE_NUMBERS ; DOUBLE_NUMBERS = DOUBLE_INPUT | FIXPOINT_INPUT
1514 BIC #UF9,SR ;2 reset flag UF9, before use as double number flag
1516 MOV &BASE,T ;3 T=BASE
1518 PUSHM #3,IP ;5 R-- IP sign base (push IP,S,T)
1519 MOV #TONUMEXIT,IP ;2 define >NUMBER return
1521 SUB #8,PSP ;1 -- x x x x addr
1522 MOV TOS,6(PSP) ;3 -- addr x x x addr
1524 MOV #0,2(PSP) ;3 -- addr 0 0 x addr
1525 MOV TOS,S ;1 -- addr ud=0 x x
1526 MOV.B @S+,T ;2 S=addr, T=count
1527 QTICK CMP.B #27h,0(S) ;4 prefix = ' ?
1528 JNZ QNUMLDCHAR ;2 no
1529 MOV.B 1(S),4(PSP) ;5 -- addr ud2lo 0 x x ud2lo = ASCII code of 'char'
1530 CMP.B #3,TOS ;2 string must be 3 chars long
1532 QNUMLDCHAR MOV.B @S,Y ;2 Y=char
1533 QMINUS SUB.B #'-',Y ;2 -- addr ud=0 x x sign minus ?
1534 JNC QBINARY ;2 if char U< '-'
1535 JNZ TONUMLOOP ;2 if char U> '-'
1536 MOV #-1,2(RSP) ;3 R-- IP sign base
1538 QBINARY MOV #2,W ;1 preset base 2
1539 ADD.B #8,Y ;1 binary prefix ?
1541 QDECIMAL ADD #8,W ;1 preset base 10
1542 ADD.B #2,Y ;1 decimal prefix ?
1544 QHEXA MOV #16,W ;1 preset base 16
1545 ADD.B #-1,Y ;2 hex prefix ?
1546 JNZ QNUMNEXT ;2 -- addr x x x cnt abort if not recognized prefix
1547 PREFIXED ADD #1,S ;1
1548 SUB #1,T ;1 S=adr+1 T=count-1
1550 ; ----------------------------------;42
1552 TONUMEXIT .word $+2 ; -- addr ud2lo-hi addr2 cnt2 R-- IP sign BASE S=addr2,T=cnt2
1553 ; ----------------------------------;
1554 JZ QNUMNEXT ;2 if conversion is ok
1555 ; ----------------------------------;
1557 CMP.B #28h,Y ; rejected char by >NUMBER is a underscore ?
1558 JZ TONUMPLUS ; yes: loopback to >NUMBER to skip char
1559 .IFDEF DOUBLE_NUMBERS ; DOUBLE_NUMBERS = DOUBLE_INPUT | FIXPOINT_INPUT
1560 BIT #UF9,SR ; UF9 already set ? (you have wrongly typed two points)
1561 JNZ QNUMNEXT ; yes, goto QNUMKO
1562 BIS #UF9,SR ;2 set double number flag
1565 CMP.B #0F7h,Y ;2 rejected char by >NUMBER is a decimal point ?
1566 JZ TONUMPLUS ;2 to terminate conversion
1568 .IFDEF FIXPOINT_INPUT ;
1569 CMP.B #0F5h,Y ;2 rejected char by >NUMBER is a comma ?
1570 JNZ QNUMNEXT ;2 no, goto QNUMKO
1571 ; ----------------------------------;
1572 S15Q16 MOV #0,X ;1 -- addr ud2lo x 0 x init ud2lo' = 0
1573 S15Q16LOOP MOV X,2(PSP) ;3 -- addr ud2lo ud2lo' ud2lo' x X = 0(PSP) = ud2lo'
1574 SUB.B #1,T ;1 decrement cnt2
1575 MOV T,X ;1 X = cnt2-1
1576 ADD S,X ;1 X = end_of_string-1, first...
1577 MOV.B @X,X ;2 X = last char of string, first...
1578 SUB.B #30h,X ;2 char --> digit conversion
1584 QS15Q16DIGI CMP W,X ;1 R-- IP sign BASE, W=BASE, is X a digit ?
1585 JC S15Q16EOC ;2 -- addr ud2lo ud2lo' x ud2lo' if no
1586 MOV X,0(PSP) ;3 -- addr ud2lo ud2lo' digit x
1587 MOV W,TOS ;1 -- addr ud2lo ud2lo' digit base R-- IP sign base
1588 PUSHM #3,S ;5 PUSH S,T,W: R-- IP sign base addr2 cnt2 base
1589 CALL #MUSMOD ;4 -- addr ud2lo ur uqlo uqhi
1590 POPM #3,S ;5 restore W,T,S: R-- IP sign BASE
1591 JMP S15Q16LOOP ;2 W=cnt
1592 S15Q16EOC MOV 4(PSP),2(PSP) ;5 -- addr ud2lo ud2lo uqlo x ud2lo from >NUMBER part1 becomes here ud2hi=S15 part2
1593 MOV @PSP,4(PSP) ;4 -- addr ud2lo ud2hi x x uqlo becomes ud2lo
1594 CMP.B #0,T ;1 cnt2 = 0 if end of conversion ok
1595 .ENDIF ; FIXPOINT_INPUT ;
1596 ; ----------------------------------;97
1597 QNUMNEXT POPM #3,IP ;4 -- addr ud2lo-hi x cnt2 POPM T,S,IP S = sign flag = {-1;0}
1598 MOV S,TOS ;1 -- addr ud2lo-hi x sign
1600 JZ QNUMOK ;2 -- addr ud2lo-hi x sign flag Z=1: conversion OK
1602 .IFDEF DOUBLE_NUMBERS
1605 ADD #6,PSP ;1 -- addr sign
1606 AND #0,TOS ;1 -- addr ff TOS=0 and Z=1 ==> conversion ko
1608 ; ----------------------------------;
1609 .IFDEF DOUBLE_NUMBERS
1610 QNUMOK ADD #2,PSP ;1 -- addr ud2lo ud2hi sign
1611 MOV 2(PSP),4(PSP) ; -- udlo udlo udhi sign
1612 MOV @PSP+,0(PSP) ;4 -- udlo udhi sign note : PSP is incremented before write back !!!
1613 XOR #-1,TOS ;1 -- udlo udhi inv(sign)
1614 JNZ QDOUBLE ;2 if jump : TOS=-1 and Z=0 ==> conversion ok
1615 XOR #-1,TOS ;1 -- udlo udhi tf
1616 Q2NEGATE XOR #-1,2(PSP) ;3
1619 ADDC #0,0(PSP) ;3 -- dlo dhi tf
1620 QDOUBLE BIT #UF9,SR ;2 -- dlo dhi tf decimal point added ?
1621 JNZ QNUMEND ;2 -- dlo dhi tf leave double
1622 ADD #2,PSP ;1 -- dlo tf leave number, Z=0
1623 QNUMEND MOV @IP+,PC ;4 TOS=-1 and Z=0 ==> conversion ok
1625 QNUMOK ADD #4,PSP ;1 -- addr ud2lo sign
1626 MOV @PSP+,0(PSP) ;4 -- udlo sign note : PSP is incremented before write back !!!
1627 XOR #-1,TOS ;1 -- udlo inv(sign)
1628 JNZ QNUMEND ;2 if jump : TOS=-1 and Z=0 ==> conversion ok
1629 XOR #-1,TOS ;1 -- udlo tf TOS=-1 and Z=0
1630 QNEGATE XOR #-1,0(PSP) ;3
1631 ADD #1,0(PSP) ;3 -- n tf
1632 QNUMEND MOV @IP+,PC ;4 TOS=-1 and Z=0 ==> conversion ok
1633 .ENDIF ; DOUBLE_NUMBERS
1635 .ENDIF ; of Hardware/Software MPY
1637 ;-------------------------------------------------------------------------------
1638 ; DICTIONARY MANAGEMENT
1639 ;-------------------------------------------------------------------------------
1641 ; https://forth-standard.org/standard/core/Comma
1642 ; , x -- append cell to dict
1649 .IFDEF CORE_COMPLEMENT
1651 ; https://forth-standard.org/standard/core/EXECUTE
1652 ; EXECUTE i*x xt -- j*x execute Forth word at 'xt'
1656 FORTHWORDIMM "LITERAL" ; immediate
1657 ; https://forth-standard.org/standard/core/LITERAL
1658 ; LITERAL n -- append single numeric literal if compiling state
1659 ; d -- append two numeric literals if compiling state and UF9<>0 (not ANS)
1660 .IFDEF DOUBLE_NUMBERS ; are recognized
1661 LITERAL CMP #0,&STATE ;3
1662 JZ LITERAL2 ;2 if interpreting state, clear UF9 flag then NEXT
1664 LITERAL1 MOV &DDP,W ;3 X = n|HId
1669 BIT #UF9,SR ;2 double number ?
1670 LITERAL2 BIC #UF9,SR ;2 in all case, clear UF9
1674 LITERALEND MOV @IP+,PC ;4
1676 LITERAL CMP #0,&STATE ;3
1677 JZ LITERALEND ;2 if interpreting state, do nothing
1678 LITERAL1 MOV &DDP,W ;3
1683 LITERALEND MOV @IP+,PC ;4
1687 ; https://forth-standard.org/standard/core/COUNT
1688 ; COUNT c-addr1 -- adr len counted->adr/len
1692 MOV.B -1(TOS),TOS ;3
1695 FORTHWORD "INTERPRET"
1696 ; INTERPRET i*x addr u -- j*x interpret given buffer
1697 ; This is the common factor of EVALUATE and QUIT.
1698 ; set addr u as input buffer then parse it word by word
1701 INTLOOP .word FBLANK,WORDD ; -- c-addr Z = 1 --> End Of Line
1703 JZ DROPEXIT ;2 Z = 1 --> EOL reached
1704 MOV #INTFINDNEXT,IP ;2 define INTFINDNEXT as FIND return
1706 INTFINDNEXT .word $+2 ; -- c-addr fl Z = 1 -->not found
1707 MOV TOS,W ; W = flag =(-1|0|+1) as (normal|not_found|immediate)
1708 MOV @PSP+,TOS ; -- c-addr
1709 MOV #INTQNUMNEXT,IP ;2 define QNUMBER return
1710 JZ QNUMBER ;2 Z = 1 --> not found, search a number
1711 MOV #INTLOOP,IP ;2 define (EXECUTE | COMMA) return
1713 JZ COMMA ;2 if W xor STATE = 0 compile xt then loop back to INTLOOP
1716 MOV @RSP+,PC ;4 xt --> PC
1718 INTQNUMNEXT .word $+2 ; -- n|c-addr fl Z = 1 --> not a number, SR(UF9) double number request
1720 MOV #INTLOOP,IP ;2 -- n|c-addr define LITERAL return
1721 JNZ LITERAL ;2 n -- Z = 0 --> is a number, execute LITERAL then loop back to INTLOOP
1723 NotFoundexe ADD.B #1,0(TOS) ;3 c-addr -- Z = 1 --> Not a Number : incr string count to add '?'
1724 MOV.B @TOS,Y ;2 Y=count+1
1725 ADD TOS,Y ;1 Y=end of string addr
1726 MOV.B #'?',0(Y) ;5 add '?' to end of string
1727 MOV #FABORT_TERM,IP ;2 define the return of COUNT
1728 JMP COUNT ;2 -- addr len 35 words
1729 NotFound .word NotFoundExe ;
1731 .IFDEF CORE_COMPLEMENT
1732 FORTHWORD "EVALUATE"
1733 ; https://forth-standard.org/standard/core/EVALUATE
1734 ; EVALUATE \ i*x c-addr u -- j*x interpret string
1735 EVALUATE MOV #SOURCE_LEN,X ;2
1736 MOV @X+,S ;2 S = SOURCE_LEN
1737 MOV @X+,T ;2 T = SOURCE_ORG
1738 MOV @X+,W ;2 W = TOIN
1739 PUSHM #4,IP ;6 PUSHM IP,S,T,W
1744 MOV @RSP+,&SOURCE_ORG ;4
1745 MOV @RSP+,&SOURCE_LEN ;4
1750 ; https://forth-standard.org/standard/core/BL
1751 ; BL -- char an ASCII space
1752 .ENDIF ; CORE_COMPLEMENT
1757 ; https://forth-standard.org/standard/core/ALLOT
1758 ; ALLOT n -- allocate n bytes
1764 ; https://forth-standard.org/standard/core/ABORT
1765 ; Empty the data stack and perform the function of QUIT,
1766 ; which includes emptying the return stack, without displaying a message.
1767 ; ABORT is the common next of WARM and ABORT"
1768 ABORT MOV #PSTACK,PSP ;
1769 MOV #0,TOS ; to reset first PSP cell (TOS), used next by WARM
1770 ; https://forth-standard.org/standard/core/QUIT
1771 ; QUIT -- interpret line by line the input stream
1772 QUIT MOV #RSTACK,RSP ;
1773 MOV #LSTACK,&LEAVEPTR ;
1777 QUIT1 .word XSQUOTE ; background interpret loop
1778 .byte 5,13,10,"ok " ; CR+LF + Forth prompt
1779 QUIT2 .word TYPE ; display it
1783 QUIT3 .word REFILL ; -- org len refill input buffer from ACCEPT (one line)
1784 QUIT4 .word INTERPRET ; interpret this line|string
1785 .word DEPTH,ZEROLESS ; stack empty test
1786 .word XSQUOTE ; ABORT" stack empty! "
1787 .byte 12,"stack empty!" ;
1788 .word QABORT ; see QABORT in forthMSP430FR_TERM_xxx.asm
1789 .word lit,FRAM_FULL ;
1790 .word HERE,ULESS ; FRAM full test
1791 .word XSQUOTE ; ABORT" FRAM full! "
1792 .byte 10,"FRAM full!" ;
1793 .word QABORT ; see QABORT in forthMSP430FR_TERM_xxx.asm
1795 .word LIT,STATE,FETCH ; STATE @
1796 .word QFBRAN,QUIT1 ; 0= case of interpretion state
1797 .word XSQUOTE ; 0<> case of compilation state
1798 .byte 5,13,10," " ; CR+LF + 3 spaces
1802 FORTHWORDIMM "ABORT\34" ; immediate
1803 ; https://forth-standard.org/standard/core/ABORTq
1804 ; ABORT" i*x flag -- i*x R: j*x -- j*x flag=0
1805 ; i*x flag -- R: j*x -- flag<>0
1806 ; ABORT" " (empty string) displays nothing
1809 .word lit,QABORT,COMMA ; see QABORT in forthMSP430FR_TERM_xxx.asm
1812 ;-------------------------------------------------------------------------------
1814 ;-------------------------------------------------------------------------------
1816 ; https://forth-standard.org/standard/core/Tick
1817 ; ' -- xt find word in dictionary and leave on stack its execution address
1819 .word FBLANK,WORDD,FIND
1820 .word QFBRAN,NotFound ; see INTERPRET
1823 FORTHWORDIMM "[']" ; immediate word, i.e. word executed during compilation
1824 ; https://forth-standard.org/standard/core/BracketTick
1825 ; ['] <name> -- find word & compile it as literal
1827 .word TICK ; get xt of <name>
1828 .word lit,lit,COMMA ; append LIT action
1829 .word COMMA,EXIT ; append xt literal
1831 FORTHWORDIMM "[" ; immediate
1832 ; https://forth-standard.org/standard/core/Bracket
1833 ; [ -- enter interpretative state
1839 ; https://forth-standard.org/standard/core/right-bracket
1840 ; ] -- enter compiling state
1845 FORTHWORDIMM "\\" ; immediate
1846 ; https://forth-standard.org/standard/block/bs
1848 ; everything up to the end of the current line is a comment.
1849 BACKSLASH MOV &SOURCE_LEN,&TOIN ;
1852 FORTHWORDIMM "POSTPONE"
1853 ; https://forth-standard.org/standard/core/POSTPONE
1855 .word FBLANK,WORDD,FIND,QDUP
1856 .word QFBRAN,NotFound ; see INTERPRET
1857 .word ZEROLESS ; immediate word ?
1858 .word QFBRAN,POST1 ; if immediate
1859 .word lit,lit,COMMA ; else compile lit
1860 .word COMMA ; compile xt
1861 .word lit,COMMA ; CFA of COMMA
1862 POST1 .word COMMA,EXIT ; then compile: if immediate xt of word found else CFA of COMMA
1865 ; https://forth-standard.org/standard/core/Colon
1866 ; : <name> -- begin a colon definition
1867 ; HEADER is CALLed by all compiling words
1868 COLON PUSH #COLONNEXT ;3 define COLONNEXT as HEADER return
1869 ;-----------------------------------;
1870 HEADER BIT #1,&DDP ;3 carry set if odd
1871 ADDC #2,&DDP ;4 (DP+2|DP+3) bytes, make room for LFA
1873 .word FBLANK,WORDD ;
1874 .word $+2 ; -- HERE HERE is the NFA of this new word
1876 MOV TOS,Y ; -- NFA Y=NFA
1877 MOV.B @TOS+,W ; -- NFA+1 W=Count_of_chars
1878 BIS.B #1,W ; W=count is always odd
1879 ADD.B #1,W ; W=add one byte for length
1880 ADD Y,W ; W=Aligned_CFA
1881 MOV &CURRENT,X ; X=VOC_BODY of CURRENT
1883 .CASE 1 ; nothing to do
1884 .ELSECASE ; multithreading add 5~ 4words
1885 MOV.B @TOS,TOS ; -- char TOS=first CHAR of new word
1886 AND #(THREADS-1)*2,TOS ; -- offset TOS= Thread offset
1887 ADD TOS,X ; X=VOC_PFAx = thread x of VOC_PFA of CURRENT
1890 HEADEREND MOV Y,&LAST_NFA ; NFA --> LAST_NFA used by QREVEAL, IMMEDIATE, MARKER
1891 MOV X,&LAST_THREAD ; VOC_PFAx --> LAST_THREAD used by QREVEAL
1892 MOV W,&LAST_CFA ; HERE=CFA --> LAST_CFA used by DOES>, RECURSE
1893 MOV PSP,&LAST_PSP ; save PSP for check compiling, used by QREVEAL
1894 ADD #4,W ; by default make room for two words...
1896 MOV @RSP+,PC ; RET W is the new DP value )
1897 ; X is LAST_THREAD > used by compiling words: CREATE, DEFER, :...
1898 COLONNEXT ; Y is NFA )
1899 .SWITCH DTC ; Direct Threaded Code select
1901 MOV #1284h,-4(W) ; compile CALL R4 = rDOCOL ([rDOCOL] = XDOCOL)
1904 MOV #120Dh,-4(W) ; compile PUSH IP 3~
1905 MOV #1284h,-2(W) ; compile CALL R4 = rDOCOL ([rDOCOL] = EXIT)
1907 MOV #120Dh,-4(W) ; compile PUSH IP 3~
1908 MOV #400Dh,-2(W) ; compile MOV PC,IP 1~
1909 MOV #522Dh,0(W) ; compile ADD #4,IP 1~
1910 MOV #4D30h,+2(W) ; compile MOV @IP+,PC 4~
1913 MOV #-1,&STATE ; enter compiling state
1915 ;-----------------------------------;
1917 ;;Z ?REVEAL -- if no stack mismatch, link this new word in the CURRENT vocabulary
1918 QREVEAL CMP PSP,&LAST_PSP ; Check SP with its saved value by :, :NONAME, CODE...
1919 JNZ BAD_CSP ; if stack mismatch.
1920 GOOD_CSP MOV &LAST_NFA,Y ;
1921 MOV &LAST_THREAD,X ;
1922 REVEAL MOV @X,-2(Y) ; [LAST_THREAD] --> LFA (for NONAME: [LAST_THREAD] --> unused PA reg)
1923 MOV Y,0(X) ; LAST_NFA --> [LAST_THREAD] (for NONAME: LAST_NFA --> unused PA reg)
1928 .byte 15,"stack mismatch!"
1929 FABORT_TERM .word ABORT_TERM
1932 ; https://forth-standard.org/standard/core/Semi
1933 ; ; -- end a colon definition
1934 SEMICOLON CMP #0,&STATE ; if interpret mode, semicolon becomes a comment identifier
1935 JZ BACKSLASH ; tip: ";" is transparent to the preprocessor, so semicolon comments are kept in file.4th
1936 mDOCOL ; compile mode
1937 .word lit,EXIT,COMMA
1938 .word QREVEAL,LEFTBRACKET,EXIT
1940 FORTHWORD "IMMEDIATE"
1941 ; https://forth-standard.org/standard/core/IMMEDIATE
1942 ; IMMEDIATE -- make last definition immediate
1943 IMMEDIATE MOV &LAST_NFA,Y ; Y = NFA|unused_PA_reg as lure for :NONAME
1948 ; https://forth-standard.org/standard/core/CREATE
1949 ; CREATE <name> -- define a CONSTANT with its next address
1950 ; Execution: ( -- a-addr ) ; a-addr is the address of name's data field
1951 ; ; the execution semantics of name may be extended by using DOES>
1952 CREATE CALL #HEADER ; -- W = DDP
1953 MOV #1286h,-4(W) ;4 -4(W) = CFA = CALL R6 = rDOCON
1954 MOV W,-2(W) ;3 -2(W) = PFA = W = next address
1955 JMP REVEAL ; to link the definition in vocabulary
1957 .IFDEF CORE_COMPLEMENT
1959 ; https://forth-standard.org/standard/core/DOES
1960 ; DOES> -- set action for the latest CREATEd definition
1961 DOES MOV &LAST_CFA,W ; W = CFA of CREATEd word
1962 MOV #1285h,0(W) ; replace old CFA of CREATE by new CFA CALL R5 = rDODOES
1963 MOV IP,2(W) ; replace PFA by the address after DOES> as execution address
1965 MOV @IP+,PC ; exit of the new created word
1967 FORTHWORD "CONSTANT"
1968 ;https://forth-standard.org/standard/core/CONSTANT
1969 ;C CONSTANT <name> n -- define a Forth CONSTANT
1970 CONSTANT CALL #HEADER ; W = DDP = CFA + 2 words
1971 MOV #1286h,-4(W) ; CFA = CALL R6 = rDOCON
1972 MOV TOS,-2(W) ; PFA = n
1974 JMP REVEAL ; to link the definition in vocabulary
1976 FORTHWORD "VARIABLE"
1977 ;https://forth-standard.org/standard/core/VARIABLE
1978 ;C VARIABLE <name> -- define a Forth VARIABLE
1979 VARIABLE CALL #HEADER ; W = DDP = CFA + 2 words
1980 MOV #1287h,-4(W) ; CFA = CALL R7 = rDOVAR, PFA is undefined
1981 JMP REVEAL ; to link created VARIABLE in vocabulary
1983 .ENDIF ; CORE_COMPLEMENT
1987 ; https://forth-standard.org/standard/core/ColonNONAME
1990 ; X is the LAST_THREAD lure value for REVEAL
1991 ; Y is the LAST_NFA lure value for REVEAL and IMMEDIATE
1992 ; ...because we don't want to modify the word set !
1993 PUSH #COLONNEXT ; define COLONNEXT as HEADERLESS RET
1994 HEADERLESS SUB #2,PSP ; common part of :NONAME and CODENNM
1998 ADDC #0,W ; W = aligned CFA
1999 MOV W,TOS ; -- xt aligned CFA of :NONAME | CODENNM
2000 MOV #210h,X ; X = 210h = unused PA register address (lure for REVEAL)
2002 ADD #2,Y ;1 Y = 212h = unused PA register address (lure for REVEAL and IMMEDIATE)
2005 ; https://forth-standard.org/standard/core/DEFER
2006 ; Skip leading space delimiters. Parse name delimited by a space.
2007 ; Create a definition for name with the execution semantics defined below.
2009 ; name Execution: --
2010 ; Execute the xt that name is set to execute, i.e. NEXT (nothing),
2011 ; until the phrase ' word IS name is executed, causing a new value of xt to be assigned to name.
2014 MOV #4030h,-4(W) ;4 first CELL = MOV @PC+,PC = BR...
2015 MOV #NEXT_ADR,-2(W) ;3 second CELL = ...mNEXT : do nothing by default
2016 JMP REVEAL ; to link created word in vocabulary
2018 ; DEFER! ( xt CFA_DEFERed_WORD -- )
2019 ; FORTHWORD "DEFER!"
2020 DEFERSTORE MOV @PSP+,2(TOS) ; -- CFA_DEFERed_WORD xt --> [PFA_DEFERed_WORD]
2026 ; DEFER DISPLAY create a "do nothing" definition (2 CELLS)
2027 ; inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY
2028 ; or in a definition : ... ['] U. IS DISPLAY ...
2029 ; KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words
2030 FORTHWORDIMM "IS" ; immediate
2034 IS_COMPILE ASMtoFORTH
2035 .word BRACTICK ; find the word, compile its CFA as literal
2036 .word lit,DEFERSTORE,COMMA ; compile DEFERSTORE
2039 .word TICK,DEFERSTORE ; find the word, leave its CFA on the stack and execute DEFERSTORE
2044 .IFDEF MSP430ASSEMBLER
2046 FORTHWORD "CODE" ; a CODE word must be finished with ENDCODE
2047 ASMCODE CALL #HEADER ; (that sets CFA and PFA)
2048 ASMCODE1 SUB #4,&DDP ; remove default CFA and PFA
2051 MOV #0,&RPT_WORD ; clear RPT instruction
2054 .word ALSO,ASSEMBLER,EXIT
2056 ; HDNCODE (hidden CODE) is used to define a CODE word which must not to be executed by FORTH interpreter
2057 ; i.e. typically an assembler word called by CALL and ended by RET, or an interrupt routine ended by RETI.
2058 ; ASM words are only usable in ASSEMBLER defined words
2060 MOV #BODYASSEMBLER,&CURRENT ; select ASSEMBLER word set to link this HDNCODE definition
2063 asmword "ENDCODE" ; test PSP balancing then restore previous CONTEXT
2064 ENDCODE mDOCOL ; and set CURRENT = CONTEXT (to also end ASM definitions)
2066 ENDCODE1 .word PREVIOUS,DEFINITIONS,EXIT
2069 FORTHWORD "CODENNM" ; CODENoNaMe is the assembly counterpart of :NONAME
2070 CODENNM PUSH #ASMCODE1 ; define HEADERLESS return
2071 JMP HEADERLESS ; that makes room for CFA and PFA
2074 ; here are 3 words used to switch FORTH <--> ASSEMBLER
2076 ; COLON -- compile DOCOL, remove ASSEMBLER from CONTEXT and CURRENT, switch to compilation state
2081 MOV #1284h,0(W) ; compile CALL R4 = rDOCOL ([rDOCOL] = XDOCOL)
2084 MOV #120Dh,0(W) ; compile PUSH IP
2085 COLON1 MOV #1284h,2(W) ; compile CALL R4 = rDOCOL
2087 .CASE 3 ; inlined DOCOL
2088 MOV #120Dh,0(W) ; compile PUSH IP
2089 COLON1 MOV #400Dh,2(W) ; compile MOV PC,IP
2090 MOV #522Dh,4(W) ; compile ADD #4,IP
2091 MOV #4D30h,6(W) ; compile MOV @IP+,PC
2095 COLON2 MOV #-1,&STATE ; enter in compile state
2097 .word PREVIOUS,DEFINITIONS,EXIT ; restore previous CONTEXT and set CURRENT = CONTEXT
2099 ; LO2HI -- same as COLON but without saving IP
2102 .CASE 1 ; compile 2 words
2104 MOV #12B0h,0(W) ; compile CALL #EXIT, 2 words 4+6=10~
2108 .ELSECASE ; CASE 2 : compile 1 word, CASE 3 : compile 3 words
2109 SUB #2,&DDP ; to skip PUSH IP
2114 ; HI2LO -- immediate, switch to low level, set interpretation state, add ASSEMBLER to CONTEXT
2115 FORTHWORDIMM "HI2LO" ;
2117 .word HERE,CELLPLUS,COMMA ; compile HERE+2
2118 .word LEFTBRACKET ; switch to interpret state
2119 .word ASMCODE2 ; add ASSEMBLER in context
2122 .ENDIF ; MSP430ASSEMBLER
2125 ; ------------------------------------------------------------------------------
2126 ; forthMSP430FR : CONDITIONNAL COMPILATION
2127 ; ------------------------------------------------------------------------------
2128 .include "forthMSP430FR_CONDCOMP.asm"
2131 .IFDEF CORE_COMPLEMENT
2132 ; ------------------------------------------------------------------------------
2133 ; CONTROL STRUCTURES
2134 ; ------------------------------------------------------------------------------
2135 ; THEN and BEGIN compile nothing
2136 ; DO compile one word
2137 ; IF, ELSE, AGAIN, UNTIL, WHILE, REPEAT, LOOP & +LOOP compile two words
2138 ; LEAVE compile three words
2140 FORTHWORDIMM "IF" ; immediate
2141 ; https://forth-standard.org/standard/core/IF
2142 ; IF -- IFadr initialize conditional forward branch
2145 MOV &DDP,TOS ; -- HERE
2146 ADD #4,&DDP ; compile one word, reserve one word
2147 MOV #QFBRAN,0(TOS) ; -- HERE compile QFBRAN
2148 .ENDIF ; CORE_COMPLEMENT
2149 CELLPLUS ADD #2,TOS ; -- HERE+2=IFadr
2152 .IFDEF CORE_COMPLEMENT
2153 FORTHWORDIMM "ELSE" ; immediate
2154 ; https://forth-standard.org/standard/core/ELSE
2155 ; ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack
2156 ELSS ADD #4,&DDP ; make room to compile two words
2157 MOV &DDP,W ; W=HERE+4
2159 MOV W,0(TOS) ; HERE+4 ==> [IFadr]
2161 MOV W,TOS ; -- ELSEadr
2164 FORTHWORDIMM "THEN" ; immediate
2165 ; https://forth-standard.org/standard/core/THEN
2166 ; THEN IFadr -- resolve forward branch
2167 THEN MOV &DDP,0(TOS) ; -- IFadr
2171 FORTHWORDIMM "BEGIN" ; immediate
2172 ; https://forth-standard.org/standard/core/BEGIN
2173 ; BEGIN -- BEGINadr initialize backward branch
2174 MOV #HERE,PC ; -- HERE
2176 FORTHWORDIMM "UNTIL" ; immediate
2177 ; https://forth-standard.org/standard/core/UNTIL
2178 ; UNTIL BEGINadr -- resolve conditional backward branch
2180 UNTIL1 ADD #4,&DDP ; compile two words
2181 MOV &DDP,W ; W = HERE
2182 MOV X,-4(W) ; compile Bran or QFBRAN at HERE
2183 MOV TOS,-2(W) ; compile bakcward adr at HERE+2
2187 FORTHWORDIMM "AGAIN" ; immediate
2188 ; https://forth-standard.org/standard/core/AGAIN
2189 ;X AGAIN BEGINadr -- resolve uncondionnal backward branch
2193 FORTHWORDIMM "WHILE" ; immediate
2194 ; https://forth-standard.org/standard/core/WHILE
2195 ; WHILE BEGINadr -- WHILEadr BEGINadr
2199 FORTHWORDIMM "REPEAT" ; immediate
2200 ; https://forth-standard.org/standard/core/REPEAT
2201 ; REPEAT WHILEadr BEGINadr -- resolve WHILE loop
2203 .word AGAIN,THEN,EXIT
2205 FORTHWORDIMM "DO" ; immediate
2206 ; https://forth-standard.org/standard/core/DO
2207 ; DO -- DOadr L: -- 0
2210 ADD #2,&DDP ; make room to compile xdo
2211 MOV &DDP,TOS ; -- HERE+2
2212 MOV #xdo,-2(TOS) ; compile xdo
2213 ADD #2,&LEAVEPTR ; -- HERE+2 LEAVEPTR+2
2215 MOV #0,0(W) ; -- HERE+2 L-- 0
2219 ; https://forth-standard.org/standard/core/I
2220 ; I -- n R: sys1 sys2 -- sys1 sys2
2221 ; get the innermost loop index
2222 II SUB #2,PSP ;1 make room in TOS
2224 MOV @RSP,TOS ;2 index = loopctr - fudge
2228 FORTHWORDIMM "LOOP" ; immediate
2229 ; https://forth-standard.org/standard/core/LOOP
2230 ; LOOP DOadr -- L-- an an-1 .. a1 0
2232 LOOPNEXT ADD #4,&DDP ; make room to compile two words
2234 MOV X,-4(W) ; xloop --> HERE
2235 MOV TOS,-2(W) ; DOadr --> HERE+2
2236 ; resolve all "leave" adr
2237 LEAVELOOP MOV &LEAVEPTR,TOS ; -- Adr of top LeaveStack cell
2238 SUB #2,&LEAVEPTR ; --
2239 MOV @TOS,TOS ; -- first LeaveStack value
2240 CMP #0,TOS ; -- = value left by DO ?
2242 MOV W,0(TOS) ; move adr after loop as UNLOOP adr
2244 LOOPEND MOV @PSP+,TOS
2247 FORTHWORDIMM "+LOOP" ; immediate
2248 ; https://forth-standard.org/standard/core/PlusLOOP
2249 ; +LOOP adrs -- L-- an an-1 .. a1 0
2250 PLUSLOOP MOV #xploop,X
2252 .ENDIF ; CORE_COMPLEMENT
2254 .IFDEF VOCABULARY_SET
2255 ;-------------------------------------------------------------------------------
2256 ; WORDS SET for VOCABULARY, not ANS compliant
2257 ;-------------------------------------------------------------------------------
2260 ; https://forth-standard.org/standard/core/DOES
2261 ; DOES> -- set action for the latest CREATEd definition
2262 DOES MOV &LAST_CFA,W ; W = CFA of CREATEd word
2263 MOV #1285h,0(W) ; replace CFA (DOCON) by new CFA (DODOES)
2264 MOV IP,2(W) ; replace PFA by the address after DOES> as execution address
2266 MOV @IP+,PC ; exit of the new created word
2269 FORTHWORD "VOCABULARY"
2270 ;X VOCABULARY -- create a vocabulary, up to 7 vocabularies in CONTEXT
2275 .word lit,0,COMMA ; will keep the NFA of the last word of the future created vocabularies
2277 .word lit,THREADS,lit,0,xdo
2278 VOCABULOOP .word lit,0,COMMA
2279 .word xloop,VOCABULOOP
2281 .word HERE ; link via LASTVOC the future created vocabulary
2282 .word LIT,LASTVOC,DUP
2283 .word FETCH,COMMA ; compile [LASTVOC] to HERE+
2284 .word STORE ; store (HERE - 2) to LASTVOC
2285 .word DOES ; compile CFA and PFA for the future defined vocabulary
2286 .ENDIF ; VOCABULARY_SET
2287 VOCDOES .word LIT,CONTEXT,STORE
2290 .IFDEF VOCABULARY_SET
2292 .ENDIF ; VOCABULARY_SET
2293 ;X FORTH -- ; set FORTH the first context vocabulary; FORTH must be the first vocabulary
2294 FORTH ; leave BODYFORTH on the stack and run VOCDOES
2295 CALL rDODOES ; Code Field Address (CFA) of FORTH
2296 PFAFORTH .word VOCDOES ; Parameter Field Address (PFA) of FORTH
2297 BODYFORTH ; BODY of FORTH
2301 .word lastforthword1
2303 .word lastforthword1
2304 .word lastforthword2
2305 .word lastforthword3
2307 .word lastforthword1
2308 .word lastforthword2
2309 .word lastforthword3
2310 .word lastforthword4
2311 .word lastforthword5
2312 .word lastforthword6
2313 .word lastforthword7
2315 .word lastforthword1
2316 .word lastforthword2
2317 .word lastforthword3
2318 .word lastforthword4
2319 .word lastforthword5
2320 .word lastforthword6
2321 .word lastforthword7
2322 .word lastforthword8
2323 .word lastforthword9
2324 .word lastforthword10
2325 .word lastforthword11
2326 .word lastforthword12
2327 .word lastforthword13
2328 .word lastforthword14
2329 .word lastforthword15
2331 .word lastforthword1
2332 .word lastforthword2
2333 .word lastforthword3
2334 .word lastforthword4
2335 .word lastforthword5
2336 .word lastforthword6
2337 .word lastforthword7
2338 .word lastforthword8
2339 .word lastforthword9
2340 .word lastforthword10
2341 .word lastforthword11
2342 .word lastforthword12
2343 .word lastforthword13
2344 .word lastforthword14
2345 .word lastforthword15
2346 .word lastforthword16
2347 .word lastforthword17
2348 .word lastforthword18
2349 .word lastforthword19
2350 .word lastforthword20
2351 .word lastforthword21
2352 .word lastforthword22
2353 .word lastforthword23
2354 .word lastforthword24
2355 .word lastforthword25
2356 .word lastforthword26
2357 .word lastforthword27
2358 .word lastforthword28
2359 .word lastforthword29
2360 .word lastforthword30
2361 .word lastforthword31
2367 .IFDEF MSP430ASSEMBLER
2368 .IFDEF VOCABULARY_SET
2369 FORTHWORD "ASSEMBLER"
2370 .ENDIF ; VOCABULARY_SET
2371 ;X ASSEMBLER -- ; set ASSEMBLER the first context vocabulary
2372 ASSEMBLER CALL rDODOES ; leave BODYASSEMBLER on the stack and run VOCDOES
2443 .ENDIF ; MSP430ASSEMBLER
2445 .IFDEF VOCABULARY_SET
2447 .ENDIF ; VOCABULARY_SET
2448 ;X ALSO -- make room to put a vocabulary as first in context
2449 ALSO MOV #12,W ; -- move up 6 words, 8th word of CONTEXT area must remain to 0
2450 MOV #CONTEXT+12,X ; X=src
2455 MOV.B @X,0(Y) ; if X=src < Y=dst copy W bytes beginning with the end
2460 .IFDEF VOCABULARY_SET
2461 FORTHWORD "PREVIOUS"
2462 .ENDIF ; VOCABULARY_SET
2463 ;X PREVIOUS -- pop last vocabulary out of context
2464 PREVIOUS MOV #14,W ; move down 7 words, first with the 8th word equal to 0
2465 MOV #CONTEXT,Y ; Y=dst
2468 MOVEDOWN MOV.B @X+,0(Y) ; if X=src > Y=dst copy W bytes
2474 .IFDEF VOCABULARY_SET
2476 .ENDIF ; VOCABULARY_SET
2477 ;X ONLY -- cut context list to access only first vocabulary, ex.: FORTH ONLY
2478 ONLY MOV #0,&CONTEXT+2
2481 .IFDEF VOCABULARY_SET
2482 FORTHWORD "DEFINITIONS"
2483 .ENDIF ; VOCABULARY_SET
2484 ;X DEFINITIONS -- set last context vocabulary as entry for further defining words
2485 DEFINITIONS MOV &CONTEXT,&CURRENT
2488 .IFDEF USE_MOVE ; if UTILITY.asm|ANS_COMP.asm
2490 ; https://forth-standard.org/standard/core/MOVE
2491 ; MOVE addr1 addr2 u -- smart move
2492 ; VERSION FOR 1 ADDRESS UNIT = 1 CHAR
2493 MOVE MOV TOS,W ; W = cnt
2494 MOV @PSP+,Y ; Y = addr2 = dst
2495 MOV @PSP+,X ; X = addr1 = src
2496 MOV @PSP+,TOS ; pop new TOS
2497 CMP #0,W ; count = 0 ?
2498 JZ MOVEND ; already done !
2499 CMP X,Y ; Y=dst = X=src ?
2500 JZ MOVEND ; already done !
2501 JNC MOVEDOWN ; if Y=dst < X=src ; see PREVIOUS
2502 ADD W,Y ; move beginning with the end
2504 JMP MOVEUP ; if Y=dst > X=src ; see ALSO
2507 ;-------------------------------------------------------------------------------
2509 ;-------------------------------------------------------------------------------
2510 STATE_DOES ; execution part of PWR_STATE ; sorry, doesn't restore search order pointers
2511 .word FORTH,ONLY,DEFINITIONS
2512 .word $+2 ; -- BODY IP is free
2513 .IFDEF VOCABULARY_SET
2514 MOV @TOS+,W ; -- BODY+2 W = old VOCLINK = VLK
2516 MOV &WIPE_VOC,W ; W = VOCLINK = VLK
2518 MOV W,&LASTVOC ; restore (or init) LASTVOC in RAM
2519 MOV @TOS,TOS ; -- OLD_DP
2520 MOV TOS,&DDP ; -- DP restore (or init) DP in RAM
2521 ; then restore words link(s) with their value < old DP
2523 .CASE 1 ; mono thread vocabularies
2524 MARKALLVOC MOV W,Y ; -- DP W=VLK Y=VLK
2525 MRKWORDLOOP MOV -2(Y),Y ; -- DP W=VLK Y=NFA
2526 CMP Y,TOS ; -- DP CMP = TOS-Y : OLD_DP-NFA
2527 JNC MRKWORDLOOP ; loop back if TOS<Y : OLD_DP<NFA
2528 MOV Y,-2(W) ; W=VLK X=THD Y=NFA refresh thread with good NFA
2529 MOV @W,W ; -- DP W=[VLK] = next voclink
2530 CMP #0,W ; -- DP W=[VLK] = next voclink end of vocs ?
2531 JNZ MARKALLVOC ; -- DP W=VLK no : loopback
2532 .ELSECASE ; multi threads vocabularies
2533 MARKALLVOC MOV #THREADS,IP ; -- DP W=VLK
2534 MOV W,X ; -- DP W=VLK X=VLK
2535 MRKTHRDLOOP MOV X,Y ; -- DP W=VLK X=VLK Y=VLK
2536 SUB #2,X ; -- DP W=VLK X=THD (thread ((case-2)to0))
2537 MRKWORDLOOP MOV -2(Y),Y ; -- DP W=VLK Y=NFA
2538 CMP Y,TOS ; -- DP CMP = TOS-Y : DP-NFA
2539 JNC MRKWORDLOOP ; loop back if TOS<Y : DP<NFA
2540 MARKTHREAD MOV Y,0(X) ; W=VLK X=THD Y=NFA refresh thread with good NFA
2541 SUB #1,IP ; -- DP W=VLK X=THD Y=NFA IP=CFT-1
2542 JNZ MRKTHRDLOOP ; loopback to compare NFA in next thread (thread-1)
2543 MOV @W,W ; -- DP W=[VLK] = next voclink
2544 CMP #0,W ; -- DP W=[VLK] = next voclink end of vocs ?
2545 JNZ MARKALLVOC ; -- DP W=VLK no : loopback
2546 .ENDCASE ; of THREADS ; -- DP
2549 NEXT_ADR MOV @IP+,PC ;
2551 ;-------------------------------------------------------------------------------
2552 ; FASTFORTH START: set DP, VOCLINK, CURRENT and CONTEXT
2553 ;-------------------------------------------------------------------------------
2554 FORTHWORD "PWR_STATE" ; executed by POWER_ON and ABORT_TERM; does PWR_HERE word set
2555 PWR_STATE CALL rDODOES ; DOES part of MARKER : resets pointers DP, voclink
2556 .word STATE_DOES ; execution vector of PWR_STATE
2557 .IFDEF VOCABULARY_SET
2558 MARKVOC .word lastvoclink ; initialised by forthMSP430FR.asm as voclink value
2560 MARKDP .word ROMDICT ; initialised by forthMSP430FR.asm as DP value
2562 FORTHWORD "RST_STATE" ; executed by <reset>, COLD, SYSRSTIV error; does RST_HERE word set
2563 RST_STATE MOV &RST_DP,&MARKDP ; INIT value above (FRAM value)
2564 .IFDEF VOCABULARY_SET
2565 MOV &RST_VOC,&MARKVOC ; INIT value above (FRAM value)
2569 FORTHWORD "PWR_HERE" ; define word set bound for POWER_ON, ABORT_TERM.
2570 PWR_HERE MOV &DDP,&MARKDP
2571 .IFDEF VOCABULARY_SET
2572 MOV &LASTVOC,&MARKVOC
2576 FORTHWORD "RST_HERE" ; define word set bound for <reset>, COLD, SYSRSTIV error.
2577 RST_HERE MOV &DDP,&RST_DP
2578 .IFDEF VOCABULARY_SET
2579 MOV &LASTVOC,&RST_VOC
2581 JMP PWR_HERE ; and obviously the same for POWER_ON...
2583 ;-------------------------------------------------------------------------------
2584 ; PUC 6.2: SELECT PWR_STATE|RST_STATE|DEEP_RESET <== INI_FORTH
2585 ;-------------------------------------------------------------------------------
2586 SEL_P_R_D CMP #0Eh,TOS ;
2587 JZ PWR_STATE ; if RSTIV_MEM = 14 (SYSSVSH event)
2589 JGE RST_STATE ; if RSTIV_MEM >= 4 (RESET,COLD,SYS_FAILURES)
2591 JGE PWR_STATE ; if RSTIV_MEM >= 0 (POWER_ON,WARM,ABORT")
2592 ;-----------------------------------;
2593 ; DEEP RESET ; if RSTIV_MEM < 0
2594 ;-----------------------------------;
2595 ; INIT SIGNATURES AREA ;
2596 ;-----------------------------------;
2597 MOV #16,X ; max known SIGNATURES length = 12 bytes
2598 SIGNATLOOP SUB #2,X ;
2599 MOV #-1,SIGNATURES(X) ; reset signature; WARNING ! DON'T CHANGE IMMEDIATE VALUE !
2601 ;-----------------------------------; X = 0 ;-)
2602 ; INIT VECTORS INT ;
2603 ;-----------------------------------;
2604 MOV #RESET,-2(X) ; write RESET at addr X-2 = FFFEh
2605 INIVECLOOP SUB #2,X ;
2606 MOV #COLD,-2(X) ; -2(X) = FFFCh first
2607 CMP #0FFAEh,X ; init 41 vectors, FFFCh down to 0FFACh
2608 JNZ INIVECLOOP ; all vectors are initialised to execute COLD routine
2609 ;-----------------------------------;
2610 ; INIT all "CALL #xxx_APP" ;
2611 ;-----------------------------------;
2612 MOV #WIPE_INI,X ; WIPE_INI constants are in FRAM INFO
2613 MOV @X+,&PFACOLD ; COLD_TERM as default COLD_APP --> PFACOLD
2614 MOV @X+,&PFA_INI_FORTH ; RET_ADR|INI_FORTH_SD as default INI_SOFT_APP --> PFA_INI_FORTH
2615 MOV @X+,&PFASLEEP ; RXON as default BACKGND_APP --> PFASLEEP
2616 MOV @X+,&PFAWARM ; INIT_TERM|INIT_SD as default INI_HARD_APP --> PFAWARM
2617 MOV @X+,&TERM_VEC ; TERMINAL_INT as default vector --> TERM_VEC
2618 ;-----------------------------------;
2619 ; INIT DP VOC_link ;
2620 ;-----------------------------------;
2621 MOV @X+,&RST_DP ; ROMDICT --> RST_DP
2622 .IFDEF VOCABULARY_SET
2623 MOV @X+,&RST_VOC ; lastvoclink --> RST_VOC
2625 ;-----------------------------------;
2626 JMP RST_STATE ; then return to LIT|WARM from resp. QABORT|RESET
2627 ;-----------------------------------;
2629 ;===============================================================================
2630 ; ┌┐ ┌─┐┬─┐ ┌─┐┌─┐┬─┐ ┌─┐┬ ┬┌─┐ ┌─┐┌─┐┬┬ ┬ ┬┬─┐┌─┐┌─┐ ┌─┐┌─┐┬ ┬ ┬ ┬┌─┐┬─┐┌─┐
2631 ; ├┴┐│ │├┬┘ ├─┘│ │├┬┘ ├─┘│ ││ ├┤ ├─┤││ │ │├┬┘├┤ └─┐ ├┤ ├─┤│ │ ├─┤├┤ ├┬┘├┤
2632 ; └─┘└─┘┴└─ ┴ └─┘┴└─ ┴ └─┘└─┘ └ ┴ ┴┴┴─┘└─┘┴└─└─┘└─┘ └ ┴ ┴┴─┘┴─┘ ┴ ┴└─┘┴└─└─┘
2633 ;===============================================================================
2635 ;===============================================================================
2636 ; PUC 1: replace pin RESET by pin NMI, stops WDT_RESET
2637 ;-------------------------------------------------------------------------------
2638 BIS #3,&SFRRPCR ; pin RST becomes pin NMI with falling edge, so SYSRSTIV = 4
2639 BIS #10h,&SFRIE1 ; enable NMI interrupt ==> hardware RESET is redirected to COLD.
2640 MOV #5A80h,&WDTCTL ; disable WDT RESET
2641 ;-------------------------------------------------------------------------------
2642 ; PUC 2: INIT STACKS
2643 ;-------------------------------------------------------------------------------
2644 MOV #RSTACK,RSP ; init return stack
2645 MOV #PSTACK,PSP ; init parameter stack
2646 ;-------------------------------------------------------------------------------
2647 ; PUC 3: init RAM to 0
2648 ;-------------------------------------------------------------------------------
2650 INITRAMLOOP SUB #2,X ; 1
2651 MOV #0,RAM_ORG(X) ; 3
2652 JNZ INITRAMLOOP ; 2 6 cycles loop !
2653 ;-------------------------------------------------------------------------------
2654 ; PUC 4: I/O, RAM, RTC, CS, SYS initialisation limited to FastForth usage.
2655 ; All unused I/O are set as input with pullup resistor.
2656 ;-------------------------------------------------------------------------------
2657 .include "TargetInit.asm" ; include target specific init code
2658 ;-------------------------------------------------------------------------------
2659 ; PUC 5: GET SYSRSTIV
2660 ;-------------------------------------------------------------------------------
2661 MOV &RSTIV_MEM,TOS ; get RSTIV_MEM = Soft_SYSRSTIV
2662 MOV #0,&RSTIV_MEM ; clear RSTIV_MEM
2663 BIS &SYSRSTIV,TOS ; hard_SYSRSTIV|soft_SYSRSTIV --> TOS; SYSRSTIV = 0
2664 ;-------------------------------------------------------------------------------
2665 ; PUC 6: START FORTH engine
2666 ;-------------------------------------------------------------------------------
2667 CALL #INI_FORTH ; common ?ABORT|PUC "hybrid" subroutine with return to FORTH interpreter
2668 .word WARM ; goto WARM, without return. See forthMSP430FR_TERM_xxx.asm
2669 ;-----------------------------------;
2671 .IFDEF MSP430ASSEMBLER
2672 ;===============================================================================
2674 ;===============================================================================
2676 .include "forthMSP430FR_EXTD_ASM.asm"
2678 .include "forthMSP430FR_ASM.asm"
2682 ;-------------------------------------------------------------------------------
2683 ; UTILITY WORDS OPTION
2684 ;-------------------------------------------------------------------------------
2685 .include "ADDON/UTILITY.asm"
2688 ;-------------------------------------------------------------------------------
2689 ; FIXED POINT OPERATORS OPTION
2690 ;-------------------------------------------------------------------------------
2691 .include "ADDON/FIXPOINT.asm"
2693 .IFDEF SD_CARD_LOADER
2694 ;-------------------------------------------------------------------------------
2696 ;-------------------------------------------------------------------------------
2697 .include "forthMSP430FR_SD_LowLvl.asm" ; SD primitives
2698 .include "forthMSP430FR_SD_INIT.asm" ; return to INIT_TERM; without use of IP,TOS
2699 .include "forthMSP430FR_SD_LOAD.asm" ; SD LOAD driver
2700 .IFDEF SD_CARD_READ_WRITE
2701 .include "forthMSP430FR_SD_RW.asm" ; SD Read/Write driver
2704 .include "ADDON/SD_TOOLS.asm"
2707 ;-------------------------------------------------------------------------------
2708 ; ADD HERE YOUR CODE TO BE INTEGRATED IN KERNEL (protected against WIPE)
2709 ;vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
2711 ; .include "MY_CODE.asm"
2713 ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2714 ; ADD HERE YOUR CODE TO BE INTEGRATED IN KERNEL (protected against WIPE)
2715 ;-------------------------------------------------------------------------------
2717 ;-------------------------------------------------------------------------------
2718 ; RESOLVE ASSEMBLY PTR, init interrupt Vectors
2719 ;-------------------------------------------------------------------------------
2720 .include "ThingsInLast.inc"