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
47 ;;Z SKIP char -- addr ; skip all occurring character 'char'
48 ; FORTHWORD "SKIP" ; used by assembler to parse input stream
49 SKIP MOV #SOURCE_LEN,Y ;2
50 MOV TOS,W ; -- char W=char
51 MOV @Y+,X ;2 -- char W=char X=buf_length
52 MOV @Y,TOS ;2 -- Start_buf_adr W=char X=buf_length
53 ADD TOS,X ; -- Start_buf_adr W=char X=Start_buf_adr+buf_length=End_buf_addr
54 ADD &TOIN,TOS ; -- Parse_Adr W=char X=End_buf_addr
55 SKIPLOOP CMP TOS,X ; -- Parse_Adr W=char X=End_buf_addr
56 JZ SKIPEND ; -- Parse_Adr if end of buffer
57 CMP.B @TOS+,W ; -- Parse_Adr does character match?
58 JZ SKIPLOOP ; -- Parse_Adr+1
59 SKIPNEXT SUB #1,TOS ; -- addr
61 SUB @Y,W ; -- addr W=Parse_Addr-Start_buf_adr=Toin
65 ; ----------------------------------------------------------------------
66 ; DTCforthMSP430FR5xxx ASSEMBLER : search argument "xxxx", IP is free
67 ; ----------------------------------------------------------------------
69 SearchARG ; separator -- n|d or abort" not found"
70 ; Search ARG of "#xxxx," ; <== PARAM10
71 ; Search ARG of "&xxxx," ; <== PARAM111
72 ; Search ARG of "xxxx(REG)," ; <== PARAM130
73 ; Search ARG of ",&xxxx" ; <== PARAM111 <== PARAM20
74 ; Search ARG of ",xxxx(REG)" ; <== PARAM210
75 PUSHM #2,S ; PUSHM S,T as OPCODE, OPCODEADR
76 ASMtoFORTH ; -- separator search word first
77 .word WORDD,FIND ; -- addr
78 .word QTBRAN,ARGWORD ; -- addr if Word found
80 .word QFBRAN,NotFound ; -- addr ABORT if not found
81 .word SearchEnd ; -- value goto SearchEnd if number found
82 ARGWORD .word $+2 ; -- CFA
83 MOV @TOS+,S ; -- PFA S=DOxxx
84 QDOVAR SUB #DOVAR,S ; DOVAR = 1287h
85 ISDOVAR JZ SearchEnd ; -- adr
86 QDOCON ADD #1,S ; DOCON = 1286h
87 ISNOTDOCON JNZ QDODOES ;
88 ISDOCON MOV @TOS,TOS ; -- cte
91 ADD #1,S ; DODOES = 1285h
92 ISDODOES JZ SearchEnd ; -- BODY leave BODY address for DOES words
93 ISOTHER SUB #4,TOS ; -- CFA leave execute adr
94 SearchEnd POPM #2,S ; POPM T,S
97 ; ----------------------------------------------------------------------
98 ; DTCforthMSP430FR5xxx ASSEMBLER : search REG
99 ; ----------------------------------------------------------------------
101 ; compute arg of "xxxx(REG)," ; <== PARAM130, sep=','
102 ; compute arg of ",xxxx(REG)" ; <== PARAM210, sep=' '
103 ComputeARGpREG ; sep -- Rn
104 MOV #'(',TOS ; -- "(" as WORD separator to find xxxx of "xxxx(REG),"
105 CALL #SearchARG ; -- xxxx aborted if not found
108 MOV TOS,0(X) ; -- xxxx compile xxxx
109 MOV #')',TOS ; -- ")" prepare separator to search REG of "xxxx(REG)"
111 ; search REG of "xxxx(REG)," separator = ')'
112 ; search REG of ",xxxx(REG)" separator = ')'
113 ; search REG of "@REG," separator = ',' <== PARAM120
114 ; search REG of "@REG+," separator = '+' <== PARAM121
115 ; search REG of "REG," separator = ',' <== PARAM13
116 ; search REG of ",REG" separator = BL <== PARAM21
118 SearchREG PUSHM #2,S ; PUSHM S,T as OPCODE, OPCODEADR
119 CMP &SOURCE_LEN,&TOIN ; bad case of ,xxxx without prefix &
121 MOV #BAD_CSP,PC ; génère une erreur bidon
122 SearchREG1 PUSH &TOIN ; -- sep save >IN
123 ADD #1,&TOIN ; skip "R"
124 ASMtoFORTH ; search xx of Rxx
125 .word WORDD,QNUMBER ;
126 .word QFBRAN,NOTaREG ; -- xxxx if Not a Number
127 .word $+2 ; -- Rn number is found
128 ADD #2,RSP ; remove >IN
130 JC BOUNDERROR ; abort if Rn out of bounds
131 JNC SearchEnd ; -- Rn
133 NOTaREG .word $+2 ; -- addr Z=1
134 MOV @RSP+,&TOIN ; -- addr restore >IN
135 JMP SearchEnd ; -- addr Z=1 ==> not a register
137 ; ----------------------------------------------------------------------
138 ; DTCforthMSP430FR5xxx ASSEMBLER : INTERPRET FIRST OPERAND
139 ; ----------------------------------------------------------------------
141 ; PARAM1 separator -- ; parse input buffer until separator and compute first operand of opcode
142 ; sep is comma for src and space for dst .
143 PARAM1 mDOCOL ; -- sep OPCODES types I|V sep = ',' OPCODES types II|VI sep = ' '
144 .word FBLANK,SKIP ; -- sep addr
145 .word $+2 ; -- sep addr
146 MOV #0,S ; -- sep addr reset OPCODE
147 MOV &DDP,T ; -- sep addr HERE --> OPCODEADR (opcode is preset to its address !)
148 ADD #2,&DDP ; -- sep addr cell allot for opcode
149 MOV.B @TOS,W ; -- sep addr W=first char of instruction code
150 MOV @PSP+,TOS ; -- sep W=c-addr
151 CMP.B #'#',W ; -- sep W=first char
153 ; "#" found : case of "#xxxx,"
154 PARAM10 ADD #1,&TOIN ; -- sep skip # prefix
155 CALL #SearchARG ; -- xxxx abort if not found
156 MOV #0300h,S ; OPCODE = 0300h : MOV #0,dst is coded MOV R3,dst
157 CMP #0,TOS ; -- xxxx #0 ?
159 MOV #0310h,S ; OPCODE = 0310h : MOV #1,dst is coded MOV 0(R3),dst
160 CMP #1,TOS ; -- xxxx #1 ?
162 MOV #0320h,S ; OPCODE = 0320h : MOV #2,dst is coded MOV @R3,dst
163 CMP #2,TOS ; -- xxxx #2 ?
165 MOV #0220h,S ; OPCODE = 0220h : MOV #4,dst is coded MOV @R2,dst
166 CMP #4,TOS ; -- xxxx #4 ?
168 MOV #0230h,S ; OPCODE = 0230h : MOV #8,dst is coded MOV @R2+,dst
169 CMP #8,TOS ; -- xxxx #8 ?
171 MOV #0330h,S ; -- -1 OPCODE = 0330h : MOV #-1,dst is coded MOV @R3+,dst
172 CMP #-1,TOS ; -- xxxx #-1 ?
174 MOV #0030h,S ; -- xxxx for all other cases : MOV @PC+,dst
175 ; case of "&xxxx," ; <== PARAM110
176 ; case of ",&xxxx" ; <== PARAM20
177 StoreArg MOV &DDP,X ;
178 ADD #2,&DDP ; cell allot for arg
179 StoreTOS ; <== TYPE1DOES
180 MOV TOS,0(X) ; compile arg
181 ; endcase of all "&xxxx" ;
182 ; endcase of all "#xxxx" ; <== PARAM101,102,104,108,10M1
183 ; endcase of all "REG"|"@REG"|"@REG+" <== PARAM124
184 PARAMENDOF MOV @PSP+,TOS ; --
186 MOV @IP+,PC ; -- S=OPCODE,T=OPCODEADR
187 ; ----------------------------------;
188 PARAM11 CMP.B #'&',W ; -- sep
190 ; case of "&xxxx," ; -- sep search for "&xxxx,"
191 PARAM110 MOV #0210h,S ; -- sep set code type : xxxx(SR) with AS=0b01 ==> x210h (and SR=0 !)
193 ; case of ",&xxxx" ; <== PARAM20
194 PARAM111 ADD #1,&TOIN ; -- sep skip "&" prefix
195 CALL #SearchARG ; -- arg abort if not found
196 JMP StoreArg ; -- then ret
197 ; ----------------------------------;
198 PARAM12 CMP.B #'@',W ; -- sep
200 ; case of "@REG,"|"@REG+,"
201 PARAM120 MOV #0020h,S ; -- sep init OPCODE with indirect code type : AS=0b10
202 ADD #1,&TOIN ; -- sep skip "@" prefix
203 CALL #SearchREG ; Z = not found
204 JNZ PARAM123 ; -- value REG of "@REG," found
205 ; case of "@REG+," ; -- addr REG of "@REG" not found, search REG of "@REG+"
206 PARAM121 ADD #0010h,S ; change OPCODE from @REG to @REG+ type
207 MOV #'+',TOS ; -- "+" as WORD separator to find REG of "@REG+,"
208 CALL #SearchREG ; -- value|addr X = flag
210 ; case of "xxxx(REG)," ; <== PARAM130
211 ; case of double separator: +, and ),
212 PARAM122 CMP &SOURCE_LEN,&TOIN ; test OPCODE II parameter ending by REG+ or (REG) without comma,
213 JZ PARAM123 ; i.e. >IN = SOURCE_LEN : don't skip char CR !
214 ADD #1,&TOIN ; -- 000R skip "," ready for the second operand search
216 ; case of "xxxx(REG),"
217 ; case of "@REG," ; -- 000R <== PARAM120
218 ; case of "REG," ; -- 000R <== PARAM13
219 PARAM123 SWPB TOS ; -- 0R00 swap bytes because it's not a dst REG typeI (not a 2 ops inst.)
220 ; case of "@REG+," ; -- 0R00 (src REG typeI)
221 ; case of "xxxx(REG)," ; -- 0R00 (src REG typeI or dst REG typeII)
222 ; case of "@REG," ; -- 0R00 (src REG typeI)
223 ; case of "REG," ; -- 0R00 (src REG typeI or dst REG typeII)
224 ; case of ",REG" ; -- 000R <== PARAM21 (dst REG typeI)
225 ; case of ",xxxx(REG)" ; -- 000R <== PARAM210 (dst REG typeI)
226 PARAM124 ADD TOS,S ; -- 0R00|000R
228 ; ----------------------------------;
229 ; case of "REG,"|"xxxx(REG)," ; first, searg REG of "REG,"
230 PARAM13 CALL #SearchREG ; -- sep save >IN for second parsing (case of "xxxx(REG),")
231 JNZ PARAM123 ; -- 000R REG of "REG," found, S=OPCODE=0
232 ; case of "xxxx(REG)," ; -- c-addr "REG," not found
233 PARAM130 ADD #0010h,S ; AS=0b01 for indexing address
234 CALL #ComputeARGpREG ; compile xxxx and search REG of "(REG)"
237 ; ----------------------------------------------------------------------
238 ; DTCforthMSP430FR5xxx ASSEMBLER : INTERPRET 2th OPERAND
239 ; ----------------------------------------------------------------------
241 PARAM3 ; for OPCODES TYPE III
242 MOV #0,S ; init OPCODE=0
243 MOV &DDP,T ; T=OPCODEADR
244 ADD #2,&DDP ; make room for opcode
245 ; ----------------------------------;
246 PARAM2 mDOCOL ; parse input buffer until BL and compute this 2th operand
247 .word FBLANK,SKIP ; skip space(s) between "arg1," and "arg2" if any; use not S,T.
248 .word $+2 ; -- c-addr search for '&' of "&xxxx
250 MOV #20h,TOS ; -- ' ' as WORD separator to find xxxx of ",&xxxx"
251 JNE PARAM21 ; '&' not found
253 PARAM20 ADD #0082h,S ; change OPCODE : AD=1, dst = R2
254 JMP PARAM111 ; -- ' '
255 ; ----------------------------------;
256 ; case of ",REG"|",xxxx(REG) ; -- ' ' first, search REG of ",REG"
257 PARAM21 CALL #SearchREG ;
258 JNZ PARAM124 ; -- 000R REG of ",REG" found
259 ; case of ",xxxx(REG) ; -- addr REG not found
260 PARAM210 ADD #0080h,S ; set AD=1
261 CALL #ComputeARGpREG ; compile argument xxxx and search REG of "(REG)"
262 JMP PARAM124 ; -- 000R REG of "(REG) found
264 ; ----------------------------------------------------------------------
265 ; DTCforthMSP430FR5xxx ASSEMBLER: OPCODES TYPE 0 : zero operand f:-)
266 ; ----------------------------------------------------------------------
269 .word lit,1300h,COMMA,EXIT
271 ; ----------------------------------------------------------------------
272 ; DTCforthMSP430FR5xxx ASSEMBLER: OPCODES TYPE I : double operand
273 ; ----------------------------------------------------------------------
275 ; OPCODE(code) for TYPE I = 0bxxxx opcode I
277 ; = 0bxxxx src register
278 ; OPCODE(7) AD (dst addr type)
282 ; OPCODE(B) for TYPE I or TYPE II = 0b0 word
284 ; OPCODE(54) AS (src addr type)
285 ; OPCODE(AS) for TYPE I or OPCODE(AD) for TYPE II = 0b00 register
290 ; OPCODE(dst) for TYPE I or TYPE II = 0bxxxx dst register
291 ; ----------------------------------------------------------------------
293 TYPE1DOES .word lit,',',PARAM1 ; -- BODYDOES
294 .word PARAM2 ; -- BODYDOES char separator (BL) included in PARAM2
296 MAKEOPCODE MOV T,X ; -- opcode X= OPCODEADR to compile opcode
297 MOV @TOS,TOS ; -- opcode part of instruction
298 BIS S,TOS ; -- opcode opcode is complete
299 JMP StoreTOS ; -- then EXIT
303 .word TYPE1DOES,4000h
306 .word TYPE1DOES,4040h
309 .word TYPE1DOES,5000h
312 .word TYPE1DOES,5040h
315 .word TYPE1DOES,6000h
318 .word TYPE1DOES,6040h
321 .word TYPE1DOES,7000h
324 .word TYPE1DOES,7040h
327 .word TYPE1DOES,8000h
330 .word TYPE1DOES,8040h
333 .word TYPE1DOES,9000h
336 .word TYPE1DOES,9040h
339 .word TYPE1DOES,0A000h
342 .word TYPE1DOES,0A040h
345 .word TYPE1DOES,0B000h
348 .word TYPE1DOES,0B040h
351 .word TYPE1DOES,0C000h
354 .word TYPE1DOES,0C040h
357 .word TYPE1DOES,0D000h
360 .word TYPE1DOES,0D040h
363 .word TYPE1DOES,0E000h
366 .word TYPE1DOES,0E040h
369 .word TYPE1DOES,0F000h
372 .word TYPE1DOES,0F040h
374 ; ----------------------------------------------------------------------
375 ; DTCforthMSP430FR5xxx ASSEMBLER, OPCODES TYPE II : single operand
376 ; ----------------------------------------------------------------------
377 ; OPCODE(FEDCBA987) opcodeII
378 ; OPCODE(code) for TYPE II = 0bxxxxxxxxx
380 ; OPCODE(B) for TYPE I or TYPE II = 0b0 word
382 ; OPCODE(54) (dst addr type)
383 ; OPCODE(AS) for TYPE I or OPCODE(AD) for TYPE II = 0b00 register
388 ; OPCODE(dst) for TYPE I or TYPE II = 0bxxxx dst register
389 ; ----------------------------------------------------------------------
391 TYPE2DOES .word FBLANK,PARAM1 ; -- BODYDOES
394 AND #0070h,S ; keep B/W & AS infos in OPCODE
395 SWPB W ; (REG org --> REG dst)
396 AND #000Fh,W ; keep REG
397 BIS_ASMTYPE BIS W,S ; -- BODYDOES add it in OPCODE
398 JMP MAKEOPCODE ; -- then end
400 asmword "RRC" ; Rotate Right through Carry ( word)
402 .word TYPE2DOES,1000h
403 asmword "RRC.B" ; Rotate Right through Carry ( byte)
405 .word TYPE2DOES,1040h
406 asmword "SWPB" ; Swap bytes
408 .word TYPE2DOES,1080h
411 .word TYPE2DOES,1100h
414 .word TYPE2DOES,1140h
417 .word TYPE2DOES,1180h
420 .word TYPE2DOES,1200h
423 .word TYPE2DOES,1240h
426 .word TYPE2DOES,1280h
428 BOUNDERRWM1 ADD #1,W ; <== RRAM|RRUM|RRCM|RLAM error
429 BOUNDERRORW MOV W,TOS ; <== PUSHM|POPM|ASM_branch error
430 BOUNDERROR ; <== REG number error
431 mDOCOL ; -- n n = value out of bounds
433 .byte 13,"out of bounds"
436 ; ----------------------------------------------------------------------
437 ; DTCforthMSP430FR5xxx ASSEMBLER, CONDITIONAL BRANCHS
438 ; ----------------------------------------------------------------------
439 ; ASSEMBLER FORTH OPCODE(FEDC)
440 ; OPCODE(code) for TYPE JNE,JNZ 0<>, <> = 0x20xx + (offset AND 3FF) ; branch if Z = 0
441 ; OPCODE(code) for TYPE JEQ,JZ 0=, = = 0x24xx + (offset AND 3FF) ; branch if Z = 1
442 ; OPCODE(code) for TYPE JNC,JLO U< = 0x28xx + (offset AND 3FF) ; branch if C = 0
443 ; OPCODE(code) for TYPE JC,JHS U>= = 0x2Cxx + (offset AND 3FF) ; branch if C = 1
444 ; OPCODE(code) for TYPE JN 0< = 0x30xx + (offset AND 3FF) ; branch if N = 1
445 ; OPCODE(code) for TYPE JGE >= = 0x34xx + (offset AND 3FF) ; branch if (N xor V) = 0
446 ; OPCODE(code) for TYPE JL < = 0x38xx + (offset AND 3FF) ; branch if (N xor V) = 1
447 ; OPCODE(code) for TYPE JMP = 0x3Cxx + (offset AND 3FF)
449 asmword "S>=" ; if >= assertion (opposite of jump if < )
453 asmword "S<" ; if < assertion
457 asmword "0>=" ; if 0>= assertion ; use only with IF UNTIL WHILE !
461 asmword "0<" ; jump if 0< ; use only with ?GOTO !
465 asmword "U<" ; if U< assertion
469 asmword "U>=" ; if U>= assertion
473 asmword "0<>" ; if <>0 assertion
477 asmword "0=" ; if =0 assertion
481 ;ASM IF OPCODE -- @OPCODE1
484 MOV TOS,0(W) ; compile incomplete opcode
489 ;ASM THEN @OPCODE -- resolve forward branch
491 ASM_THEN MOV &DDP,W ; -- @OPCODE W=dst
492 MOV TOS,Y ; Y=@OPCODE
493 ASM_THEN1 MOV @PSP+,TOS ; --
495 ADD #2,X ; -- Y=@OPCODE W=dst X=src+2
496 SUB X,W ; -- Y=@OPCODE W=dst-src+2=displacement*2 (bytes)
497 RRA W ; -- Y=@OPCODE W=displacement (words)
499 JC BOUNDERRORW ; (JHS) unsigned branch if u> 511
500 BIS W,0(Y) ; -- [@OPCODE]=OPCODE completed
503 ; ELSE @OPCODE1 -- @OPCODE2 branch for IF..ELSE
505 ASM_ELSE MOV &DDP,W ; -- W=HERE
506 MOV #3C00h,0(W) ; compile unconditionnal branch
507 ADD #2,&DDP ; -- DP+2
509 MOV W,0(PSP) ; -- @OPCODE2 @OPCODE1
510 JMP ASM_THEN ; -- @OPCODE2
512 ; BEGIN -- BEGINadr initialize backward branch
516 ; UNTIL @BEGIN OPCODE -- resolve conditional backward branch
518 ASM_UNTIL MOV @PSP+,W ; -- OPCODE W=@BEGIN
519 ASM_UNTIL1 MOV TOS,Y ; Y=OPCODE W=@BEGIN
520 ASM_UNTIL2 MOV @PSP+,TOS ; --
521 MOV &DDP,X ; -- Y=OPCODE X=HERE W=dst
522 SUB #2,W ; -- Y=OPCODE X=HERE W=dst-2
523 SUB X,W ; -- Y=OPCODE X=src W=src-dst-2=displacement (bytes)
524 RRA W ; -- Y=OPCODE X=HERE W=displacement (words)
526 JL BOUNDERRORW ; signed branch if < -512
527 AND #3FFh,W ; -- Y=OPCODE X=HERE W=troncated negative displacement (words)
528 BIS W,Y ; -- Y=OPCODE (completed)
533 ; AGAIN @BEGIN -- uncond'l backward branch
534 ; unconditional backward branch
536 ASM_AGAIN MOV TOS,W ; W=@BEGIN
537 MOV #3C00h,Y ; Y = asmcode JMP
540 ; WHILE @BEGIN OPCODE -- @WHILE @BEGIN
542 ASM_WHILE mDOCOL ; -- @BEGIN OPCODE
543 .word ASM_IF,SWAP,EXIT
545 ; REPEAT @WHILE @BEGIN -- resolve WHILE loop
547 ASM_REPEAT mDOCOL ; -- @WHILE @BEGIN
548 .word ASM_AGAIN,ASM_THEN,EXIT
550 ; ------------------------------------------------------------------------------------------
551 ; DTCforthMSP430FR5xxx ASSEMBLER : branch up to 3 backward labels and up to 3 forward labels
552 ; ------------------------------------------------------------------------------------------
553 ; used for non canonical branchs, as BASIC language: "goto line x"
554 ; labels BWx and FWx must be respectively set and used at the beginning of line (>IN < 8).
555 ; FWx at the beginning of a line can resolve only one previous GOTO|?GOTO FWx.
556 ; BWx at the beginning of a line can be resolved by any subsequent GOTO|?GOTO BWx.
558 ;BACKWDOES FORTHtoASM
561 ; MOV TOS,Y ; Y = ASMBWx
563 ; MOV @Y,W ; W = [ASMBWx]
564 ; CMP #8,&TOIN ; are we colon 8 or more ?
565 ;BACKWUSE JHS ASM_UNTIL1 ; yes, use this label
566 ;BACKWSET MOV &DDP,0(Y) ; no, set LABEL = DP
573 ; .word ASMBW1 ; in RAM
577 MOV TOS,Y ; -- PFA Y = ASMBWx addr
580 CMP #8,&TOIN ; are we colon 8 or more ?
581 BACKWUSE JC ASM_UNTIL1 ; yes, use this label
582 BACKWSET MOV &DDP,0(Y) ; no, set LABEL = DP
605 ; MOV @TOS,Y ; -- PFA Y= ASMFWx
606 ; CMP #8,&TOIN ; are we colon 8 or more ?
607 ;FORWUSE JNC ASM_THEN1 ; no: resolve FWx with W=DDP, Y=ASMFWx
608 ;FORWSET MOV @PSP+,0(W) ; yes compile incomplete opcode
609 ; ADD #2,&DDP ; increment DDP
610 ; MOV W,0(TOS) ; store @OPCODE into ASMFWx
618 ; .word ASMFW1 ; in RAM
623 MOV @TOS,Y ; -- PFA Y=[BODY]=ASMFWx
624 CMP #8,&TOIN ; are we colon 8 or more ?
625 FORWUSE JNC ASM_THEN1 ; no: resolve FWx with W=DDP, Y=ASMFWx
626 FORWSET MOV @PSP+,0(W) ; yes compile incomplete opcode
627 ADD #2,&DDP ; increment DDP
628 MOV W,0(TOS) ; store @OPCODE into ASMFWx
648 ;ASM GOTO <label> -- unconditionnal branch to label
652 MOV #3C00h,TOS ; -- JMP_OPCODE
654 .word TICK ; -- OPCODE CFA<label>
657 ;ASM <cond> ?GOTO <label> OPCODE -- conditionnal branch to label
659 INVJMP CMP #3000h,TOS ; invert code jump process
660 JZ GOTONEXT ; case of JN, do nothing
661 XOR #0400h,TOS ; case of: JNZ<-->JZ JNC<-->JC JL<-->JGE
662 BIT #1000h,TOS ; 3xxxh case ?
664 XOR #0800h,TOS ; complementary action for JL<-->JGE
667 ; --------------------------------------------------------------------------------
668 ; DTCforthMSP430FR5xxx ASSEMBLER, OPCODES TYPE III : PUSHM|POPM|RLAM|RRAM|RRUM|RRCM
669 ; --------------------------------------------------------------------------------
670 ; PUSHM, syntax: PUSHM #n,REG with 0 < n < 17
671 ; POPM syntax: POPM #n,REG with 0 < n < 17
674 ; PUSHM order : PSP,TOS, IP, S, T, W, X, Y, rEXIT,rDOVAR,rDOCON, rDODOES, R3, SR,RSP, PC
675 ; PUSHM order : R15,R14,R13,R12,R11,R10, R9, R8, R7 , R6 , R5 , R4 , R3, R2, R1, R0
677 ; example : PUSHM #6,IP pushes IP,S,T,W,X,Y registers to return stack
679 ; POPM order : PC,RSP, SR, R3, rDODOES,rDOCON,rDOVAR,rEXIT, Y, X, W, T, S, IP,TOS,PSP
680 ; POPM order : R0, R1, R2, R3, R4 , R5 , R6 , R7 , R8, R9,R10,R11,R12,R13,R14,R15
682 ; example : POPM #6,IP pulls Y,X,W,T,S,IP registers from return stack
684 ; RxxM syntax: RxxM #n,REG with 0 < n < 5
686 TYPE3DOES .word FBLANK,SKIP ; skip spaces if any
687 .word $+2 ; -- BODYDOES c-addr
688 ADD #1,&TOIN ; skip "#"
689 MOV #',',TOS ; -- BODYDOES ","
692 .word QFBRAN,NotFound ; ABORT
693 .word PARAM3 ; -- BODYDOES 0x000N S=OPCODE = 0x000R
695 MOV TOS,W ; -- BODYDOES n W = n
696 MOV @PSP+,TOS ; -- BODYDOES
697 SUB #1,W ; W = n floored to 0
699 MOV @TOS,X ; X=OPCODE
700 RLAM #4,X ; OPCODE bit 1000h --> C
701 JNC RxxMINSTRU ; if bit 1000h = 0
702 PxxxINSTRU MOV S,Y ; S=REG, Y=REG to test
703 RLAM #3,X ; OPCODE bit 0200h --> C
704 JNC PUSHMINSTRU ; W=n-1 Y=REG
705 POPMINSTRU SUB W,S ; to make POPM opcode, compute first REG to POP; TI is complicated....
706 PUSHMINSTRU SUB W,Y ; Y=REG-(n-1)
708 JC BOUNDERRWM1 ; JC=JHS (U>=)
709 RLAM #4,W ; W = n << 4
710 JMP BIS_ASMTYPE ; BODYDOES --
711 RxxMINSTRU CMP #4,W ;
712 JC BOUNDERRWM1 ; JC=JHS (U>=)
713 SWPB W ; -- BODYDOES W = n << 8
714 RLAM #2,W ; W = N << 10
715 JMP BIS_ASMTYPE ; BODYDOES --
719 .word TYPE3DOES,0050h
722 .word TYPE3DOES,0150h
725 .word TYPE3DOES,0250h
728 .word TYPE3DOES,0350h
731 .word TYPE3DOES,1500h
734 .word TYPE3DOES,1700h
740 .word TYPE3DOES,0040h
743 .word TYPE3DOES,0140h
746 .word TYPE3DOES,0240h
749 .word TYPE3DOES,0340h
752 .word TYPE3DOES,1400h
755 .word TYPE3DOES,1600h
757 ; --------------------------------------------------------------------------------
758 ; DTCforthMSP430FR5xxx ASSEMBLER: OPCODE TYPE III bis: CALLA (without extended word)
759 ; --------------------------------------------------------------------------------
760 ; absolute and immediate instructions must be written as $x.xxxx (DOUBLE numbers with dot)
761 ; indexed instructions must be written as $.xxxx(REG) (DOUBLE numbers with dot)
762 ; --------------------------------------------------------------------------------
763 ; may be usefull to access ROM libraries beyond $FFFF
764 ; --------------------------------------------------------------------------------
768 .word FBLANK,SKIP ; -- addr
771 ADD #2,&DDP ; make room for opcode
772 MOV.B @TOS,TOS ; -- char First char of opcode
773 CALLA0 MOV #134h,S ; 134h<<4 = 1340h = opcode for CALLA Rn
776 CALLA01 MOV.B #' ',TOS ;
777 CALLA02 CALL #SearchREG ; -- Rn
778 CALLA03 RLAM #4,S ; (opcode>>4)<<4 = opcode
779 BIS TOS,S ; update opcode
780 MOV S,0(T) ; store opcode
784 ;-----------------------------------;
785 CALLA1 ADD #2,S ; 136h<<4 = opcode for CALLA @REG
786 CMP.B #'@',TOS ; -- char Search @REG
788 ADD #1,&TOIN ; skip '@'
789 MOV.B #' ',TOS ; -- ' '
791 JNZ CALLA03 ; if REG found, update opcode
792 ;-----------------------------------;
793 ADD #1,S ; 137h<<4 = opcode for CALLA @REG+
794 MOV #'+',TOS ; -- '+'
796 ;-----------------------------------;
797 CALLA2 ADD #2,&DDP ; make room for xxxx of #$x.xxxx|&$x.xxxx|$0.xxxx(REG)
800 MOV #13Bh,S ; 13Bh<<4 = opcode for CALLA #$x.xxxx
801 CALLA21 ADD #1,&TOIN ; skip '#'|'&'
802 CALLA22 CALL #SearchARG ; -- Lo Hi
803 MOV @PSP+,2(T) ; -- Hi store #$xxxx|&$xxxx
804 JMP CALLA03 ; update opcode with $x. and store opcode
805 ;-----------------------------------;
806 CALLA3 CMP.B #'&',TOS
808 ADD #2,S ; 138h<<4 = opcode for CALLA &$x.xxxx
810 ;-----------------------------------;
811 CALLA4 MOV.B #'(',TOS ; -- "("
812 SUB #1,S ; 135h<<4 = opcode for CALLA $0.xxxx(REG)
813 CALLA41 CALL #SearchARG ; -- Lo Hi
814 MOV @PSP+,2(T) ; -- Hi store $xxxx
815 MOV #')',TOS ; -- ')'
816 JMP CALLA02 ; search Rn and update opcode
818 ; ===============================================================
819 ; to allow data access beyond $FFFF
820 ; ===============================================================
822 ; MOVA (#$x.xxxx|&$x.xxxx|$.xxxx(Rs)|Rs|@Rs|@Rs+ , &|Rd|$.xxxx(Rd))
823 ; ADDA (#$x.xxxx|Rs , Rd)
824 ; CMPA (#$x.xxxx|Rs , Rd)
825 ; SUBA (#$x.xxxx|Rs , Rd)
827 ; first argument process ACMS1
828 ;-----------------------------------;
829 ACMS1 mDOCOL ; -- BODYDOES ','
830 .word FBLANK,SKIP ; -- BODYDOES ',' addr
832 MOV.B @TOS,X ; X=first char of opcode string
833 MOV @PSP+,TOS ; -- BODYDOES ','
834 MOV @PSP+,S ; -- ',' S=BODYDOES
837 ADD #2,&DDP ; make room for opcode
838 ;-----------------------------------;
839 ACMS10 CMP.B #'R',X ; -- ','
841 ACMS101 CALL #SearchREG ; -- Rn src
842 ACMS102 RLAM #4,TOS ; 8<<src
844 ACMS103 BIS S,TOS ; update opcode with src|dst
845 MOV TOS,0(T) ; save opcode
846 MOV T,TOS ; -- OPCODE_addr
848 ;-----------------------------------;
849 ACMS11 CMP.B #'#',X ; -- ',' X=addr
851 BIC #40h,S ; set #opcode
852 ACMS111 ADD #1,&TOIN ; skip '#'|'&'
853 ADD #2,&DDP ; make room for low #$xxxx|&$xxxx|$xxxx(REG)
854 CALL #SearchARG ; -- Lo Hi
855 MOV @PSP+,2(T) ; -- Hi store $xxxx of #$x.xxxx|&$x.xxxx|$x.xxxx(REG)
856 AND #0Fh,TOS ; -- Hi sel Hi src
858 ;-----------------------------------;
859 MOVA12 CMP.B #'&',X ; -- ',' case of MOVA &$x.xxxx
861 XOR #00E0h,S ; set MOVA &$x.xxxx, opcode
863 ;-----------------------------------;
864 MOVA13 BIC #00F0h,S ; set MOVA @REG, opcode
865 CMP.B #'@',X ; -- ','
867 ADD #1,&TOIN ; skip '@'
868 CALL #SearchREG ; -- Rn
869 JNZ ACMS102 ; if @REG found
870 ;-----------------------------------;
871 BIS #0010h,S ; set @REG+ opcode
872 MOV #'+',TOS ; -- '+'
873 MOVA131 CALL #SearchREG ; -- Rn case of MOVA @REG+,|MOVA $x.xxxx(REG),
874 CMP &SOURCE_LEN,&TOIN ; test TYPE II first parameter ending by @REG+ (REG) without comma,
875 JZ ACMS102 ; i.e. may be >IN = SOURCE_LEN: don't skip char CR !
876 ADD #1,&TOIN ; skip "," ready for the second operand search
878 ;-----------------------------------;
879 MOVA14 BIS #0030h,S ; set xxxx(REG), opcode
880 ADD #2,&DDP ; -- ',' make room for first $xxxx of $0.xxxx(REG),
881 MOV #'(',TOS ; -- "(" as WORD separator to find xxxx of "xxxx(REG),"
882 CALL #SearchARG ; -- Lo Hi
883 MOV @PSP+,2(T) ; -- Hi store $xxxx as 2th word
884 MOV #')',TOS ; -- ')'
887 ; 2th argument process ACMS2
888 ;-----------------------------------;
889 ACMS2 mDOCOL ; -- OPCODE_addr
890 .word FBLANK,SKIP ; -- OPCODE_addr addr
892 MOV @PSP+,T ; -- addr T=OPCODE_addr
894 MOV.B @TOS,X ; -- addr X=first char of string instruction
895 MOV.B #' ',TOS ; -- ' '
896 ;-----------------------------------;
897 ACMS21 CMP.B #'R',X ; -- ' '
899 ACMS211 CALL #SearchREG ; -- Rn
901 ;-----------------------------------;
903 ADD #2,&DDP ; -- ' ' make room for $xxxx
906 BIS #060h,S ; set ,&$x.xxxx opcode
907 ADD #1,&TOIN ; skip '&'
908 CALL #SearchARG ; -- Lo Hi
909 MOV @PSP+,2(T) ; -- Hi store $xxxx as 2th word
910 JMP ACMS103 ; update opcode with dst $x and write opcode
911 ;-----------------------------------;
912 MOVA23 BIS #070h,S ; set ,xxxx(REG) opcode
913 MOV #'(',TOS ; -- "(" as WORD separator to find xxxx of "xxxx(REG),"
914 CALL #SearchARG ; -- Lo Hi
915 MOV @PSP+,2(T) ; -- Hi write $xxxx of ,$0.xxxx(REG) as 2th word
916 MOV #')',TOS ; -- ")" as WORD separator to find REG of "xxxx(REG),"
919 ; --------------------------------------------------------------------------------
920 ; DTCforthMSP430FR5xxx ASSEMBLER, OPCODES IV 2 operands: Adda|Cmpa|Mova|Suba (without extended word)
921 ; --------------------------------------------------------------------------------
922 ; absolute and immediate instructions must be written as $x.xxxx (DOUBLE numbers)
923 ; indexed instructions must be written as $.xxxx(REG) (DOUBLE numbers)
924 ; --------------------------------------------------------------------------------
926 TYPE4DOES .word lit,',' ; -- BODYDOES "," char separator for PARAM1
927 .word ACMS1 ; -- OPCODE_addr
928 .word ACMS2 ; -- OPCODE_addr
933 .word TYPE4DOES,00C0h
936 .word TYPE4DOES,00D0h
939 .word TYPE4DOES,00E0h
942 .word TYPE4DOES,00F0h
944 .ENDIF ; EXTENDED_MEM