1 ; -*- coding: utf-8 -*-
2 ; http://patorjk.com/software/taag/#p=display&f=Banner&t=Fast Forth
4 ; Fast Forth For Texas Instrument MSP430FRxxxx FRAM devices
5 ; Copyright (C) <2017> <J.M. THOORENS>
7 ; This program is free software: you can redistribute it and/or modify
8 ; it under the terms of the GNU General Public License as published by
9 ; the Free Software Foundation, either version 3 of the License, or
10 ; (at your option) any later version.
12 ; This program is distributed in the hope that it will be useful,
13 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ; GNU General Public License for more details.
17 ; You should have received a copy of the GNU General Public License
18 ; along with this program. If not, see <http://www.gnu.org/licenses/>.
21 ; ----------------------------------------------------------------------
22 ;forthMSP430FR_asm.asm
23 ; ----------------------------------------------------------------------
25 ; ----------------------------------------------------------------------
26 ; MOV(.B) #0, dst is coded as follow : MOV(.B) R3, dst ; 1 cycle, one word As=00 register mode
27 ; MOV(.B) #1, dst is coded as follow : MOV(.B) 0(R3), dst ; 2 cycles, one word AS=01 x(reg) mode
28 ; MOV(.B) #2, dst is coded as follow : MOV(.B) @R3, dst ; 2 cycles, one word AS=10 @reg mode
29 ; MOV(.B) #4, dst is coded as follow : MOV(.B) @R2, dst ; 2 cycles, one word AS=10 @reg mode
30 ; MOV(.B) #8, dst is coded as follow : MOV(.B) @R2+, dst ; 2 cycles, one word AS=11 @reg+ mode
31 ; MOV(.B) #-1,dst is coded as follow : MOV(.B) @R3+, dst ; 2 cycles, one word AS=11
32 ; MOV(.B) #xxxx,dst is coded a follow : MOV(.B) @PC+, dst ; 2 cycles, two words AS=11 @reg+ mode
33 ; MOV(.B) &EDE,&TON is coded as follow: MOV(.B) EDE(R2),TON(R2) ; (R2=0), three words AS=01, AD=1 x(reg) mode
34 ; ----------------------------------------------------------------------
36 ; PUSHM order : PSP,TOS, IP, S, T, W, X, Y, rEXIT,rDOVAR,rDOCON, rDODOES, R3, SR,RSP, PC
37 ; PUSHM order : R15,R14,R13,R12,R11,R10, R9, R8, R7 , R6 , R5 , R4 , R3, R2, R1, R0
39 ; example : PUSHM #6,IP pushes IP,S,T,W,X,Y registers to return stack
41 ; POPM order : PC,RSP, SR, R3, rDODOES,rDOCON,rDOVAR,rEXIT, Y, X, W, T, S, IP,TOS,PSP
42 ; POPM order : R0, R1, R2, R3, R4 , R5 , R6 , R7 , R8, R9,R10,R11,R12,R13,R14,R15
44 ; example : POPM #6,IP pop Y,X,W,T,S,IP registers from return stack
46 ; ----------------------------------------------------------------------
47 ; DTCforthMSP430FR5xxx ASSEMBLER : search argument "xxxx", IP is free
48 ; ----------------------------------------------------------------------
50 ;SearchARG ; separator -- n|d or abort" not found"
51 ;; Search ARG of "#xxxx," ; <== PARAM10
52 ;; Search ARG of "&xxxx," ; <== PARAM111
53 ;; Search ARG of "xxxx(REG)," ; <== PARAM130
54 ;; Search ARG of ",&xxxx" ; <== PARAM111 <== PARAM20
55 ;; Search ARG of ",xxxx(REG)" ; <== PARAM210
56 ; PUSHM #2,S ; PUSHM S,T as OPCODE, OPCODEADR
57 ; ASMtoFORTH ; -- separator search word first
58 ; .word WORDD,FIND ; -- addr
59 ; .word QTBRAN,SearchARGW ; -- addr if word found
61 ; .word QFBRAN,NotFound ; -- addr ABORT if not found
62 ;FSearchEnd .word SearchEnd ; -- value goto SearchEnd if number found
63 ;SearchARGW FORTHtoASM ; -- xt xt = CFA
64 ; MOV @TOS+,X ; -- PFA
65 ;QDODOES SUB #DODOES,X ; DODOES = 1284h
67 ; ADD #2,TOS ; -- BODY leave BODY address for DOES words
69 ;QDOCON CMP #1,X ; -- PFA DOCON = 1285h
71 ; MOV @TOS,TOS ; -- cte replace PFA by [PFA] for CONSTANT and CREATE words
73 ;QDOVAR CMP #2,X ; -- PFA DOVAR = 1286h
74 ; JZ SearchEnd ; if DOVAR nothing to do
75 ; SUB #2,TOS ; -- CFA replace PFA by CFA for all other words
76 ;SearchEnd POPM #2,S ; POPM T,S
79 SearchARG ; separator -- n|d or abort" not found"
80 ; Search ARG of "#xxxx," ; <== PARAM10
81 ; Search ARG of "&xxxx," ; <== PARAM111
82 ; Search ARG of "xxxx(REG)," ; <== PARAM130
83 ; Search ARG of ",&xxxx" ; <== PARAM111 <== PARAM20
84 ; Search ARG of ",xxxx(REG)" ; <== PARAM210
85 PUSHM #2,S ; PUSHM S,T as OPCODE, OPCODEADR
86 ASMtoFORTH ; -- separator search word first
87 .word WORDD,FIND ; -- addr
88 .word QTBRAN,SearchARGW ; -- addr if word found
90 .word QFBRAN,NotFound ; -- addr ABORT if not found
91 FSearchEnd .word SearchEnd ; -- value goto SearchEnd if number found
92 SearchARGW FORTHtoASM ; -- xt xt = CFA
94 QDOVAR SUB #DOVAR,X ; DOVAR = 1286h
96 ADD #1,X ; -- PFA DOCON = 1285h
100 QDODOES ADD #2,TOS ; -- BODY leave BODY address for DOES words
101 ADD #1,X ; DODOES = 1284h
104 SearchEnd POPM #2,S ; POPM T,S
107 ; ----------------------------------------------------------------------
108 ; DTCforthMSP430FR5xxx ASSEMBLER : search REG
109 ; ----------------------------------------------------------------------
111 ; compute arg of "xxxx(REG)," ; <== PARAM130, sep=','
112 ; compute arg of ",xxxx(REG)" ; <== PARAM210, sep=' '
113 ComputeARGParenREG ; sep -- Rn
114 MOV #'(',TOS ; -- "(" as WORD separator to find xxxx of "xxxx(REG),"
115 CALL #SearchARG ; -- xxxx aborted if not found
118 MOV TOS,0(X) ; -- xxxx compile xxxx
119 MOV #')',TOS ; -- ")" prepare separator to search REG of "xxxx(REG)"
121 ; search REG of "xxxx(REG)," separator = ')'
122 ; search REG of ",xxxx(REG)" separator = ')'
123 ; search REG of "@REG," separator = ',' <== PARAM120
124 ; search REG of "@REG+," separator = '+' <== PARAM121
125 ; search REG of "REG," separator = ',' <== PARAM13
126 ; search REG of ",REG" separator = BL <== PARAM21
128 SearchREG PUSHM #2,S ; PUSHM S,T as OPCODE, OPCODEADR
129 PUSH &TOIN ; -- sep save >IN
130 ADD #1,&TOIN ; skip "R"
131 ASMtoFORTH ; search xx of Rxx
132 .word WORDD,QNUMBER ;
133 .word QFBRAN,NOTaREG ; -- xxxx if Not a Number
134 FORTHtoASM ; -- Rn number is found
135 ADD #2,RSP ; remove >IN
137 JHS BOUNDERROR ; abort if Rn out of bounds
138 JLO SearchEnd ; -- Rn Z=0 ==> found
140 NOTaREG FORTHtoASM ; -- addr Z=1
141 MOV @RSP+,&TOIN ; -- addr restore >IN
142 JMP SearchEnd ; -- addr Z=1 ==> not a register
144 ; ----------------------------------------------------------------------
145 ; DTCforthMSP430FR5xxx ASSEMBLER : INTERPRET FIRST OPERAND
146 ; ----------------------------------------------------------------------
148 ; PARAM1 separator -- ; parse input buffer until separator and compute first operand of opcode
149 ; sep is comma for src and space for dst .
150 PARAM1 mDOCOL ; -- sep OPCODES types I|V sep = ',' OPCODES types II|VI sep = ' '
151 .word FBLANK,SKIP ; -- sep addr
152 FORTHtoASM ; -- sep addr
153 MOV #0,S ; -- sep addr reset OPCODE
154 MOV &DDP,T ; -- sep addr HERE --> OPCODEADR (opcode is preset to its address !)
155 ADD #2,&DDP ; -- sep addr cell allot for opcode
156 MOV.B @TOS,W ; -- sep addr W=first char of instruction code
157 MOV @PSP+,TOS ; -- sep W=c-addr
158 CMP.B #'#',W ; -- sep W=first char
160 ; "#" found : case of "#xxxx,"
161 PARAM10 ADD #1,&TOIN ; -- sep skip # prefix
162 CALL #SearchARG ; -- xxxx abort if not found
163 MOV #0300h,S ; OPCODE = 0300h : MOV #0,dst is coded MOV R3,dst
164 CMP #0,TOS ; -- xxxx #0 ?
166 MOV #0310h,S ; OPCODE = 0310h : MOV #1,dst is coded MOV 0(R3),dst
167 CMP #1,TOS ; -- xxxx #1 ?
169 MOV #0320h,S ; OPCODE = 0320h : MOV #2,dst is coded MOV @R3,dst
170 CMP #2,TOS ; -- xxxx #2 ?
172 MOV #0220h,S ; OPCODE = 0220h : MOV #4,dst is coded MOV @R2,dst
173 CMP #4,TOS ; -- xxxx #4 ?
175 MOV #0230h,S ; OPCODE = 0230h : MOV #8,dst is coded MOV @R2+,dst
176 CMP #8,TOS ; -- xxxx #8 ?
178 MOV #0330h,S ; -- -1 OPCODE = 0330h : MOV #-1,dst is coded MOV @R3+,dst
179 CMP #-1,TOS ; -- xxxx #-1 ?
181 MOV #0030h,S ; -- xxxx for all other cases : MOV @PC+,dst
182 ; case of "&xxxx," ; <== PARAM110
183 ; case of ",&xxxx" ; <== PARAM20
184 StoreArg MOV &DDP,X ;
185 ADD #2,&DDP ; cell allot for arg
186 StoreTOS ; <== TYPE1DOES
187 MOV TOS,0(X) ; compile arg
188 ; endcase of all "&xxxx" ;
189 ; endcase of all "#xxxx" ; <== PARAM101,102,104,108,10M1
190 ; endcase of all "REG"|"@REG"|"@REG+" <== PARAM124
191 PARAMENDOF MOV @PSP+,TOS ; --
193 mNEXT ; -- S=OPCODE,T=OPCODEADR
194 ; ----------------------------------;
195 PARAM11 CMP.B #'&',W ; -- sep
197 ; case of "&xxxx," ; -- sep search for "&xxxx,"
198 PARAM110 MOV #0210h,S ; -- sep set code type : xxxx(SR) with AS=0b01 ==> x210h (and SR=0 !)
200 ; case of ",&xxxx" ; <== PARAM20
201 PARAM111 ADD #1,&TOIN ; -- sep skip "&" prefix
202 CALL #SearchARG ; -- arg abort if not found
203 JMP StoreArg ; -- then ret
204 ; ----------------------------------;
205 PARAM12 CMP.B #'@',W ; -- sep
207 ; case of "@REG,"|"@REG+,"
208 PARAM120 MOV #0020h,S ; -- sep init OPCODE with indirect code type : AS=0b10
209 ADD #1,&TOIN ; -- sep skip "@" prefix
210 CALL #SearchREG ; Z = not found
211 JNZ PARAM123 ; -- value REG of "@REG," found
212 ; case of "@REG+," ; -- addr REG of "@REG" not found, search REG of "@REG+"
213 PARAM121 ADD #0010h,S ; change OPCODE from @REG to @REG+ type
214 MOV #'+',TOS ; -- "+" as WORD separator to find REG of "@REG+,"
215 CALL #SearchREG ; -- value|addr X = flag
217 ; case of "xxxx(REG)," ; <== PARAM130
218 ; case of double separator: +, and ),
219 PARAM122 CMP &SOURCE_LEN,&TOIN ; test OPCODE II parameter ending by REG+ or (REG) without comma,
220 JZ PARAM123 ; i.e. >IN = SOURCE_LEN : don't skip char CR !
221 ADD #1,&TOIN ; -- 000R skip "," ready for the second operand search
223 ; case of "xxxx(REG),"
224 ; case of "@REG," ; -- 000R <== PARAM120
225 ; case of "REG," ; -- 000R <== PARAM13
226 PARAM123 SWPB TOS ; -- 0R00 swap bytes because it's not a dst REG typeI (not a 2 ops inst.)
227 ; case of "@REG+," ; -- 0R00 (src REG typeI)
228 ; case of "xxxx(REG)," ; -- 0R00 (src REG typeI or dst REG typeII)
229 ; case of "@REG," ; -- 0R00 (src REG typeI)
230 ; case of "REG," ; -- 0R00 (src REG typeI or dst REG typeII)
231 ; case of ",REG" ; -- 000R <== PARAM21 (dst REG typeI)
232 ; case of ",xxxx(REG)" ; -- 000R <== PARAM210 (dst REG typeI)
233 PARAM124 ADD TOS,S ; -- 0R00|000R
235 ; ----------------------------------;
236 ; case of "REG,"|"xxxx(REG)," ; first, searg REG of "REG,"
237 PARAM13 CALL #SearchREG ; -- sep save >IN for second parsing (case of "xxxx(REG),")
238 JNZ PARAM123 ; -- 000R REG of "REG," found, S=OPCODE=0
239 ; case of "xxxx(REG)," ; -- c-addr "REG," not found
240 PARAM130 ADD #0010h,S ; AS=0b01 for indexing address
241 CALL #ComputeARGparenREG; compile xxxx and search REG of "(REG)"
244 ; ----------------------------------------------------------------------
245 ; DTCforthMSP430FR5xxx ASSEMBLER : INTERPRET 2th OPERAND
246 ; ----------------------------------------------------------------------
248 PARAM3 ; for OPCODES TYPE III
249 MOV #0,S ; init OPCODE=0
250 MOV &DDP,T ; T=OPCODEADR
251 ADD #2,&DDP ; make room for opcode
252 ; ----------------------------------;
253 PARAM2 mDOCOL ; parse input buffer until BL and compute this 2th operand
254 .word FBLANK,SKIP ; skip space(s) between "arg1," and "arg2" if any; use not S,T.
255 FORTHtoASM ; -- c-addr search for '&' of "&xxxx
257 MOV #20h,TOS ; -- ' ' as WORD separator to find xxxx of ",&xxxx"
258 JNE PARAM21 ; '&' not found
260 PARAM20 ADD #0082h,S ; change OPCODE : AD=1, dst = R2
261 JMP PARAM111 ; -- ' '
262 ; ----------------------------------;
263 ; case of ",REG"|",xxxx(REG) ; -- ' ' first, search REG of ",REG"
264 PARAM21 CALL #SearchREG ;
265 JNZ PARAM124 ; -- 000R REG of ",REG" found
266 ; case of ",xxxx(REG) ; -- addr REG not found
267 PARAM210 ADD #0080h,S ; set AD=1
268 CALL #ComputeARGparenREG; compile argument xxxx and search REG of "(REG)"
269 JMP PARAM124 ; -- 000R REG of "(REG) found
271 ; ----------------------------------------------------------------------
272 ; DTCforthMSP430FR5xxx ASSEMBLER: OPCODES TYPE 0 : zero operand f:-)
273 ; ----------------------------------------------------------------------
276 .word lit,1300h,COMMA,EXIT
278 ; ----------------------------------------------------------------------
279 ; DTCforthMSP430FR5xxx ASSEMBLER: OPCODES TYPE I : double operand
280 ; ----------------------------------------------------------------------
282 ; OPCODE(code) for TYPE I = 0bxxxx opcode I
284 ; = 0bxxxx src register
285 ; OPCODE(7) AD (dst addr type)
289 ; OPCODE(B) for TYPE I or TYPE II = 0b0 word
291 ; OPCODE(54) AS (src addr type)
292 ; OPCODE(AS) for TYPE I or OPCODE(AD) for TYPE II = 0b00 register
297 ; OPCODE(dst) for TYPE I or TYPE II = 0bxxxx dst register
298 ; ----------------------------------------------------------------------
300 TYPE1DOES .word lit,',',PARAM1 ; -- BODYDOES
301 .word PARAM2 ; -- BODYDOES char separator (BL) included in PARAM2
303 MAKEOPCODE MOV T,X ; -- opcode X= OPCODEADR to compile opcode
304 MOV @TOS,TOS ; -- opcode part of instruction
305 BIS S,TOS ; -- opcode opcode is complete
306 JMP StoreTOS ; -- then EXIT
310 .word TYPE1DOES,4000h
314 .word TYPE1DOES,4040h
317 .word TYPE1DOES,5000h
320 .word TYPE1DOES,5040h
323 .word TYPE1DOES,6000h
326 .word TYPE1DOES,6040h
329 .word TYPE1DOES,7000h
332 .word TYPE1DOES,7040h
335 .word TYPE1DOES,8000h
338 .word TYPE1DOES,8040h
341 .word TYPE1DOES,9000h
344 .word TYPE1DOES,9040h
347 .word TYPE1DOES,0A000h
350 .word TYPE1DOES,0A040h
353 .word TYPE1DOES,0B000h
356 .word TYPE1DOES,0B040h
359 .word TYPE1DOES,0C000h
362 .word TYPE1DOES,0C040h
365 .word TYPE1DOES,0D000h
368 .word TYPE1DOES,0D040h
371 .word TYPE1DOES,0E000h
374 .word TYPE1DOES,0E040h
377 .word TYPE1DOES,0F000h
380 .word TYPE1DOES,0F040h
382 ; ----------------------------------------------------------------------
383 ; DTCforthMSP430FR5xxx ASSEMBLER, OPCODES TYPE II : single operand
384 ; ----------------------------------------------------------------------
385 ; OPCODE(FEDCBA987) opcodeII
386 ; OPCODE(code) for TYPE II = 0bxxxxxxxxx
388 ; OPCODE(B) for TYPE I or TYPE II = 0b0 word
390 ; OPCODE(54) (dst addr type)
391 ; OPCODE(AS) for TYPE I or OPCODE(AD) for TYPE II = 0b00 register
396 ; OPCODE(dst) for TYPE I or TYPE II = 0bxxxx dst register
397 ; ----------------------------------------------------------------------
399 TYPE2DOES .word FBLANK,PARAM1 ; -- BODYDOES
402 AND #0070h,S ; keep B/W & AS infos in OPCODE
403 SWPB W ; (REG org --> REG dst)
404 AND #000Fh,W ; keep REG
405 BIS_ASMTYPE BIS W,S ; -- BODYDOES add it in OPCODE
406 JMP MAKEOPCODE ; -- then end
408 asmword "RRC" ; Rotate Right through Carry ( word)
410 .word TYPE2DOES,1000h
411 asmword "RRC.B" ; Rotate Right through Carry ( byte)
413 .word TYPE2DOES,1040h
414 asmword "SWPB" ; Swap bytes
416 .word TYPE2DOES,1080h
419 .word TYPE2DOES,1100h
422 .word TYPE2DOES,1140h
425 .word TYPE2DOES,1180h
428 .word TYPE2DOES,1200h
431 .word TYPE2DOES,1240h
434 .word TYPE2DOES,1280h
436 BOUNDERRWM1 ADD #1,W ; <== RRAM|RRUM|RRCM|RLAM error
437 BOUNDERRORW MOV W,TOS ; <== PUSHM|POPM|ASM_branch error
438 BOUNDERROR ; <== REG number error
439 mDOCOL ; -- n n = value out of bounds
441 .byte 13,"out of bounds"
444 ; --------------------------------------------------------------------------------
445 ; DTCforthMSP430FR5xxx ASSEMBLER, OPCODES TYPE III : PUSHM|POPM|RLAM|RRAM|RRUM|RRCM
446 ; --------------------------------------------------------------------------------
447 ; PUSHM, syntax: PUSHM #n,REG with 0 < n < 17
448 ; POPM syntax: POPM #n,REG with 0 < n < 17
451 ; PUSHM order : PSP,TOS, IP, S, T, W, X, Y, rEXIT,rDOVAR,rDOCON, rDODOES, R3, SR,RSP, PC
452 ; PUSHM order : R15,R14,R13,R12,R11,R10, R9, R8, R7 , R6 , R5 , R4 , R3, R2, R1, R0
454 ; example : PUSHM #6,IP pushes IP,S,T,W,X,Y registers to return stack
456 ; POPM order : PC,RSP, SR, R3, rDODOES,rDOCON,rDOVAR,rEXIT, Y, X, W, T, S, IP,TOS,PSP
457 ; POPM order : R0, R1, R2, R3, R4 , R5 , R6 , R7 , R8, R9,R10,R11,R12,R13,R14,R15
459 ; example : POPM #6,IP pulls Y,X,W,T,S,IP registers from return stack
461 ; RxxM syntax: RxxM #n,REG with 0 < n < 5
463 TYPE3DOES .word FBLANK,SKIP ; skip spaces if any
464 FORTHtoASM ; -- BODYDOES c-addr
465 ADD #1,&TOIN ; skip "#"
466 MOV #',',TOS ; -- BODYDOES ","
469 .word QFBRAN,NotFound ; ABORT
470 .word PARAM3 ; -- BODYDOES 0x000N S=OPCODE = 0x000R
472 MOV TOS,W ; -- BODYDOES n W = n
473 MOV @PSP+,TOS ; -- BODYDOES
474 SUB #1,W ; W = n floored to 0
476 MOV @TOS,X ; X=OPCODE
477 RLAM #4,X ; OPCODE bit 1000h --> C
478 JNC RxxMINSTRU ; if bit 1000h = 0
479 PxxxINSTRU MOV S,Y ; S=REG, Y=REG to test
480 RLAM #3,X ; OPCODE bit 0200h --> C
481 JNC PUSHMINSTRU ; W=n-1 Y=REG
482 POPMINSTRU SUB W,S ; to make POPM opcode, compute first REG to POP; TI is complicated....
483 PUSHMINSTRU SUB W,Y ; Y=REG-(n-1)
485 JHS BOUNDERRWM1 ; JC=JHS (U>=)
486 RLAM #4,W ; W = n << 4
487 JMP BIS_ASMTYPE ; BODYDOES --
488 RxxMINSTRU CMP #4,W ;
489 JHS BOUNDERRWM1 ; JC=JHS (U>=)
490 SWPB W ; -- BODYDOES W = n << 8
491 RLAM #2,W ; W = N << 10
492 JMP BIS_ASMTYPE ; BODYDOES --
496 .word TYPE3DOES,0050h
499 .word TYPE3DOES,0150h
502 .word TYPE3DOES,0250h
505 .word TYPE3DOES,0350h
508 .word TYPE3DOES,1500h
511 .word TYPE3DOES,1700h
513 ; ----------------------------------------------------------------------
514 ; DTCforthMSP430FR5xxx ASSEMBLER, CONDITIONAL BRANCHS
515 ; ----------------------------------------------------------------------
516 ; ASSEMBLER FORTH OPCODE(FEDC)
517 ; OPCODE(code) for TYPE JNE,JNZ 0<>, <> = 0x20xx + (offset AND 3FF) ; branch if Z = 0
518 ; OPCODE(code) for TYPE JEQ,JZ 0=, = = 0x24xx + (offset AND 3FF) ; branch if Z = 1
519 ; OPCODE(code) for TYPE JNC,JLO U< = 0x28xx + (offset AND 3FF) ; branch if C = 0
520 ; OPCODE(code) for TYPE JC,JHS U>= = 0x2Cxx + (offset AND 3FF) ; branch if C = 1
521 ; OPCODE(code) for TYPE JN 0< = 0x30xx + (offset AND 3FF) ; branch if N = 1
522 ; OPCODE(code) for TYPE JGE >= = 0x34xx + (offset AND 3FF) ; branch if (N xor V) = 0
523 ; OPCODE(code) for TYPE JL < = 0x38xx + (offset AND 3FF) ; branch if (N xor V) = 1
524 ; OPCODE(code) for TYPE JMP = 0x3Cxx + (offset AND 3FF)
526 asmword "S>=" ; if >= assertion (opposite of jump if < )
530 asmword "S<" ; if < assertion
534 asmword "0>=" ; if 0>= assertion ; use only with IF UNTIL WHILE !
538 asmword "0<" ; jump if 0< ; use only with ?JMP ?GOTO !
542 asmword "U<" ; if U< assertion
546 asmword "U>=" ; if U>= assertion
550 asmword "0<>" ; if <>0 assertion
554 asmword "0=" ; if =0 assertion
558 ;ASM IF OPCODE -- @OPCODE1
561 MOV TOS,0(W) ; compile incomplete opcode
566 ;ASM THEN @OPCODE -- resolve forward branch
568 ASM_THEN MOV &DDP,W ; -- @OPCODE W=dst
569 MOV TOS,Y ; Y=@OPCODE
570 ASM_THEN1 MOV @PSP+,TOS ; --
572 ADD #2,X ; -- Y=@OPCODE W=dst X=src+2
573 SUB X,W ; -- Y=@OPCODE W=dst-src+2=displacement*2 (bytes)
574 RRA W ; -- Y=@OPCODE W=displacement (words)
576 JC BOUNDERRORW ; (JHS) unsigned branch if u> 511
577 BIS W,0(Y) ; -- [@OPCODE]=OPCODE completed
580 ;C ELSE @OPCODE1 -- @OPCODE2 branch for IF..ELSE
582 ASM_ELSE MOV &DDP,W ; -- W=HERE
583 MOV #3C00h,0(W) ; compile unconditionnal branch
584 ADD #2,&DDP ; -- DP+2
586 MOV W,0(PSP) ; -- @OPCODE2 @OPCODE1
587 JMP ASM_THEN ; -- @OPCODE2
589 ;C BEGIN -- @BEGIN same as FORTH counterpart
591 ;C UNTIL @BEGIN OPCODE -- resolve conditional backward branch
593 ASM_UNTIL MOV @PSP+,W ; -- OPCODE W=@BEGIN
594 ASM_UNTIL1 MOV TOS,Y ; Y=OPCODE W=@BEGIN
595 ASM_UNTIL2 MOV @PSP+,TOS ; --
596 MOV &DDP,X ; -- Y=OPCODE X=HERE W=dst
597 SUB #2,W ; -- Y=OPCODE X=HERE W=dst-2
598 SUB X,W ; -- Y=OPCODE X=src W=src-dst-2=displacement (bytes)
599 RRA W ; -- Y=OPCODE X=HERE W=displacement (words)
601 JL BOUNDERRORW ; signed branch if < -512
602 AND #3FFh,W ; -- Y=OPCODE X=HERE W=troncated negative displacement (words)
603 BIS W,Y ; -- Y=OPCODE (completed)
608 ;X AGAIN @BEGIN -- uncond'l backward branch
609 ; unconditional backward branch
611 ASM_AGAIN MOV TOS,W ; W=@BEGIN
612 MOV #3C00h,Y ; Y = asmcode JMP
615 ;C WHILE @BEGIN OPCODE -- @WHILE @BEGIN
617 ASM_WHILE mDOCOL ; -- @BEGIN OPCODE
618 .word ASM_IF,SWAP,EXIT
620 ;C REPEAT @WHILE @BEGIN -- resolve WHILE loop
622 ASM_REPEAT mDOCOL ; -- @WHILE @BEGIN
623 .word ASM_AGAIN,ASM_THEN,EXIT
625 ; ------------------------------------------------------------------------------------------
626 ; DTCforthMSP430FR5xxx ASSEMBLER : branch up to 3 backward labels and up to 3 forward labels
627 ; ------------------------------------------------------------------------------------------
628 ; used for non canonical branchs, as BASIC language: "goto line x"
629 ; labels BWx and FWx must be respectively set and used at the beginning of line (>IN < 8).
630 ; FWx at the beginning of a line can resolve only one previous GOTO|?GOTO FWx.
631 ; BWx at the beginning of a line can be resolved by any subsequent GOTO|?GOTO BWx.
635 MOV TOS,Y ; -- PFA Y = ASMBWx addr
638 CMP #8,&TOIN ; are we colon 8 or more ?
639 BACKWUSE JHS ASM_UNTIL1 ; yes, use this label
640 BACKWSET MOV &DDP,0(Y) ; no, set LABEL = DP
662 MOV @TOS,Y ; -- PFA Y=[ASMFWx]
663 CMP #8,&TOIN ; are we colon 8 or more ?
664 FORWUSE JLO ASM_THEN1 ; no: resolve FWx with W=DDP, Y=ASMFWx
665 FORWSET MOV @PSP+,0(W) ; yes compile incomplete opcode
666 ADD #2,&DDP ; increment DDP
667 MOV W,0(TOS) ; store @OPCODE into ASMFWx
687 ;ASM <cond> ?GOTO <label> OPCODE -- conditionnal branch to label
689 INVJMP CMP #3000h,TOS ; invert code jump process
690 JZ GOTONEXT ; case of JN, do nothing
691 XOR #0400h,TOS ; case of: JNZ<-->JZ JNC<-->JC JL<-->JGE
692 BIT #1000h,TOS ; 3xxxh case ?
694 XOR #0800h,TOS ; complementary action for JL<-->JGE
696 .word TICK ; -- OPCODE CFA<label>
699 ;ASM GOTO <label> -- unconditionnal branch to label
703 MOV #3C00h,TOS ; asmcode JMP
711 ; ===============================================================
712 ; to allow data access beyond $FFFF
713 ; ===============================================================
715 ; MOVA (#$x.xxxx|&$x.xxxx|$.xxxx(Rs)|Rs|@Rs|@Rs+ , &|Rd|$.xxxx(Rd))
716 ; ADDA (#$x.xxxx|Rs , Rd)
717 ; CMPA (#$x.xxxx|Rs , Rd)
718 ; SUBA (#$x.xxxx|Rs , Rd)
720 ; first argument process ACMS1
721 ;-----------------------------------;
722 ACMS1 mDOCOL ; -- BODYDOES ','
723 .word FBLANK,SKIP ; -- BODYDOES ',' addr
725 MOV.B @TOS,X ; X=first char of opcode string
726 MOV @PSP+,TOS ; -- BODYDOES ','
727 MOV @PSP+,S ; -- ',' S=BODYDOES
730 ADD #2,&DDP ; make room for opcode
731 ;-----------------------------------;
732 ACMS10 CMP.B #'R',X ; -- ','
734 ACMS101 CALL #SearchREG ; -- Rn src
735 ACMS102 RLAM #4,TOS ; 8<<src
737 ACMS103 BIS S,TOS ; update opcode with src|dst
738 MOV TOS,0(T) ; save opcode
739 MOV T,TOS ; -- OPCODE_addr
741 ;-----------------------------------;
742 ACMS11 CMP.B #'#',X ; -- ',' X=addr
744 BIC #40h,S ; set #opcode
745 ACMS111 ADD #1,&TOIN ; skip '#'|'&'
746 ADD #2,&DDP ; make room for low #$xxxx|&$xxxx|$xxxx(REG)
747 CALL #SearchARG ; -- Lo Hi
748 MOV @PSP+,2(T) ; -- Hi store $xxxx of #$x.xxxx|&$x.xxxx|$x.xxxx(REG)
749 AND #0Fh,TOS ; -- Hi sel Hi src
751 ;-----------------------------------;
752 MOVA12 CMP.B #'&',X ; -- ',' case of MOVA &$x.xxxx
754 XOR #00E0h,S ; set MOVA &$x.xxxx, opcode
756 ;-----------------------------------;
757 MOVA13 BIC #00F0h,S ; set MOVA @REG, opcode
758 CMP.B #'@',X ; -- ','
760 ADD #1,&TOIN ; skip '@'
761 CALL #SearchREG ; -- Rn
762 JNZ ACMS102 ; if @REG found
763 ;-----------------------------------;
764 BIS #0010h,S ; set @REG+ opcode
765 MOV #'+',TOS ; -- '+'
766 MOVA131 CALL #SearchREG ; -- Rn case of MOVA @REG+,|MOVA $x.xxxx(REG),
767 CMP &SOURCE_LEN,&TOIN ; test TYPE II first parameter ending by @REG+ (REG) without comma,
768 JZ ACMS102 ; i.e. may be >IN = SOURCE_LEN: don't skip char CR !
769 ADD #1,&TOIN ; skip "," ready for the second operand search
771 ;-----------------------------------;
772 MOVA14 BIS #0030h,S ; set xxxx(REG), opcode
773 ADD #2,&DDP ; -- ',' make room for first $xxxx of $0.xxxx(REG),
774 MOV #'(',TOS ; -- "(" as WORD separator to find xxxx of "xxxx(REG),"
775 CALL #SearchARG ; -- Lo Hi
776 MOV @PSP+,2(T) ; -- Hi store $xxxx as 2th word
777 MOV #')',TOS ; -- ')'
780 ; 2th argument process ACMS2
781 ;-----------------------------------;
782 ACMS2 mDOCOL ; -- OPCODE_addr
783 .word FBLANK,SKIP ; -- OPCODE_addr addr
785 MOV @PSP+,T ; -- addr T=OPCODE_addr
787 MOV.B @TOS,X ; -- addr X=first char of string instruction
788 MOV.B #' ',TOS ; -- ' '
789 ;-----------------------------------;
790 ACMS21 CMP.B #'R',X ; -- ' '
792 ACMS211 CALL #SearchREG ; -- Rn
794 ;-----------------------------------;
796 ADD #2,&DDP ; -- ' ' make room for $xxxx
799 BIS #060h,S ; set ,&$x.xxxx opcode
800 ADD #1,&TOIN ; skip '&'
801 CALL #SearchARG ; -- Lo Hi
802 MOV @PSP+,2(T) ; -- Hi store $xxxx as 2th word
803 JMP ACMS103 ; update opcode with dst $x and write opcode
804 ;-----------------------------------;
805 MOVA23 BIS #070h,S ; set ,xxxx(REG) opcode
806 MOV #'(',TOS ; -- "(" as WORD separator to find xxxx of "xxxx(REG),"
807 CALL #SearchARG ; -- Lo Hi
808 MOV @PSP+,2(T) ; -- Hi write $xxxx of ,$0.xxxx(REG) as 2th word
809 MOV #')',TOS ; -- ")" as WORD separator to find REG of "xxxx(REG),"
812 ; --------------------------------------------------------------------------------
813 ; DTCforthMSP430FR5xxx ASSEMBLER, OPCODES IV 2 operands: Adda|Cmpa|Mova|Suba (without extended word)
814 ; --------------------------------------------------------------------------------
815 ; absolute and immediate instructions must be written as $x.xxxx (DOUBLE numbers)
816 ; indexed instructions must be written as $.xxxx(REG) (DOUBLE numbers)
817 ; --------------------------------------------------------------------------------
819 TYPE4DOES .word lit,',' ; -- BODYDOES "," char separator for PARAM1
820 .word ACMS1 ; -- OPCODE_addr
821 .word ACMS2 ; -- OPCODE_addr
826 .word TYPE4DOES,00C0h
829 .word TYPE4DOES,00D0h
832 .word TYPE4DOES,00E0h
835 .word TYPE4DOES,00F0h
838 ;; perhaps you also want to call ROM lib routines beyond $FFFF....
839 ;; --------------------------------------------------------------------------------
840 ;; DTCforthMSP430FR5xxx ASSEMBLER: OPCODE TYPE III bis: CALLA (without extended word)
841 ;; --------------------------------------------------------------------------------
842 ;; absolute and immediate instructions must be written as $x.xxxx (DOUBLE numbers)
843 ;; indexed instructions must be written as $.xxxx(REG) (DOUBLE numbers)
844 ;; --------------------------------------------------------------------------------
848 ; .word FBLANK,SKIP ; -- addr
850 ; MOV &DDP,T ; T = DDP
851 ; ADD #2,&DDP ; make room for opcode
852 ; MOV.B @TOS,TOS ; -- char First char of opcode
853 ;CALLA0 MOV #134h,S ; 134h<<4 = 1340h = opcode for CALLA Rn
856 ;CALLA01 MOV.B #' ',TOS ;
857 ;CALLA02 CALL #SearchREG ; -- Rn
858 ;CALLA03 RLAM #4,S ; (opcode>>4)<<4 = opcode
859 ; BIS TOS,S ; update opcode
860 ; MOV S,0(T) ; store opcode
863 ;;-----------------------------------;
864 ;CALLA1 ADD #2,S ; 136h<<4 = opcode for CALLA @REG
865 ; CMP.B #'@',TOS ; -- char Search @REG
867 ; ADD #1,&TOIN ; skip '@'
868 ; MOV.B #' ',TOS ; -- ' '
870 ; JNZ CALLA03 ; if REG found, update opcode
871 ;;-----------------------------------;
872 ; ADD #1,S ; 137h<<4 = opcode for CALLA @REG+
873 ; MOV #'+',TOS ; -- '+'
875 ;;-----------------------------------;
876 ;CALLA2 ADD #2,&DDP ; make room for xxxx of #$x.xxxx|&$x.xxxx|$0.xxxx(REG)
879 ; MOV #13Bh,S ; 13Bh<<4 = opcode for CALLA #$x.xxxx
880 ;CALLA21 ADD #1,&TOIN ; skip '#'|'&'
881 ;CALLA22 CALL #SearchARG ; -- Lo Hi
882 ; MOV @PSP+,2(T) ; -- Hi store #$xxxx|&$xxxx
883 ; JMP CALLA03 ; update opcode with $x. and store opcode
884 ;;-----------------------------------;
885 ;CALLA3 CMP.B #'&',TOS
887 ; ADD #2,S ; 138h<<4 = opcode for CALLA &$x.xxxx
889 ;;-----------------------------------;
890 ;CALLA4 MOV.B #'(',TOS ; -- "("
891 ; SUB #1,S ; 135h<<4 = opcode for CALLA $0.xxxx(REG)
892 ;CALLA41 CALL #SearchARG ; -- Lo Hi
893 ; MOV @PSP+,2(T) ; -- Hi store $xxxx
894 ; MOV #')',TOS ; -- ')'
895 ; JMP CALLA02 ; search Rn and update opcode
898 .ENDIF ; EXTENDED_MEM