2 // RMAC - Reboot's Macro Assembler for all Atari computers
3 // PARMODE.C - Addressing Modes Parser Include
4 // Copyright (C) 199x Landon Dyer, 2011-2017 Reboot and Friends
5 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
6 // Source utilised with the kind permission of Landon Dyer
9 // This file is included (twice) to parse two addressing modes, into slightly
10 // different var names
15 if ((*tok >= KW_D0) && (*tok <= KW_D7))
20 else if ((*tok >= KW_A0) && (*tok <= KW_A7))
29 if (expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
35 // Small problem with this is that the opening parentheses might be an
36 // expression that's part of a displacement; this code will falsely flag
41 // (An,Xn[.siz][*scale])
42 // (PC,Xn[.siz][*scale])
44 // (d8,An,Xn[.siz][*scale])
46 // (d8,PC,Xn[.siz][*scale])
55 if ((*tok >= KW_A0) && (*tok <= KW_A7))
75 goto AMn_IX0; // Handle ",Xn[.siz][*scale])"
77 else if ((*tok >= KW_D0) && (*tok <= KW_D7))
79 //Since index register isn't used here, store register number in this field
80 AnIXREG = *tok++ & 7; // (Dn)
85 AnEXTEN |= EXT_FULLWORD; // Definitely using full extension format, so set bit 8
86 AnEXTEN |= EXT_BS; // Base register suppressed
87 AnEXTEN |= EXT_BDSIZE0; // Base displacement null
88 AnEXTEN |= EXT_IISPOSN; // Indirect Postindexed with Null Outer Displacement
90 AnREG = 6 << 3; // stuff 110 to mode field
95 // TODO: does DINDL gets used at all?
96 AMn = DINDL; // (Dn.l)
97 AnEXTEN = 1 << 1; // Long index size
100 else if (*tok == 'W') // (Dn.w)
102 // TODO: does DINDW gets used at all?
104 AnEXTEN = 1 << 1; // Word index size
107 else if (*tok == ',')
109 // ([bd,An],Xn..) without bd, An
110 // Base displacement is suppressed
111 AnEXTEN |= EXT_FULLWORD; // Definitely using full extension format, so set bit 8
112 AnEXTEN |= EXT_BS; // Base register suppressed
113 AnEXTEN |= EXT_BDSIZE0;
114 AnREG = 6 << 3; // stuff 110 to mode field
120 return error("(Dn) error");
124 { // scale: *1, *2, *4, *8
129 if (expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
130 return error("scale factor expression must evaluate");
149 else if (*tok++ != CONST || *tok > 8)
175 AnEXTEN |= EXT_FULLWORD; // Definitely using full extension format, so set bit 8
176 AnEXTEN |= EXT_BS; // Base register suppressed
177 AnEXTEN |= EXT_BDSIZE0; // Base displacement null
178 AnEXTEN |= EXT_IISPOSN; // Indirect Postindexed with Null Outer Displacement
179 AnREG = 6 << 3; // stuff 110 to mode field
185 tok++; // eat the comma
186 // It might be (Dn[.wl][*scale],od)
187 // Maybe this is wrong and we have to write some code here
188 // instead of reusing that path...
192 return error("unhandled so far");
194 else if (*tok == KW_PC)
195 { // (PC,Xn[.siz][*scale])
199 // Common index handler; enter here with 'tok' pointing at the
202 AMn_IX0: // Handle indexed with missing expr
205 AnEXATTR = ABS | DEFINED;
207 AMn_IXN: // Handle any indexed (tok -> a comma)
212 if (*tok < KW_D0 || *tok > KW_A7)
215 AnIXREG = *tok++ & 15;
218 { // Index reg size: <empty> | .W | .L
228 case DOTB: // .B not allowed here...
233 { // scale: *1, *2, *4, *8
238 if (expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
239 return error("scale factor expression must evaluate");
257 else if (*tok++ != CONST || *tok > 8)
285 if (*tok++ != ')') // final ")"
290 else if (*tok == '[')
293 AnEXTEN |= EXT_FULLWORD; // Definitely using full extension format, so set bit 8
295 // Check to see if base displacement is present
296 if (*tok != CONST && *tok != SYMBOL)
298 AnEXTEN |= EXT_BDSIZE0;
302 expr(AnBEXPR, &AnBEXVAL, &AnBEXATTR, &AnESYM);
303 if (CHECK_OPTS(OPT_BASE_DISP) && AnBEXVAL == 0 && AnEXATTR != 0)
305 // bd=0 so let's optimise it out
306 AnEXTEN|=EXT_BDSIZE0;
310 AnEXTEN |= EXT_BDSIZEL;
314 { // ([bd[.w],... or ([bd,...
315 // Is .W forced here?
318 AnEXTEN |= EXT_BDSIZEW;
323 // Defined, absolute values from $FFFF8000..$00007FFF get optimized
325 if (CHECK_OPTS(OPT_ABS_SHORT)
326 && ((AnBEXATTR & (TDB | DEFINED)) == DEFINED)
327 && (((uint32_t)AnBEXVAL + 0x8000) < 0x10000))
329 AnEXTEN |= EXT_BDSIZEW;
330 warn("absolute value in base displacement ranging $FFFF8000..$00007FFF optimised to absolute short");
334 AnEXTEN |= EXT_BDSIZEL;
342 // return error("Comma expected after base displacement");
345 // Check for address register or PC, suppress base register
350 AnREG = (7 << 3) | 3; // PC is special case - stuff 011 to register field and 111 to the mode field
353 else if ((*tok >= KW_A0) && (*tok <= KW_A7))
355 AnREG = (6 << 3) | *tok & 7;
358 else if ((*tok >= KW_D0) && (*tok <= KW_D7))
362 AnEXTEN |= ((*tok & 7) << 12);
364 AnEXTEN |= EXT_BS; // Oh look, a data register! Which means that base register is suppressed
368 // ([bd,An/PC],Xn.W/L...)
371 // Index reg size: <empty> | .W | .L
382 // .B not allowed here...
387 if (*tok == '*') // ([bd,An/PC],Xn*...)
388 { // scale: *1, *2, *4, *8
393 if (expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
394 return error("scale factor expression must evaluate");
413 else if (*tok++ != CONST || *tok > 8)
435 if (*tok == ']') // ([bd,Dn]...
441 else if (*tok == ']')
443 // PC and Xn is suppressed
444 AnREG = 6 << 3; // stuff 110 to mode field
445 //AnEXTEN|=EXT_BS|EXT_IS;
453 // At a crossroads here. We can accept either ([bd,An/PC],... or ([bd,An/PC,Xn*scale],...
462 //Xn and od are non existent, get out of jail free card
464 AMn = MEMPRE; // ([bc,An,Xn],od) with no Xn and od
465 AnEXTEN |= EXT_IS | EXT_IISPREN; //Suppress Xn and od
468 else if (*tok != ',')
469 return error("comma expected after ]");
471 tok++; // eat the comma
473 if ((*tok >= KW_A0) && (*tok <= KW_A7))
475 AnIXREG = ((*tok & 7) << 12);
479 else if ((*tok >= KW_D0) && (*tok <= KW_D7))
481 AnEXTEN |= ((*tok & 7) << 12);
487 //No index found, suppress it
489 tok--; // Rewind tok to point to the comma
490 goto IS_SUPPRESSEDn; // https://xkcd.com/292/ - what does he know anyway?
495 // ([bd,An/PC],Xn.W/L...)
498 // Index reg size: <empty> | .W | .L
509 // .B not allowed here...
515 if (*tok == '*') // ([bd,An/PC],Xn*...)
516 { // scale: *1, *2, *4, *8
521 if (expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
522 return error("scale factor expression must evaluate");
541 else if (*tok++ != CONST || *tok > 8)
565 if (*tok == ')') // ([bd,An/PC],Xn)
567 //od is non existant, get out of jail free card
568 AMn = MEMPOST; // let's say it's ([bd,An],Xn,od) with od=0 then
569 AnEXTEN |= EXT_IISPOSN; // No outer displacement
573 else if (*tok != ',')
574 return error("comma expected");
576 tok++; // eat the comma
579 if (expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
582 if (CHECK_OPTS(OPT_BASE_DISP) && (AnEXVAL == 0))
584 // od=0 so optimise it out
585 AMn = MEMPOST; // let's say it's ([bd,An],Xn,od) with od=0 then
586 AnEXTEN |= EXT_IISPOSN; // No outer displacement
591 // ([bd,An/PC],Xn,od)
595 AnEXTEN |= EXT_IISPOSL; // Long outer displacement
599 // Defined, absolute values from $FFFF8000..$00007FFF get
600 // optimized to absolute short
601 if (CHECK_OPTS(OPT_ABS_SHORT)
602 && ((AnEXATTR & (TDB | DEFINED)) == DEFINED)
603 && (((uint32_t)AnEXVAL + 0x8000) < 0x10000))
605 AnEXTEN |= EXT_IISPOSW; // Word outer displacement
607 warn("outer displacement absolute value from $FFFF8000..$00007FFF optimised to absolute short");
614 AnEXTEN |= EXT_IISPOSW; // Word outer displacement
617 // Is .W forced here?
622 // Check for final closing parenthesis
629 return error("Closing parenthesis missing on addressing mode");
634 if (*tok == ')') // ([bd,An/PC],Xn)
636 //od is non existant, get out of jail free card
637 AMn = MEMPOST; // let's say it's ([bd,An],Xn,od) with od=0 then
638 AnEXTEN |= EXT_IISNOIN; // No outer displacement
643 return error("comma expected");
645 tok++; // eat the comma
647 if ((*tok != CONST) && (*tok != SYMBOL))
650 expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM);
652 if (CHECK_OPTS(OPT_BASE_DISP) && (AnEXVAL == 0))
654 // od=0 so optimise it out
655 AMn = MEMPOST; // let's say it's ([bd,An],Xn,od) with od=0 then
656 AnEXTEN |= EXT_IISNOIN; // No outer displacement
661 // ([bd,An/PC],Xn,od)
667 AnEXTEN |= EXT_IISNOIL; // Long outer displacement with IS suppressed
672 AnEXTEN |= EXT_IISNOIW; // Word outer displacement with IS suppressed
677 //AnEXTEN|=EXT_IISNOIW; // Word outer displacement
681 // Defined, absolute values from $FFFF8000..$00007FFF get
682 // optimized to absolute short
683 else if (CHECK_OPTS(OPT_BASE_DISP)
684 && ((AnEXATTR & (TDB | DEFINED)) == DEFINED)
685 && (((uint32_t)AnEXVAL + 0x8000) < 0x10000))
687 //AnEXTEN|=EXT_IISNOIW; // Word outer displacement with IS suppressed
688 warn("outer displacement absolute value from $FFFF8000..$00007FFF optimised to absolute short");
692 // Check for final closing parenthesis
699 return error("Closing parenthesis missing on addressing mode");
701 else if (*tok == ',')
703 *tok++; // ([bd,An,Xn.size*scale],od)
706 if ((*tok >= KW_A0) && (*tok <= KW_A7))
708 AnEXTEN |= ((*tok & 7) << 12);
712 else if ((*tok >= KW_D0) && (*tok <= KW_D7))
714 AnEXTEN |= ((*tok & 7) << 12);
720 // ([bd,An/PC],Xn.W/L...)
723 // Index reg size: <empty> | .W | .L
734 // .B not allowed here...
739 if (*tok == '*') // ([bd,An/PC],Xn*...)
740 { // scale: *1, *2, *4, *8
745 if (expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
746 return error("scale factor expression must evaluate");
764 else if (*tok++ != CONST || *tok > 8)
789 return error("Expected closing bracket ]");
790 tok++; // Eat the bracket
793 if (*tok == ')') // ([bd,An/PC,Xn]...
795 //od is non existant, get out of jail free card
796 //AnEXVAL=0; // zero outer displacement
797 AMn = MEMPRE; // let's say it's ([bd,An,Xn],od) with od suppressed then
798 AnEXTEN |= EXT_IISPREN; // No outer displacement
802 else if (*tok++ != ',')
803 return error("comma expected after ]");
805 if (*tok == SYMBOL || *tok == CONST)
807 if (expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
810 if (CHECK_OPTS(OPT_BASE_DISP) && (AnEXVAL == 0) && (AnEXATTR & DEFINED))
812 // od=0 so optimise it out
813 AMn = MEMPRE; // let's say it's ([bd,An],Xn,od) with od=0 then
814 AnEXTEN |= EXT_IISPRE0; // No outer displacement
820 // ([bd,An/PC,Xn],od)
826 AnEXTEN |= EXT_IISPREL;
832 int expr_size = EXT_IISPREW; // Assume we have a .w value
834 if ((AnEXVAL + 0x8000) > 0x10000)
836 // Long value, so mark it as such for now
837 expr_size = EXT_IISPREL;
839 // Defined, absolute values from $FFFF8000..$00007FFF
840 // get optimized to absolute short
841 if (CHECK_OPTS(OPT_BASE_DISP)
842 && ((AnEXATTR & (TDB | DEFINED)) == DEFINED)
843 && (((uint32_t)AnEXVAL + 0x8000) < 0x10000))
845 expr_size = EXT_IISPREW;
846 warn("outer displacement absolute value from $FFFF8000..$00007FFF optimised to absolute short");
850 AnEXTEN |= expr_size; // Assume we have a .w value
852 // Is .W forced here?
857 if (expr_size == EXT_IISPREL)
858 return error("outer displacement value does not fit in .w size");
862 // Check for final closing parenthesis
869 return error("Closing parenthesis missing on addressing mode");
877 if (expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
880 // It could be that this is really just an expression prefixing a
881 // register as a displacement...
888 // Otherwise, check for PC & etc displacements...
892 if ((*tok >= KW_A0) && (*tok <= KW_A7))
902 else if (*tok == ')')
911 else if (*tok == KW_PC)
918 else if (*tok == ')')
920 AMn = PCDISP; // expr(PC)
931 else if (*tok == '-' && tok[1] == '(' && ((tok[2] >= KW_A0) && (tok[2] <= KW_A7)) && tok[3] == ')')
937 else if (*tok == KW_CCR)
943 else if (*tok == KW_SR)
949 else if (*tok == KW_USP)
953 AnREG = 2; //Added this for the case of USP used in movec (see CREGlut in mach.c). Hopefully nothing gets broken!
956 else if ((*tok >= KW_IC40) && (*tok <= KW_BC40))
959 AnREG = *tok++ - KW_IC40;
961 // After a cache keyword only a comma or EOL is allowed
962 if ((*tok != ',') && (*tok != EOL))
966 else if ((*tok >= KW_SFC) && (*tok <= KW_CRP))
969 AnREG = (*tok++) - KW_SFC;
972 else if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
975 AnREG = (*tok++ & 7);
977 else if ((*tok >= KW_FPIAR) && (*tok <= KW_FPCR))
980 AnREG = (1 << ((*tok++) - KW_FPIAR + 10));
991 if (expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
1001 if (((AnEXATTR & (TDB | DEFINED)) == DEFINED) && (AnEXVAL < 0x10000))
1002 AnEXVAL = (int32_t)(int16_t)AnEXVAL; // Sign extend value
1006 else if (*tok != '(')
1011 // Defined, absolute values from $FFFF8000..$00007FFF get optimized
1012 // to absolute short
1013 if (CHECK_OPTS(OPT_ABS_SHORT)
1014 && ((AnEXATTR & (TDB | DEFINED)) == DEFINED)
1015 && (((uint32_t)AnEXVAL + 0x8000) < 0x10000))
1020 warn("absolute value from $FFFF8000..$00007FFF optimised to absolute short");
1023 // Is .L forced here?
1035 if ((*tok >= KW_A0) && (*tok <= KW_A7))
1049 else if (*tok == KW_PC)
1065 // Addressing mode OK
1070 // Clean up dirty little macros
1085 #undef CHK_FOR_DISPn
1092 #undef IS_SUPPRESSEDn