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 : R15,R14,R13,R12,R11,R10, R9, R8, R7, R6, R5, R4 (TI's reg)
37 ; or : PSP,TOS, IP, S, T, W, X, Y, R7, R6, R5, R4 (FastForth reg)
38 ; example : PUSHM IP,Y or PUSHM R13,R8
40 ; POPM order : R4, R5, R6, R7, R8, R9,R10,R11,R12,R13,R14,R15 (TI's reg)
41 ; or : R4, R5, R6, R7, Y, X, W, T, S, IP,TOS,PSP (FastForth reg)
42 ; example : POPM Y,IP or POPM R8,R13
44 ; ----------------------------------------------------------------------
45 ; DTCforthMSP430FR5xxx ASSEMBLER : STRUCTURE
46 ; ----------------------------------------------------------------------
48 ;X ASSEMBLER -- ; set ASSEMBLER the first context vocabulary
51 .ENDIF ; VOCABULARY_SET
52 ASSEMBLER mDODOES ; leave ASSEMBLER_BODY on the stack and run VOCDOES
54 ASSEMBLER_BODY .word lastasmword ; here is the structure created by VOCABULARY
123 FORTHWORDIMM "HI2LO" ; immediate, switch to low level, add ASSEMBLER context, set interpretation state
125 HI2LO .word HERE,CELLPLUS,COMMA
127 HI2LONEXT .word ALSO,ASSEMBLER
130 ; FORTHWORDIMM "SEMIC" ; same as HI2LO, plus restore IP; counterpart of COLON
133 ; .word LIT,413Dh,COMMA ; compile MOV @RSP+,IP
136 FORTHWORD "CODE" ; a CODE word must be finished with ENDCODE
137 ASMCODE CALL #HEADER ;
144 asmword "ENDCODE" ; restore previous context and test PSP balancing
146 .word PREVIOUS,QREVEAL
149 FORTHWORD "ASM" ; used to define an assembler word which is not executable by FORTH interpreter
150 ; i.e. typically an assembler word called by CALL and ended by RET
151 ; ASM words are only usable in another ASSEMBLER words
152 ; an ASM word must be finished with ENDASM
153 MOV &CURRENT,&ASM_CURRENT
154 MOV #ASSEMBLER_BODY,&CURRENT
157 asmword "ENDASM" ; end of an ASM word
158 MOV &ASM_CURRENT,&CURRENT
162 asmword "COLON" ; compile DOCOL, remove ASSEMBLER from CONTEXT, switch to compilation state
167 MOV #DOCOL1,0(W) ; compile CALL xDOCOL
171 MOV #DOCOL1,0(W) ; compile PUSH IP
172 COLON1 MOV #DOCOL2,2(W) ; compile CALL rEXIT
175 .CASE 3 ; inlined DOCOL
176 MOV #DOCOL1,0(W) ; compile PUSH IP
177 COLON1 MOV #DOCOL2,2(W) ; compile MOV PC,IP
178 MOV #DOCOL3,4(W) ; compile ADD #4,IP
179 MOV #NEXT,6(W) ; compile MOV @IP+,PC
183 COLON2 MOV #-1,&STATE ; enter in compile state
184 MOV #PREVIOUS,PC ; restore previous state of CONTEXT
187 asmword "LO2HI" ; same as COLON but without saving IP
189 .CASE 1 ; compile 2 words
191 MOV #12B0h,0(W) ; compile CALL #EXIT, 2 words 4+6=10~
195 .ELSECASE ; CASE 2 : compile 1 word, CASE 3 : compile 3 words
196 SUB #2,&DDP ; to skip PUSH IP
201 ;;Z SKIP char -- addr ; skip all occurring character 'char' in input stream
202 ; FORTHWORD "SKIP" ; used by assembler to parse input stream
203 SKIP: MOV #SOURCE_LEN,Y ;
204 MOV @Y+,X ; -- char X=length
205 MOV @Y,W ; -- char X=length W=org
206 ADD W,X ; -- char X=End W=org
207 ADD &TOIN,W ; -- char X=End W=ptr
208 SKIPLOOP: CMP W,X ; -- char ptr=End ?
209 JZ SKIPEND ; -- char yes
210 CMP.B @W+,TOS ; -- char does character match?
211 JZ SKIPLOOP ; -- char yes
212 SKIPNEXT: SUB #1,W ; -- char
213 SKIPEND: MOV W,TOS ; -- addr
214 SUB @Y,W ; -- addr W=Ptr-Org=Toin
218 ; ----------------------------------------------------------------------
219 ; DTCforthMSP430FR5xxx ASSEMBLER : search argument "xxxx", IP is free
220 ; ----------------------------------------------------------------------
222 ; Search ARG of "#xxxx"<sep> ; <== PARAM10
223 ; Search ARG of "&xxxx"<sep> ; <== PARAM111
224 ; Search ARG of "xxxx(REG)"<sep> ; <== PARAM130
225 ; Search ARG of <sep>"xxxx(REG)" ; <== PARAM210
226 SearchARG ASMtoFORTH ; -- separator search word first
227 .word WORDD,FIND ; -- c-addr
229 ; .word QBRAN,SearchARGW ; -- c-addr if found
230 .word QZBRAN,SearchARGW ; -- c-addr if found
232 .word QBRAN,NotFound ; -- c-addr
233 .word AsmSrchEnd ; -- value end if number found
234 SearchARGW FORTHtoASM ; -- xt
238 ADD #2,TOS ; remplace CFA by PFA for VARIABLE words
242 MOV 2(TOS),TOS ; remplace CFA by [PFA] for CONSTANT (and CREATEd) words
244 QDODOES CMP #DODOES,X
246 ADD #4,TOS ; leave BODY for DOES words (but don't execute !)
249 ; ----------------------------------------------------------------------
250 ; DTCforthMSP430FR5xxx ASSEMBLER : search REG
251 ; ----------------------------------------------------------------------
253 ; STOre ARGument xxxx of "xxxx(REG)"<sep> ; <== PARAM130
254 ; STOre ARGument xxxx of <sep>"xxxx(REG)" ; <== PARAM210
258 MOV TOS,0(X) ; -- xxxx compile xxxx
259 MOV #')',TOS ; -- ")" prepare separator to search REG of "xxxx(REG)"
261 ; search REG of "xxxx(REG)"<sep> separator = ')' ;
262 ; search REG of <sep>"xxxx(REG)" separator = ')' ;
263 ; search REG of "@REG"<sep> separator = <sep>; <== PARAM120
264 ; search REG of "@REG+"<sep> separator = '+' ; <== PARAM121
265 ; search REG of "REG"<sep> separator = <sep>; <== PARAM13
266 ; search REG of <sep>"REG" separator = ' ' ; <== PARAM21
268 SearchREG PUSH &TOIN ; -- separator save >IN
269 ADD #1,&TOIN ; skip "R"
270 ASMtoFORTH ; search xx of Rxx
271 .word WORDD,QNUMBER ;
272 .word QBRAN,notREG ; -- xxxx if number found
273 FORTHtoASM ; -- c-addr if number not found
274 ADD #2,RSP ; remove >IN
275 CMP #16,TOS ; -- 000R register > 15 ?
276 JHS BOUNDERROR ; yes : abort
277 MOV @RSP+,PC ; -- 000R Z=0 ==> found
279 notREG FORTHtoASM ; -- c-addr
280 MOV @RSP+,&TOIN ; -- c-addr restore >IN
281 BIS #Z,SR ; Z=1 ==> not found
282 MOV @RSP+,PC ; -- c_addr
284 ; ----------------------------------------------------------------------
285 ; DTCforthMSP430FR5xxx ASSEMBLER : INTERPRET FIRST OPERAND
286 ; ----------------------------------------------------------------------
288 ; PARAM1 separator -- ; parse input buffer until separator and compute first operand of opcode
289 ; sep is comma or space.
291 PARAM1 mDOCOL ; -- sep
292 .word FBLANK,SKIP ; -- sep c-addr
293 FORTHtoASM ; -- sep c-addr
294 MOV #0,&ASMTYPE ; -- sep c-addr reset ASMTYPE
295 MOV &DDP,&OPCODE ; -- sep c-addr HERE --> OPCODE (opcode is preset to its address !)
296 ADD #2,&DDP ; -- sep c-addr cell allot for opcode
297 MOV TOS,W ; -- sep c-addr W=c-addr
298 MOV @PSP+,TOS ; -- sep W=c-addr
299 CMP.B #'#',0(W) ; -- sep W=c-addr
302 ; "#" found : case of "#xxxx"<sep>
303 PARAM10 ADD #1,&TOIN ; -- sep skip # prefix
304 CALL #SearchARG ; -- xxxx abort if not found
306 PARAM100 CMP #0,TOS ; -- xxxx = 0 ?
309 MOV #0300h,&ASMTYPE ; -- 0 example : MOV #0,dst <=> MOV R3,dst
312 PARAM101 CMP #1,TOS ; -- xxxx = 1 ?
315 MOV #0310h,&ASMTYPE ; -- 1 example : MOV #1,dst <=> MOV 0(R3),dst
318 PARAM102 CMP #2,TOS ; -- xxxx = 2 ?
321 MOV #0320h,&ASMTYPE ; -- 2 ASMTYPE = 0320h example : MOV #2, <=> MOV @R3,
324 PARAM104 CMP #4,TOS ; -- xxxx = 4 ?
327 MOV #0220h,&ASMTYPE ; -- 4 ASMTYPE = 0220h example : MOV #4, <=> MOV @SR,
330 PARAM108 CMP #8,TOS ; -- xxxx = 8 ?
333 MOV #0230h,&ASMTYPE ; -- 8 ASMTYPE = 0230h example : MOV #8, <=> MOV @SR+,
336 PARAM10M1 CMP #-1,TOS ; -- xxxx = -1 ?
339 MOV #0330h,&ASMTYPE ; -- -1 ASMTYPE = 0330h example : XOR #-1 <=> XOR @R3+,
342 ; case of all others "#xxxx"<sep> ; -- xxxx
343 PARAM1000 MOV #0030h,&ASMTYPE ; -- xxxx add immediate code type : @PC+,
345 ; case of "&xxxx"<sep> ; <== PARAM110
346 ; case of <sep>"&xxxx" ; <== PARAM20
347 StoreArg MOV &DDP,X ; -- xxxx
348 ADD #2,&DDP ; cell allot for arg
349 StoreTOS MOV TOS,0(X) ; compile arg
351 ; endcase of all "&xxxx" ;
352 ; endcase of all "#xxxx" ; <== PARAM101,102,104,108,10M1
353 ; endcase of all "REG"|"@REG"|"@REG+" ; <== PARAM124
354 PARAMENDOF MOV @PSP+,TOS ; --
357 ; ------------------------------------------
359 PARAM11 CMP.B #'&',0(W) ; -- sep
362 ; case of "&xxxx"<sep> ; -- sep search for "&xxxx,"
363 PARAM110 MOV #0210h,&ASMTYPE ; -- sep set code type : xxxx(SR) with AS=0b01 ==> x210h (and SR=0 !)
365 ; case of "&xxxx"<sep>
366 ; case of <sep>"&xxxx" ; <== PARAM20
367 PARAM111 ADD #1,&TOIN ; -- sep skip "&" prefix
368 PUSH #StoreArg ; prepare next ret : compile xxxx then ret
369 JMP SearchARG ; -- sep abort if not found
370 ; ------------------------------------------
372 PARAM12 CMP.B #'@',0(W) ; -- sep
375 ; case of "@REG"<sep>|"@REG+"<sep>
376 PARAM120 MOV #0020h,&ASMTYPE ; -- sep init ASMTYPE with indirect code type : AS=0b10
377 ADD #1,&TOIN ; -- sep skip "@" prefix
378 CALL #SearchREG ; Z = not found
379 JNZ PARAM123 ; -- value REG of "@REG," found
381 ; case of "@REG+"<sep> ; -- c-addr "@REG"<sep> not found, search REG of "@REG+"
382 PARAM121 ADD #0010h,&ASMTYPE ; change ASMTYPE from @REG to @REG+ type
383 MOV #'+',TOS ; -- "+" as WORD separator to find REG of "@REG+,"
384 CALL #SearchREG ; -- value|c-addr X = flag
386 ; case of "REG" of "@REG+"<sep>
387 ; case of "REG" of "xxxx(REG)"<sep> ; <== PARAM130
388 PARAM122 JZ REGnotFound ; -- c-addr
389 CMP &SOURCE_LEN,&TOIN ; test OPCODE II parameter ending by REG+ or (REG) without comma,
390 JZ PARAM123 ; i.e. >IN = SOURCE_LEN : don't skip char CR !
391 ADD #1,&TOIN ; -- 000R skip "," ready for the second operand search
393 ; case of "REG" of "@REG+"<sep>
394 ; case of "REG" of "xxxx(REG)"<sep>
395 ; case of "REG" of "@REG"<sep> ; <== PARAM120
396 ; case of "REG" of "REG"<sep> ; <== PARAM13
397 PARAM123 SWPB TOS ; 000R -- 0R00 swap bytes because it's not a dst REG typeI (not a 2 ops inst.)
399 ; case of "REG" of "@REG+"<sep> ; -- 0R00 (src REG typeI)
400 ; case of "REG" of "xxxx(REG)"<sep> ; -- 0R00 (src REG typeI or dst REG typeII)
401 ; case of "REG" of "@REG"<sep> ; -- 0R00 (src REG typeI)
402 ; case of "REG" of "REG"<sep> ; -- 0R00 (src REG typeI or dst REG typeII)
403 ; case of "REG" of <sep>"REG" ; -- 000R <== PARAM21 (dst REG typeI)
404 ; case of "REG" of <sep>"xxxx(REG)" ; -- 000R <== PARAM210 (dst REG typeI)
405 PARAM124 ADD TOS,&ASMTYPE ; -- 0R00|000R
407 ; ------------------------------------------
409 ; case of "REG"<sep>|"xxxx(REG)"<sep> ; first, searg REG of "REG,"
410 PARAM13 CALL #SearchREG ; -- sep save >IN for second parsing (case of "xxxx(REG),")
411 JNZ PARAM123 ; -- 000R REG of "REG," found, ASMTYPE=0
413 ; case of "xxxx(REG)"<sep> ; -- c-addr "REG," not found
414 PARAM130 ADD #0010h,&ASMTYPE ; AS=0b01 for indexing address
415 MOV #'(',TOS ; -- "(" as WORD separator to find xxxx of "xxxx(REG),"
416 CALL #SearchARG ; -- xxxx aborted if not found
417 PUSH #PARAM122 ; prepare next ret : REG found or not found
418 JMP StoARGsearchREG ; compile xxxx and search REG of "(REG)"
420 ; ----------------------------------------------------------------------
421 ; DTCforthMSP430FR5xxx ASSEMBLER : INTERPRET 2th OPERAND
422 ; ----------------------------------------------------------------------
424 ; PARAM2 -- ; parse input buffer until BL and compute this 2th operand
427 .word FBLANK,SKIP ; skip space(s) between "arg1," and "arg2" if any
428 FORTHtoASM ; -- c-addr search for '&' of "&xxxx
430 MOV #20h,TOS ; -- " " as WORD separator to find xxxx of ",&xxxx"
431 JNE PARAM21 ; '&' not found
433 ; case of <sep>"&xxxx" ;
434 PARAM20 ADD #0082h,&ASMTYPE ; change ASMTYPE : AD=1, dst = R2
435 JMP PARAM111 ; -- " "
436 ; ------------------------------------------
438 ; case of <sep>"REG"|<sep>"xxxx(REG) ; -- " " first, search REG of ",REG"
439 PARAM21 CALL #SearchREG ;
440 JNZ PARAM124 ; -- 000R REG of ",REG" found
442 ; case of <sep>"xxxx(REG) ; -- c-addr REG not found
443 PARAM210 ADD #0080h,&ASMTYPE ; set AD=1
444 MOV #'(',TOS ; -- "(" as WORD separator to find xxxx of ",xxxx(REG)"
445 CALL #SearchARG ; -- xxxx aborted if not found
446 CALL #StoARGsearchREG ; compile argument xxxx and search REG of "(REG)"
447 JNZ PARAM124 ; -- 000R REG of "(REG) found
448 REGnotFound MOV #NotFound,IP ; -- c-addr abort
452 ; ----------------------------------------------------------------------
453 ; DTCforthMSP430FR5xxx ASSEMBLER: OPCODES TYPE 0 : zero operand f:-)
454 ; ----------------------------------------------------------------------
457 .word lit,1300h,COMMA,EXIT
459 ; ----------------------------------------------------------------------
460 ; DTCforthMSP430FR5xxx ASSEMBLER: OPCODES TYPE I : double operand
461 ; ----------------------------------------------------------------------
463 ; OPCODE(code) for TYPE I = 0bxxxx opcode I
465 ; = 0bxxxx src register
466 ; OPCODE(7) AD (dst addr type)
470 ; OPCODE(B) for TYPE I or TYPE II = 0b0 word
472 ; OPCODE(54) AS (src addr type)
473 ; OPCODE(AS) for TYPE I or OPCODE(AD) for TYPE II = 0b00 register
478 ; OPCODE(dst) for TYPE I or TYPE II = 0bxxxx dst register
479 ; ----------------------------------------------------------------------
481 ; TYPE1DOES -- PFADOES search and compute PARAM1 & PARAM2 as src and dst operands then compile instruction
482 TYPE1DOES ; -- PFADOES
483 .word lit,',' ; -- PFADOES "," char separator for PARAM1
484 .word PARAM1 ; -- PFADOES
485 .word PARAM2 ; -- PFADOES char separator (BL) included in PARAM2
486 FORTHtoASM ; -- PFADOES
487 MAKEOPCODE MOV @TOS,TOS ; -- opcode part of instruction
488 BIS &ASMTYPE,TOS ; -- opcode opcode is complete
489 MOV &OPCODE,X ; -- opcode X= addr to compile opcode
490 JMP StoreTOS ; then EXIT
494 .word TYPE1DOES,4000h
498 .word TYPE1DOES,4040h
502 .word TYPE1DOES,5000h
506 .word TYPE1DOES,5040h
510 .word TYPE1DOES,6000h
514 .word TYPE1DOES,6040h
518 .word TYPE1DOES,7000h
522 .word TYPE1DOES,7040h
526 .word TYPE1DOES,8000h
530 .word TYPE1DOES,8040h
534 .word TYPE1DOES,9000h
538 .word TYPE1DOES,9040h
542 .word TYPE1DOES,0A000h
546 .word TYPE1DOES,0A040h
550 .word TYPE1DOES,0B000h
554 .word TYPE1DOES,0B040h
558 .word TYPE1DOES,0C000h
562 .word TYPE1DOES,0C040h
566 .word TYPE1DOES,0D000h
570 .word TYPE1DOES,0D040h
574 .word TYPE1DOES,0E000h
578 .word TYPE1DOES,0E040h
582 .word TYPE1DOES,0F000h
586 .word TYPE1DOES,0F040h
588 ; ----------------------------------------------------------------------
589 ; DTCforthMSP430FR5xxx ASSEMBLER, OPCODES TYPE II : single operand
590 ; ----------------------------------------------------------------------
591 ; OPCODE(FEDCBA987) opcodeII
592 ; OPCODE(code) for TYPE II = 0bxxxxxxxxx
594 ; OPCODE(B) for TYPE I or TYPE II = 0b0 word
596 ; OPCODE(54) (dst addr type)
597 ; OPCODE(AS) for TYPE I or OPCODE(AD) for TYPE II = 0b00 register
602 ; OPCODE(dst) for TYPE I or TYPE II = 0bxxxx dst register
603 ; ----------------------------------------------------------------------
605 ; TYPE2DOES -- PFADOES search and compute PARAM1 as dst operand then compile instruction
606 TYPE2DOES ; -- PFADOES
607 .word FBLANK ; char separator for PARAM1
609 FORTHtoASM ; -- PFADOES
611 AND #0070h,&ASMTYPE ; keep B/W & AS infos in ASMTYPE
612 SWPB W ; (REG org --> REG dst)
613 AND #000Fh,W ; keep REG
614 BIS_ASMTYPE BIS W,&ASMTYPE ; -- PFADOES add it in ASMTYPE
615 JMP MAKEOPCODE ; -- then end
617 asmword "RRC" ; Rotate Right through Carry ( word)
619 .word TYPE2DOES,1000h
621 asmword "RRC.B" ; Rotate Right through Carry ( byte)
623 .word TYPE2DOES,1040h
625 asmword "SWPB" ; Swap bytes
627 .word TYPE2DOES,1080h
631 .word TYPE2DOES,1100h
635 .word TYPE2DOES,1140h
639 .word TYPE2DOES,1180h
643 .word TYPE2DOES,1200h
647 .word TYPE2DOES,1240h
651 .word TYPE2DOES,1280h
653 ; ----------------------------------------------------------------------
654 ; DTCforthMSP430FR5xxx ASSEMBLER, OPCODES TYPE III : PUSHM POPM
655 ; ----------------------------------------------------------------------
656 ; syntax : PUSHM R13,R9 ; R-- R13 R12 R11 R10 R9 (first >= last)
657 ; POPM R9,R13 ; R-- (last >= first)
658 ; this syntax is more explicit than TI's one and can reuse typeI template
660 ; PUSHM order : R15,R14,R13,R12,R11,R10, R9, R8, R7, R6, R5, R4 (TI's reg)
661 ; or : PSP,TOS, IP, S, T, W, X, Y, R7, R6, R5, R4 (FastForth reg)
662 ; example : PUSHM IP,Y or PUSHM R13,R8
664 ; POPM order : R4, R5, R6, R7, R8, R9,R10,R11,R12,R13,R14,R15 (TI's reg)
665 ; or : R4, R5, R6, R7, Y, X, W, T, S, IP,TOS,PSP (FastForth reg)
666 ; example : POPM Y,IP or POPM R8,R13
668 ; TYPE3DOES -- PFADOES parse input stream to search :" REG, REG " as operands of PUSHM|POPM then compile instruction
669 TYPE3DOES ; -- PFADOES
670 .word lit,',' ; -- PFADOES "," char separator for PARAM1
671 .word PARAM1 ; -- PFADOES ASMTYPE contains : 0x0S00 S=REGsrc
672 .word PARAM2 ; -- PFADOES ASMTYPE contains : 0x0S0D D=REGdst
673 FORTHtoASM ; -- PFADOES
674 MOV.B &ASMTYPE,X ; X=REGdst
675 MOV.B &ASMTYPE+1,W ; W=REGsrc
676 MOV W,&ASMTYPE ; ASMTYPE = 0x000S
677 CMP #1500h,0(TOS) ; -- PFADOES PUSHM ?
679 PUSHMCASEOF SUB X,W ; -- PFADOES PUSHM : REGsrc - REGdst = n-1
681 POPMCASEOF SUB W,X ; -- PFADOES POPM : REGdst - REGsrc = n-1
684 JHS BOUNDERRORW ; -- PFADOES (u>=)
685 .word 0E5Ah ; RLAM #4,R10 --> RLAM #4,W
686 JMP BIS_ASMTYPE ; -- then end
688 BOUNDERRWM1 ADD #1,W ; <== RRAM|RRUM|RRCM|RLAM error
689 BOUNDERRORW MOV W,TOS ; <== PUSHM|POPM|ASM_branch error
690 BOUNDERROR ; <== REG number error
691 mDOCOL ; -- n n = value out of bounds
693 .byte 13,"out of bounds"
698 .word TYPE3DOES,01500h
702 .word TYPE3DOES,01700h
704 ; ----------------------------------------------------------------------
705 ; DTCforthMSP430FR5xxx ASSEMBLER, OPCODES TYPE IV : RLAM|RRAM|RRUM|RRCM
706 ; ----------------------------------------------------------------------
708 ; TYPE4DOES -- PFADOES parse input stream to search : " #N, REG " as operands of RLAM|RRAM|RRUM|RRCM
709 TYPE4DOES ; -- PFADOES
710 .word FBLANK,SKIP ; skip spaces if any
711 FORTHtoASM ; -- PFADOES c-addr
712 MOV #0,&ASMTYPE ; init ASMTYPE=0
713 MOV &DDP,&OPCODE ; init OPCODE=DP
714 ADD #2,&DDP ; make room for opcode
715 ADD #1,&TOIN ; skip "#"
716 MOV #',',TOS ; -- PFADOES ","
720 .word PARAM2 ; -- PFADOES 0x000N ASMTYPE = 0x000R
722 MOV TOS,W ; -- PFADOES 0x000N W = 0x000N
723 MOV @PSP+,TOS ; -- PFADOES
724 SUB #1,W ; W = N floored to 0
726 JHS BOUNDERRWM1 ; JC=JHS (U>=)
727 SWPB W ; -- PFADOES W = N << 8
728 .word 065Ah ; RLAM #2,R10 W = N << 10
733 .word TYPE4DOES,0050h
737 .word TYPE4DOES,0150h
741 .word TYPE4DOES,0250h
745 .word TYPE4DOES,0350h
747 ; ----------------------------------------------------------------------
748 ; DTCforthMSP430FR5xxx ASSEMBLER, CONDITIONAL BRANCHS
749 ; ----------------------------------------------------------------------
750 ; ASSEMBLER FORTH OPCODE(FEDC)
751 ; OPCODE(code) for TYPE JNE,JNZ 0<>, <> = 0x20xx + (offset AND 3FF) ; branch if Z = 0
752 ; OPCODE(code) for TYPE JEQ,JZ 0=, = = 0x24xx + (offset AND 3FF) ; branch if Z = 1
753 ; OPCODE(code) for TYPE JNC,JLO U< = 0x28xx + (offset AND 3FF) ; branch if C = 0
754 ; OPCODE(code) for TYPE JC,JHS U>= = 0x2Cxx + (offset AND 3FF) ; branch if C = 1
755 ; OPCODE(code) for TYPE JN 0< = 0x30xx + (offset AND 3FF) ; branch if N = 1
756 ; OPCODE(code) for TYPE JGE >= = 0x34xx + (offset AND 3FF) ; branch if (N xor V) = 0
757 ; OPCODE(code) for TYPE JL < = 0x38xx + (offset AND 3FF) ; branch if (N xor V) = 1
758 ; OPCODE(code) for TYPE JMP = 0x3Cxx + (offset AND 3FF)
760 CODE_JMP mDOCON ; branch always
763 asmword "S>=" ; if >= assertion
767 asmword "S<" ; if < assertion
771 asmword "0>=" ; if 0>= assertion ; use only with IF UNTIL WHILE !
775 asmword "0<" ; jump if 0< ; use only with ?JMP ?GOTO !
779 asmword "U<" ; if U< assertion
783 asmword "U>=" ; if U>= assertion
787 asmword "0<>" ; if <>0 assertion
791 asmword "0=" ; if =0 assertion
795 ;ASM IF OPCODE -- @OPCODE1
803 ;ASM THEN @OPCODE -- resolve forward branch
805 ASM_THEN MOV &DDP,W ; -- @OPCODE W=dst
806 MOV TOS,Y ; Y=@OPCODE
807 ASM_THEN1 MOV @PSP+,TOS ; --
809 ADD #2,X ; -- Y=@OPCODE W=dst X=src+2
810 SUB X,W ; -- Y=@OPCODE W=dst-src+2=displacement*2 (bytes)
811 RRA W ; -- Y=@OPCODE W=displacement (words)
813 JC BOUNDERRORW ; (JHS) unsigned branch if u> 511
814 BIS W,0(Y) ; -- [@OPCODE]=OPCODE completed
817 ;C ELSE @OPCODE1 -- @OPCODE2 branch for IF..ELSE
819 ASM_ELSE MOV &DDP,W ; -- W=HERE
820 MOV #3C00h,0(W) ; compile unconditionnal branch
821 ADD #2,&DDP ; -- DP+2
823 MOV W,0(PSP) ; -- dst
826 ;C BEGIN -- @BEGIN same as FORTH counterpart
828 ;C UNTIL @BEGIN OPCODE -- resolve conditional backward branch
830 ASM_UNTIL MOV @PSP+,W ; -- OPCODE W=dst
833 MOV &DDP,X ; -- Y=OPCODE X=HERE W=dst
834 SUB #2,W ; -- Y=OPCODE X=HERE W=dst-2
835 SUB X,W ; -- Y=OPCODE X=src W=src-dst-2=displacement (bytes)
836 RRA W ; -- Y=OPCODE X=HERE W=displacement (words)
838 JL BOUNDERRORW ; signed branch if < -512
839 AND #3FFh,W ; -- Y=OPCODE X=HERE W=troncated negative displacement (words)
840 BIS W,Y ; -- Y=OPCODE (completed)
845 ;X AGAIN @BEGIN -- uncond'l backward branch
846 ; unconditional backward branch
848 ASM_AGAIN mDOCOL ; -- @BEGIN
849 .word CODE_JMP ; -- @BEGIN opcode
853 ;C WHILE @BEGIN OPCODE -- @WHILE @BEGIN
855 ASM_WHILE mDOCOL ; -- @BEGIN OPCODE
856 .word ASM_IF ; -- @BEGIN @WHILE
857 .word SWAP ; -- @WHILE @BEGIN
860 ;C REPEAT @WHILE @BEGIN -- resolve WHILE loop
862 ASM_REPEAT mDOCOL ; -- @WHILE @BEGIN
863 .word CODE_JMP ; -- @WHILE @BEGIN opcode
864 .word ASM_UNTIL ; -- @WHILE
868 ; ----------------------------------------------------------------
869 ; DTCforthMSP430FR5xxx ASSEMBLER : branch to a previous definition
870 ; ----------------------------------------------------------------
872 ;ASM JMP <word> ; -- unconditionnal branch to a previous definition
879 ; invert FORTH conditionnal branch FORTH_JMP_OPCODE -- LABEL_JMP_OPCODE
880 INVJMP BIT #1000h,TOS ; 3xxxh case ?
881 JNZ INVJMP3xxxh ; yes
882 INVJMP2xxxh XOR #0400h,TOS ; no: case of JNE/JNZ JEQ/JZ JNC/JLO JC/JHS
884 INVJMP3xxxh CMP #3400h,TOS
885 JLO INVJMPEND ; case of 3000h, do nothing
887 INVJMP3800h MOV #3400h,TOS ; not jump if >= --> jump if <
889 INVJMP3400h MOV #3800h,TOS ; not jump if < --> jump if >=
893 ;ASM <cond> ?JMP <word> ; OPCODE -- conditionnal branch to a previous definition
896 .word INVJMP,TICK,SWAP
899 ; ------------------------------------------------------------------------------------------
900 ; DTCforthMSP430FR5xxx ASSEMBLER : branch up to 3 backward labels and up to 3 forward labels
901 ; ------------------------------------------------------------------------------------------
902 ; used for non canonical branchs, as BASIC language: "goto line x"
903 ; when a branch to label is resolved, it's ready for new use
914 MOV &DDP,0(Y) ; [PFA] = @LABEL
917 MOV #0,0(Y) ; reset [PFA] for next use
918 JMP ASM_UNTIL1 ; resolve backward branch
942 MOV @TOS,Y ; Y=@OPCODE
945 FORWSET ; OPCODE PFA --
946 MOV @PSP+,0(W) ; -- PFA compile incomplete opcode
948 MOV W,0(TOS) ; store @OPCODE into PFA
951 FORWUSE ; PFA -- @OPCODE
952 MOV #0,0(TOS) ; reset PFA for next use
953 JMP ASM_THEN1 ; resolve forward branch
975 ;ASM GOTO <label> -- unconditionnal branch to label
978 .word CODE_JMP,TICK ; -- OPCODE PFA<label>
981 ;ASM <cond> ?GOTO <label> OPCODE -- conditionnal branch to label
984 .word INVJMP,TICK ; -- OPCODE PFA<label>