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 : STRUCTURE
48 ; ----------------------------------------------------------------------
50 ;X ASSEMBLER -- ; set ASSEMBLER the first context vocabulary
53 .ENDIF ; VOCABULARY_SET
54 ASSEMBLER mDODOES ; leave BODYASSEMBLER on the stack and run VOCDOES
56 BODYASSEMBLER .word lastasmword ; here is the structure created by VOCABULARY
125 FORTHWORDIMM "HI2LO" ; immediate, switch to low level, add ASSEMBLER context, set interpretation state
127 HI2LO .word HERE,CELLPLUS,COMMA
129 HI2LONEXT .word ALSO,ASSEMBLER
132 ; FORTHWORDIMM "SEMIC" ; same as HI2LO, plus restore IP; counterpart of COLON
135 ; .word LIT,413Dh,COMMA ; compile MOV @RSP+,IP
138 FORTHWORD "CODE" ; a CODE word must be finished with ENDCODE
139 ASMCODE CALL #HEADER ;
146 asmword "ENDCODE" ; restore previous context and test PSP balancing
148 .word PREVIOUS,QREVEAL
151 FORTHWORD "ASM" ; used to define an assembler word which is not executable by FORTH interpreter
152 ; i.e. typically an assembler word called by CALL and ended by RET
153 ; ASM words are only usable in another ASSEMBLER words
154 ; an ASM word must be finished with ENDASM
155 MOV &CURRENT,&SAV_CURRENT
156 MOV #BODYASSEMBLER,&CURRENT
159 asmword "ENDASM" ; end of an ASM word
160 MOV &SAV_CURRENT,&CURRENT
164 asmword "COLON" ; compile DOCOL, remove ASSEMBLER from CONTEXT, switch to compilation state
169 MOV #DOCOL1,0(W) ; compile CALL xDOCOL
173 MOV #DOCOL1,0(W) ; compile PUSH IP
174 COLON1 MOV #DOCOL2,2(W) ; compile CALL rEXIT
177 .CASE 3 ; inlined DOCOL
178 MOV #DOCOL1,0(W) ; compile PUSH IP
179 COLON1 MOV #DOCOL2,2(W) ; compile MOV PC,IP
180 MOV #DOCOL3,4(W) ; compile ADD #4,IP
181 MOV #NEXT,6(W) ; compile MOV @IP+,PC
185 COLON2 MOV #-1,&STATE ; enter in compile state
186 MOV #PREVIOUS,PC ; restore previous state of CONTEXT
189 asmword "LO2HI" ; same as COLON but without saving IP
191 .CASE 1 ; compile 2 words
193 MOV #12B0h,0(W) ; compile CALL #EXIT, 2 words 4+6=10~
197 .ELSECASE ; CASE 2 : compile 1 word, CASE 3 : compile 3 words
198 SUB #2,&DDP ; to skip PUSH IP
205 FORTHWORD "CODENNM" ; CODENoNaMe is the assembly counterpart of :NONAME
207 .word COLONNONAME,LEFTBRACKET
210 SUB #4,W ; to remove DEFER snippet
218 ;;Z SKIP char -- addr ; skip all occurring character 'char' in input stream
219 ; FORTHWORD "SKIP" ; used by assembler to parse input stream
220 SKIP: MOV #SOURCE_LEN,Y ;
221 MOV @Y+,X ; -- char X=length
222 MOV @Y,W ; -- char X=length W=org
223 ADD W,X ; -- char X=End W=org
224 ADD &TOIN,W ; -- char X=End W=ptr
225 SKIPLOOP: CMP W,X ; -- char ptr=End ?
226 JZ SKIPEND ; -- char yes
227 CMP.B @W+,TOS ; -- char does character match?
228 JZ SKIPLOOP ; -- char yes
229 SKIPNEXT: SUB #1,W ; -- char
230 SKIPEND: MOV W,TOS ; -- addr
231 SUB @Y,W ; -- addr W=Ptr-Org=Toin
235 ; ----------------------------------------------------------------------
236 ; DTCforthMSP430FR5xxx ASSEMBLER : search argument "xxxx", IP is free
237 ; ----------------------------------------------------------------------
239 ; Search ARG of "#xxxx," ; <== PARAM10
240 ; Search ARG of "&xxxx," ; <== PARAM111
241 ; Search ARG of "xxxx(REG)," ; <== PARAM130
242 ; Search ARG of ",&xxxx" ; <== PARAM111 <== PARAM20
243 ; Search ARG of ",xxxx(REG)" ; <== PARAM210
244 SearchARG PUSHM #2,S ; PUSHM S,T
245 ASMtoFORTH ; -- separator search word first
246 .word WORDD,FIND ; -- c-addr
247 .word QZBRAN,SearchARGW ; -- c-addr if found
249 .word QBRAN,NotFound ; -- c-addr ABORT
250 .word SearchEnd ; -- value goto end if number found
251 SearchARGW FORTHtoASM ; -- xt xt = CFA
255 ADD #2,TOS ; remplace CFA by PFA for VARIABLE words
259 MOV 2(TOS),TOS ; remplace CFA by [PFA] for CONSTANT (and CREATEd) words
261 QDODOES CMP #DODOES,X
263 ADD #4,TOS ; leave BODY address for DOES words
264 SearchEnd POPM #2,S ; POPM T,S
267 ; ----------------------------------------------------------------------
268 ; DTCforthMSP430FR5xxx ASSEMBLER : search REG
269 ; ----------------------------------------------------------------------
271 ; compute "xxxx(REG)," ; <== PARAM130
272 ; compute ",xxxx(REG)" ; <== PARAM210
274 MOV #'(',TOS ; -- "(" as WORD separator to find xxxx of "xxxx(REG),"
275 CALL #SearchARG ; -- xxxx aborted if not found
278 MOV TOS,0(X) ; -- xxxx compile xxxx
279 MOV #')',TOS ; -- ")" prepare separator to search REG of "xxxx(REG)"
281 ; search REG of "xxxx(REG)," separator = ')' ;
282 ; search REG of ",xxxx(REG)" separator = ')' ;
283 ; search REG of "@REG," separator = ',' ; <== PARAM120
284 ; search REG of "@REG+," separator = '+' ; <== PARAM121
285 ; search REG of "REG," separator = ',' ; <== PARAM13
286 ; search REG of ",REG" separator = ' ' ; <== PARAM21
288 SearchREG PUSHM #2,S ; PUSHM S,T
289 PUSH &TOIN ; -- separator save >IN
290 ADD #1,&TOIN ; skip "R"
291 ASMtoFORTH ; search xx of Rxx
292 .word WORDD,QNUMBER ;
293 .word QBRAN,NOTaREG ; -- xxxx if Not a Number
294 FORTHtoASM ; -- c-addr number is found
295 ADD #2,RSP ; remove >IN
296 CMP #16,TOS ; -- 000R register > 15 ?
297 JHS BOUNDERROR ; yes : abort
298 JLO SearchEnd ; -- 000R Z=0 ==> found
300 NOTaREG FORTHtoASM ; -- c-addr Z=1
301 MOV @RSP+,&TOIN ; -- c-addr restore >IN
302 JMP SearchEnd ; -- c_addr Z=1 ==> not a register
305 ; ----------------------------------------------------------------------
306 ; DTCforthMSP430FR5xxx ASSEMBLER : INTERPRET FIRST OPERAND
307 ; ----------------------------------------------------------------------
309 ; PARAM1 separator -- ; parse input buffer until separator and compute first operand of opcode
310 ; sep is comma for src and space for dst .
312 PARAM1 mDOCOL ; -- sep
313 .word FBLANK,SKIP ; -- sep c-addr
314 FORTHtoASM ; -- sep c-addr
315 MOV #0,S ; -- sep c-addr reset ASMTYPE
316 MOV &DDP,T ; -- sep c-addr HERE --> OPCODEADR (opcode is preset to its address !)
317 ADD #2,&DDP ; -- sep c-addr cell allot for opcode
318 MOV TOS,W ; -- sep c-addr W=c-addr
319 MOV @PSP+,TOS ; -- sep W=c-addr
320 CMP.B #'#',0(W) ; -- sep W=c-addr
323 ; "#" found : case of "#xxxx,"
324 PARAM10 ADD #1,&TOIN ; -- sep skip # prefix
325 CALL #SearchARG ; -- xxxx abort if not found
327 PARAM100 CMP #0,TOS ; -- xxxx = 0 ?
330 MOV #0300h,S ; -- 0 example : MOV #0,dst <=> MOV R3,dst
333 PARAM101 CMP #1,TOS ; -- xxxx = 1 ?
336 MOV #0310h,S ; -- 1 example : MOV #1,dst <=> MOV 0(R3),dst
339 PARAM102 CMP #2,TOS ; -- xxxx = 2 ?
342 MOV #0320h,S ; -- 2 ASMTYPE = 0320h example : MOV #2, <=> MOV @R3,
345 PARAM104 CMP #4,TOS ; -- xxxx = 4 ?
348 MOV #0220h,S ; -- 4 ASMTYPE = 0220h example : MOV #4, <=> MOV @SR,
351 PARAM108 CMP #8,TOS ; -- xxxx = 8 ?
354 MOV #0230h,S ; -- 8 ASMTYPE = 0230h example : MOV #8, <=> MOV @SR+,
357 PARAM10M1 CMP #-1,TOS ; -- xxxx = -1 ?
360 MOV #0330h,S ; -- -1 ASMTYPE = 0330h example : XOR #-1 <=> XOR @R3+,
363 ; case of all others "#xxxx," ; -- xxxx
364 PARAM1000 MOV #0030h,S ; -- xxxx add immediate code type : @PC+,
366 ; case of "&xxxx," ; <== PARAM110
367 ; case of ",&xxxx" ; <== PARAM20
368 StoreArg MOV &DDP,X ; -- xxxx
369 ADD #2,&DDP ; cell allot for arg
371 StoreTOS ; <== TYPE1DOES
372 MOV TOS,0(X) ; compile arg
373 ; endcase of all "&xxxx" ;
374 ; endcase of all "#xxxx" ; <== PARAM101,102,104,108,10M1
375 ; endcase of all "REG"|"@REG"|"@REG+" ; <== PARAM124
376 PARAMENDOF MOV @PSP+,TOS ; --
379 ; ------------------------------------------
381 PARAM11 CMP.B #'&',0(W) ; -- sep
384 ; case of "&xxxx," ; -- sep search for "&xxxx,"
385 PARAM110 MOV #0210h,S ; -- sep set code type : xxxx(SR) with AS=0b01 ==> x210h (and SR=0 !)
388 ; case of ",&xxxx" ; <== PARAM20
389 PARAM111 ADD #1,&TOIN ; -- sep skip "&" prefix
390 CALL #SearchARG ; -- arg abort if not found
391 JMP StoreArg ; -- then ret
392 ; ------------------------------------------
394 PARAM12 CMP.B #'@',0(W) ; -- sep
397 ; case of "@REG,"|"@REG+,"
398 PARAM120 MOV #0020h,S ; -- sep init ASMTYPE with indirect code type : AS=0b10
399 ADD #1,&TOIN ; -- sep skip "@" prefix
400 CALL #SearchREG ; Z = not found
401 JNZ PARAM123 ; -- value REG of "@REG," found
403 ; case of "@REG+," ; -- c-addr REG of "@REG" not found, search REG of "@REG+"
404 PARAM121 ADD #0010h,S ; change ASMTYPE from @REG to @REG+ type
405 MOV #'+',TOS ; -- "+" as WORD separator to find REG of "@REG+,"
406 CALL #SearchREG ; -- value|c-addr X = flag
409 ; case of "xxxx(REG)," ; <== PARAM130
410 ; cases of double separator: +, and ),
411 PARAM122 CMP &SOURCE_LEN,&TOIN ; test OPCODE II parameter ending by REG+ or (REG) without comma,
412 JZ PARAM123 ; i.e. >IN = SOURCE_LEN : don't skip char CR !
413 ADD #1,&TOIN ; -- 000R skip "," ready for the second operand search
416 ; case of "xxxx(REG),"
417 ; case of "@REG," ; <== PARAM120
418 ; case of "REG," ; <== PARAM13
419 PARAM123 SWPB TOS ; 000R -- 0R00 swap bytes because it's not a dst REG typeI (not a 2 ops inst.)
421 ; case of "@REG+," ; -- 0R00 (src REG typeI)
422 ; case of "xxxx(REG)," ; -- 0R00 (src REG typeI or dst REG typeII)
423 ; case of "@REG," ; -- 0R00 (src REG typeI)
424 ; case of "REG," ; -- 0R00 (src REG typeI or dst REG typeII)
428 ; case of ",REG" ; -- 000R <== PARAM21 (dst REG typeI)
429 ; case of ",xxxx(REG)" ; -- 000R <== PARAM210 (dst REG typeI)
430 PARAM124 ADD TOS,S ; -- 0R00|000R
432 ; ------------------------------------------
434 ; case of "REG,"|"xxxx(REG)," ; first, searg REG of "REG,"
435 PARAM13 CALL #SearchREG ; -- sep save >IN for second parsing (case of "xxxx(REG),")
436 JNZ PARAM123 ; -- 000R REG of "REG," found, S=ASMTYPE=0
438 ; case of "xxxx(REG)," ; -- c-addr "REG," not found
439 PARAM130 ADD #0010h,S ; AS=0b01 for indexing address
440 CALL #ComputeARGparenREG ; compile xxxx and search REG of "(REG)"
443 ; ----------------------------------------------------------------------
444 ; DTCforthMSP430FR5xxx ASSEMBLER : INTERPRET 2th OPERAND
445 ; ----------------------------------------------------------------------
447 ; PARAM2 -- ; parse input buffer until BL and compute this 2th operand
449 .word FBLANK,SKIP ; skip space(s) between "arg1," and "arg2" if any; use not S,T.
450 FORTHtoASM ; -- c-addr search for '&' of "&xxxx
452 MOV #20h,TOS ; -- " " as WORD separator to find xxxx of ",&xxxx"
453 JNE PARAM21 ; '&' not found
456 PARAM20 ADD #0082h,S ; change ASMTYPE : AD=1, dst = R2
457 JMP PARAM111 ; -- " "
458 ; ------------------------------------------
460 ; case of ",REG"|",xxxx(REG) ; -- " " first, search REG of ",REG"
461 PARAM21 CALL #SearchREG ;
462 JNZ PARAM124 ; -- 000R REG of ",REG" found
464 ; case of ",xxxx(REG) ; -- c-addr REG not found
465 PARAM210 ADD #0080h,S ; set AD=1
466 CALL #ComputeARGparenREG ; compile argument xxxx and search REG of "(REG)"
467 JMP PARAM124 ; -- 000R REG of "(REG) found
470 ; ----------------------------------------------------------------------
471 ; DTCforthMSP430FR5xxx ASSEMBLER: OPCODES TYPE 0 : zero operand f:-)
472 ; ----------------------------------------------------------------------
475 .word lit,1300h,COMMA,EXIT
477 ; ----------------------------------------------------------------------
478 ; DTCforthMSP430FR5xxx ASSEMBLER: OPCODES TYPE I : double operand
479 ; ----------------------------------------------------------------------
481 ; OPCODE(code) for TYPE I = 0bxxxx opcode I
483 ; = 0bxxxx src register
484 ; OPCODE(7) AD (dst addr type)
488 ; OPCODE(B) for TYPE I or TYPE II = 0b0 word
490 ; OPCODE(54) AS (src addr type)
491 ; OPCODE(AS) for TYPE I or OPCODE(AD) for TYPE II = 0b00 register
496 ; OPCODE(dst) for TYPE I or TYPE II = 0bxxxx dst register
497 ; ----------------------------------------------------------------------
499 ; TYPE1DOES -- PFADOES search and compute PARAM1 & PARAM2 as src and dst operands then compile instruction
500 TYPE1DOES ; -- PFADOES
501 .word lit,',' ; -- PFADOES "," char separator for PARAM1
502 .word PARAM1 ; -- PFADOES
503 .word PARAM2 ; -- PFADOES char separator (BL) included in PARAM2
504 FORTHtoASM ; -- PFADOES
505 MAKEOPCODE MOV @TOS,TOS ; -- opcode part of instruction
506 BIS S,TOS ; -- opcode opcode is complete
507 MOV T,X ; -- opcode X= OPCODEADR to compile opcode
508 JMP StoreTOS ; then EXIT
512 .word TYPE1DOES,4000h
516 .word TYPE1DOES,4040h
520 .word TYPE1DOES,5000h
524 .word TYPE1DOES,5040h
528 .word TYPE1DOES,6000h
532 .word TYPE1DOES,6040h
536 .word TYPE1DOES,7000h
540 .word TYPE1DOES,7040h
544 .word TYPE1DOES,8000h
548 .word TYPE1DOES,8040h
552 .word TYPE1DOES,9000h
556 .word TYPE1DOES,9040h
560 .word TYPE1DOES,0A000h
564 .word TYPE1DOES,0A040h
568 .word TYPE1DOES,0B000h
572 .word TYPE1DOES,0B040h
576 .word TYPE1DOES,0C000h
580 .word TYPE1DOES,0C040h
584 .word TYPE1DOES,0D000h
588 .word TYPE1DOES,0D040h
592 .word TYPE1DOES,0E000h
596 .word TYPE1DOES,0E040h
600 .word TYPE1DOES,0F000h
604 .word TYPE1DOES,0F040h
606 ; ----------------------------------------------------------------------
607 ; DTCforthMSP430FR5xxx ASSEMBLER, OPCODES TYPE II : single operand
608 ; ----------------------------------------------------------------------
609 ; OPCODE(FEDCBA987) opcodeII
610 ; OPCODE(code) for TYPE II = 0bxxxxxxxxx
612 ; OPCODE(B) for TYPE I or TYPE II = 0b0 word
614 ; OPCODE(54) (dst addr type)
615 ; OPCODE(AS) for TYPE I or OPCODE(AD) for TYPE II = 0b00 register
620 ; OPCODE(dst) for TYPE I or TYPE II = 0bxxxx dst register
621 ; ----------------------------------------------------------------------
623 ; TYPE2DOES -- PFADOES search and compute PARAM1 as dst operand then compile instruction
624 TYPE2DOES ; -- PFADOES
625 .word FBLANK ; char separator for PARAM1
627 FORTHtoASM ; -- PFADOES
629 AND #0070h,S ; keep B/W & AS infos in ASMTYPE
630 SWPB W ; (REG org --> REG dst)
631 AND #000Fh,W ; keep REG
632 BIS_ASMTYPE BIS W,S ; -- PFADOES add it in ASMTYPE
633 JMP MAKEOPCODE ; -- then end
635 asmword "RRC" ; Rotate Right through Carry ( word)
637 .word TYPE2DOES,1000h
639 asmword "RRC.B" ; Rotate Right through Carry ( byte)
641 .word TYPE2DOES,1040h
643 asmword "SWPB" ; Swap bytes
645 .word TYPE2DOES,1080h
649 .word TYPE2DOES,1100h
653 .word TYPE2DOES,1140h
657 .word TYPE2DOES,1180h
661 .word TYPE2DOES,1200h
665 .word TYPE2DOES,1240h
669 .word TYPE2DOES,1280h
672 BOUNDERRWM1 ADD #1,W ; <== RRAM|RRUM|RRCM|RLAM error
673 BOUNDERRORW MOV W,TOS ; <== PUSHM|POPM|ASM_branch error
674 BOUNDERROR ; <== REG number error
675 mDOCOL ; -- n n = value out of bounds
677 .byte 13,"out of bounds"
680 ; --------------------------------------------------------------------------------
681 ; DTCforthMSP430FR5xxx ASSEMBLER, OPCODES TYPE III : PUSHM|POPM|RLAM|RRAM|RRUM|RRCM
682 ; --------------------------------------------------------------------------------
683 ; PUSHM, syntax: PUSHM #n,REG with 0 < n < 17
684 ; POPM syntax: POPM #n,REG with 0 < n < 17
687 ; PUSHM order : PSP,TOS, IP, S, T, W, X, Y, rEXIT,rDOVAR,rDOCON, rDODOES, R3, SR,RSP, PC
688 ; PUSHM order : R15,R14,R13,R12,R11,R10, R9, R8, R7 , R6 , R5 , R4 , R3, R2, R1, R0
690 ; example : PUSHM #6,IP pushes IP,S,T,W,X,Y registers to return stack
692 ; POPM order : PC,RSP, SR, R3, rDODOES,rDOCON,rDOVAR,rEXIT, Y, X, W, T, S, IP,TOS,PSP
693 ; POPM order : R0, R1, R2, R3, R4 , R5 , R6 , R7 , R8, R9,R10,R11,R12,R13,R14,R15
695 ; example : POPM #6,IP pulls Y,X,W,T,S,IP registers from return stack
697 ; RxxM syntax: RxxM #n,REG with 0 < n < 5
699 ; TYPE3DOES -- PFADOES parse input stream to search : " #N, REG " as operands of RLAM|RRAM|RRUM|RRCM
700 TYPE3DOES ; -- PFADOES
701 .word FBLANK,SKIP ; skip spaces if any
702 FORTHtoASM ; -- PFADOES c-addr
703 MOV #0,S ; init ASMTYPE=0
704 MOV &DDP,T ; init OPCODEADR=DP
705 ADD #2,&DDP ; make room for opcode
706 ADD #1,&TOIN ; skip "#"
707 MOV #',',TOS ; -- PFADOES ","
708 PUSHM #2,S ; PUSHM S,T
711 .word QBRAN,NotFound ; ABORT
715 .word PARAM2 ; -- PFADOES 0x000N S=ASMTYPE = 0x000R
717 MOV TOS,W ; -- PFADOES n W = n
718 MOV @PSP+,TOS ; -- PFADOES
719 SUB #1,W ; W = n floored to 0
721 MOV @TOS,X ; X=OPCODE
722 RLAM #4,X ; OPCODE bit 1000h --> C
724 PxxxINSTRU MOV S,Y ; S=REG, Y=REG to test
725 RLAM #3,X ; OPCODE bit 0200h --> C
726 JNC PUSHMINSTRU ; W=n-1 Y=REG
727 POPMINSTRU SUB W,S ; to make POPM opcode, keep first REG to POP; TI is complicated....
728 PUSHMINSTRU SUB W,Y ; Y=REG-(n-1)
730 JHS BOUNDERRWM1 ; JC=JHS (U>=)
731 RLAM.W #4,W ; W = n << 4
732 JMP BIS_ASMTYPE ; PFADOES --
733 RxxMINSTRU CMP #4,W ;
734 JHS BOUNDERRWM1 ; JC=JHS (U>=)
735 SWPB W ; -- PFADOES W = n << 8
736 RLAM.W #2,W ; RLAM #2,R10 W = N << 10
737 JMP BIS_ASMTYPE ; PFADOES --
741 .word TYPE3DOES,0050h
745 .word TYPE3DOES,0150h
749 .word TYPE3DOES,0250h
753 .word TYPE3DOES,0350h
757 .word TYPE3DOES,1500h
761 .word TYPE3DOES,1700h
763 ; ----------------------------------------------------------------------
764 ; DTCforthMSP430FR5xxx ASSEMBLER, CONDITIONAL BRANCHS
765 ; ----------------------------------------------------------------------
766 ; ASSEMBLER FORTH OPCODE(FEDC)
767 ; OPCODE(code) for TYPE JNE,JNZ 0<>, <> = 0x20xx + (offset AND 3FF) ; branch if Z = 0
768 ; OPCODE(code) for TYPE JEQ,JZ 0=, = = 0x24xx + (offset AND 3FF) ; branch if Z = 1
769 ; OPCODE(code) for TYPE JNC,JLO U< = 0x28xx + (offset AND 3FF) ; branch if C = 0
770 ; OPCODE(code) for TYPE JC,JHS U>= = 0x2Cxx + (offset AND 3FF) ; branch if C = 1
771 ; OPCODE(code) for TYPE JN 0< = 0x30xx + (offset AND 3FF) ; branch if N = 1
772 ; OPCODE(code) for TYPE JGE >= = 0x34xx + (offset AND 3FF) ; branch if (N xor V) = 0
773 ; OPCODE(code) for TYPE JL < = 0x38xx + (offset AND 3FF) ; branch if (N xor V) = 1
774 ; OPCODE(code) for TYPE JMP = 0x3Cxx + (offset AND 3FF)
776 CODE_JMP mDOCON ; branch always
779 asmword "S>=" ; if >= assertion
783 asmword "S<" ; if < assertion
787 asmword "0>=" ; if 0>= assertion ; use only with IF UNTIL WHILE !
791 asmword "0<" ; jump if 0< ; use only with ?JMP ?GOTO !
795 asmword "U<" ; if U< assertion
799 asmword "U>=" ; if U>= assertion
803 asmword "0<>" ; if <>0 assertion
807 asmword "0=" ; if =0 assertion
811 ;ASM IF OPCODE -- @OPCODE1
814 MOV TOS,0(W) ; compile incomplete opcode
819 ;ASM THEN @OPCODE -- resolve forward branch
821 ASM_THEN MOV &DDP,W ; -- @OPCODE W=dst
822 MOV TOS,Y ; Y=@OPCODE
823 ASM_THEN1 MOV @PSP+,TOS ; --
825 ADD #2,X ; -- Y=@OPCODE W=dst X=src+2
826 SUB X,W ; -- Y=@OPCODE W=dst-src+2=displacement*2 (bytes)
827 RRA W ; -- Y=@OPCODE W=displacement (words)
829 JC BOUNDERRORW ; (JHS) unsigned branch if u> 511
830 BIS W,0(Y) ; -- [@OPCODE]=OPCODE completed
833 ;C ELSE @OPCODE1 -- @OPCODE2 branch for IF..ELSE
835 ASM_ELSE MOV &DDP,W ; -- W=HERE
836 MOV #3C00h,0(W) ; compile unconditionnal branch
837 ADD #2,&DDP ; -- DP+2
839 MOV W,0(PSP) ; -- @OPCODE2 @OPCODE1
840 JMP ASM_THEN ; -- @OPCODE2
842 ;C BEGIN -- @BEGIN same as FORTH counterpart
844 ;C UNTIL @BEGIN OPCODE -- resolve conditional backward branch
846 ASM_UNTIL MOV @PSP+,W ; -- OPCODE W=dst
849 MOV &DDP,X ; -- Y=OPCODE X=HERE W=dst
850 SUB #2,W ; -- Y=OPCODE X=HERE W=dst-2
851 SUB X,W ; -- Y=OPCODE X=src W=src-dst-2=displacement (bytes)
852 RRA W ; -- Y=OPCODE X=HERE W=displacement (words)
854 JL BOUNDERRORW ; signed branch if < -512
855 AND #3FFh,W ; -- Y=OPCODE X=HERE W=troncated negative displacement (words)
856 BIS W,Y ; -- Y=OPCODE (completed)
861 ;X AGAIN @BEGIN -- uncond'l backward branch
862 ; unconditional backward branch
864 ASM_AGAIN mDOCOL ; -- @BEGIN
865 .word CODE_JMP ; -- @BEGIN opcode
869 ;C WHILE @BEGIN OPCODE -- @WHILE @BEGIN
871 ASM_WHILE mDOCOL ; -- @BEGIN OPCODE
872 .word ASM_IF ; -- @BEGIN @WHILE
873 .word SWAP ; -- @WHILE @BEGIN
876 ;C REPEAT @WHILE @BEGIN -- resolve WHILE loop
878 ASM_REPEAT mDOCOL ; -- @WHILE @BEGIN
879 .word CODE_JMP ; -- @WHILE @BEGIN opcode
880 .word ASM_UNTIL ; -- @WHILE
884 ; ------------------------------------------------------------------------------------------
885 ; DTCforthMSP430FR5xxx ASSEMBLER : branch up to 3 backward labels and up to 3 forward labels
886 ; ------------------------------------------------------------------------------------------
887 ; used for non canonical branchs, as BASIC language: "goto line x"
888 ; when a branch to label is resolved, it's ready for new use
894 MOV TOS,Y ; Y = ASMBWx
896 MOV @Y,W ; W = [ASMBWx]
898 MOV #0,0(Y) ; preset [ASMBWx] = 0 for next use
902 MOV &DDP,0(Y) ; [ASMBWx] = DDP
904 ; JMP ASM_UNTIL1 ; resolve backward branch with W
929 MOV @TOS,Y ; Y=[ASMFWx]
930 MOV #0,0(TOS) ; preset [ASMFWx] for next use
931 CMP #0,Y ; ASMFWx = 0 ? (FWx is free?)
932 FORWUSE ; PFA -- @OPCODE
934 FORWSET ; OPCODE PFA --
935 MOV @PSP+,0(W) ; -- PFA compile incomplete opcode
936 ADD #2,&DDP ; increment DDP
937 MOV W,0(TOS) ; store @OPCODE into ASMFWx
940 ; JMP ASM_THEN1 ; resolve forward branch with Y
962 ; invert FORTH conditionnal branch FORTH_JMP_OPCODE -- LABEL_JMP_OPCODE
963 INVJMP CMP #3000h,TOS
964 JZ INVJMPEND ; case of JN, do nothing
965 XOR #0400h,TOS ; case of: JNZ<-->JZ JNC<-->JC JL<-->JGE
966 BIT #1000h,TOS ; 3xxxh case ?
968 XOR #0800h,TOS ; complementary action for JL<-->JGE
971 ;ASM GOTO <label> -- unconditionnal branch to label
974 .word CODE_JMP,TICK ; -- OPCODE CFA<label>
977 ;ASM <cond> ?GOTO <label> OPCODE -- conditionnal branch to label
980 .word INVJMP,TICK ; -- OPCODE CFA<label>
983 ; ----------------------------------------------------------------
984 ; DTCforthMSP430FR5xxx ASSEMBLER : branch to a previous definition
985 ; ----------------------------------------------------------------
987 ;ASM JMP <word> ; -- unconditionnal branch to a previous definition
990 .word TICK ; -- @BACKWARD
994 ;ASM <cond> ?JMP <word> ; OPCODE -- conditionnal branch to a previous definition
997 .word INVJMP,TICK,SWAP ;