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.u32 >= KW_D0) && (*tok.u32 <= KW_D7))
18 AnREG = *tok.u32++ & 7;
20 else if ((*tok.u32 >= KW_A0) && (*tok.u32 <= KW_A7))
23 AnREG = *tok.u32++ & 7;
25 else if (*tok.u32 == '#')
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])
51 else if (*tok.u32 == '(')
55 if ((*tok.u32 >= KW_A0) && (*tok.u32 <= KW_A7))
57 AnREG = *tok.u32++ & 7;
75 goto AMn_IX0; // Handle ",Xn[.siz][*scale])"
77 else if ((*tok.u32 >= KW_D0) && (*tok.u32 <= KW_D7))
79 //Since index register isn't used here, store register number in this field
80 AnIXREG = *tok.u32++ & 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
93 else if (*tok.u32 == 'L')
95 // TODO: does DINDL gets used at all?
96 AMn = DINDL; // (Dn.l)
97 AnEXTEN = 1 << 1; // Long index size
100 else if (*tok.u32 == 'W') // (Dn.w)
102 // TODO: does DINDW gets used at all?
104 AnEXTEN = 1 << 1; // Word index size
107 else if (*tok.u32 == ',')
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
127 if (*tok.u32 == SYMBOL)
129 if (expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
130 return error("scale factor expression must evaluate");
149 else if (*tok.u32++ != CONST || *tok.u32 > 8)
153 switch ((int)*tok.u32++)
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
183 else if (*tok.u32 == ',')
185 tok.u32++; // 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...
189 AnEXTEN |= EXT_BDSIZE0; // Base displacement null - suppressed
193 return error("unhandled so far");
195 else if (*tok.u32 == KW_PC)
196 { // (PC,Xn[.siz][*scale])
200 // Common index handler; enter here with 'tok' pointing at the
203 AMn_IX0: // Handle indexed with missing expr
206 AnEXATTR = ABS | DEFINED;
208 AMn_IXN: // Handle any indexed (tok -> a comma)
210 if (*tok.u32++ != ',')
213 if (*tok.u32 < KW_D0 || *tok.u32 > KW_A7)
216 AnIXREG = *tok.u32++ & 15;
218 switch ((int)*tok.u32)
219 { // Index reg size: <empty> | .W | .L
229 case DOTB: // .B not allowed here...
234 { // scale: *1, *2, *4, *8
237 if (*tok.u32 == SYMBOL)
239 if (expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
240 return error("scale factor expression must evaluate");
258 else if (*tok.u32++ != CONST || *tok.u32 > 8)
262 switch ((int)*tok.u32++)
283 // If we got here we didn't get any [] stuff
284 // so let's suppress base displacement before
287 AnEXTEN |= EXT_BDSIZE0; // Base displacement null - suppressed
290 if (*tok.u32++ != ')') // final ")"
295 else if (*tok.u32 == '[')
298 AnEXTEN |= EXT_FULLWORD; // Definitely using full extension format, so set bit 8
300 // Check to see if base displacement is present
301 if (*tok.u32 != CONST && *tok.u32 != SYMBOL)
303 AnEXTEN |= EXT_BDSIZE0;
307 expr(AnBEXPR, &AnBEXVAL, &AnBEXATTR, &AnESYM);
308 if (CHECK_OPTS(OPT_BASE_DISP) && AnBEXVAL == 0 && AnEXATTR != 0)
310 // bd=0 so let's optimise it out
311 AnEXTEN|=EXT_BDSIZE0;
313 else if (*tok.u32 == DOTL)
315 AnEXTEN |= EXT_BDSIZEL;
319 { // ([bd[.w],... or ([bd,...
320 // Is .W forced here?
321 if (*tok.u32 == DOTW)
323 AnEXTEN |= EXT_BDSIZEW;
328 // Defined, absolute values from $FFFF8000..$00007FFF get optimized
330 if (CHECK_OPTS(OPT_ABS_SHORT)
331 && ((AnBEXATTR & (TDB | DEFINED)) == DEFINED)
332 && (((uint32_t)AnBEXVAL + 0x8000) < 0x10000))
334 AnEXTEN |= EXT_BDSIZEW;
335 warn("absolute value in base displacement ranging $FFFF8000..$00007FFF optimised to absolute short");
339 AnEXTEN |= EXT_BDSIZEL;
347 // return error("Comma expected after base displacement");
350 // Check for address register or PC, suppress base register
353 if (*tok.u32 == KW_PC)
355 AnREG = (7 << 3) | 3; // PC is special case - stuff 011 to register field and 111 to the mode field
358 else if ((*tok.u32 >= KW_A0) && (*tok.u32 <= KW_A7))
360 AnREG = (6 << 3) | *tok.u32 & 7;
363 else if ((*tok.u32 >= KW_D0) && (*tok.u32 <= KW_D7))
367 AnEXTEN |= ((*tok.u32 & 7) << 12);
369 AnEXTEN |= EXT_BS; // Oh look, a data register! Which means that base register is suppressed
374 // ([bd,An/PC],Xn.W/L...)
375 switch ((int)*tok.u32)
377 // Index reg size: <empty> | .W | .L
388 // .B not allowed here...
394 if (*tok.u32 == '*') // ([bd,An/PC],Xn*...)
395 { // scale: *1, *2, *4, *8
398 if (*tok.u32 == SYMBOL)
400 if (expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
401 return error("scale factor expression must evaluate");
420 else if (*tok.u32++ != CONST || *tok.u32 > 8)
424 switch ((int)*tok.u32++)
442 if (*tok.u32 == ']') // ([bd,Dn]...
448 else if (*tok.u32 == ']')
450 // PC and Xn is suppressed
451 AnREG = 6 << 3; // stuff 110 to mode field
452 //AnEXTEN|=EXT_BS|EXT_IS;
460 // At a crossroads here. We can accept either ([bd,An/PC],... or ([bd,An/PC,Xn*scale],...
469 //Xn and od are non existent, get out of jail free card
471 AMn = MEMPRE; // ([bc,An,Xn],od) with no Xn and od
472 AnEXTEN |= EXT_IS | EXT_IISPREN; //Suppress Xn and od
475 else if (*tok.u32 != ',')
476 return error("comma expected after ]");
478 tok.u32++; // eat the comma
480 if ((*tok.u32 >= KW_A0) && (*tok.u32 <= KW_A7))
482 AnIXREG = ((*tok.u32 & 7) << 12);
486 else if ((*tok.u32 >= KW_D0) && (*tok.u32 <= KW_D7))
488 AnEXTEN |= ((*tok.u32 & 7) << 12);
494 //No index found, suppress it
496 tok.u32--; // Rewind tok to point to the comma
497 goto IS_SUPPRESSEDn; // https://xkcd.com/292/ - what does he know anyway?
502 // ([bd,An/PC],Xn.W/L...)
503 switch ((int)*tok.u32)
505 // Index reg size: <empty> | .W | .L
516 // .B not allowed here...
522 if (*tok.u32 == '*') // ([bd,An/PC],Xn*...)
523 { // scale: *1, *2, *4, *8
526 if (*tok.u32 == SYMBOL)
528 if (expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
529 return error("scale factor expression must evaluate");
548 else if (*tok.u32++ != CONST || *tok.u32 > 8)
552 switch ((int)*tok.u32++)
572 if (*tok.u32 == ')') // ([bd,An/PC],Xn)
574 //od is non existant, get out of jail free card
575 AMn = MEMPOST; // let's say it's ([bd,An],Xn,od) with od=0 then
576 AnEXTEN |= EXT_IISPOSN; // No outer displacement
580 else if (*tok.u32 != ',')
581 return error("comma expected");
583 tok.u32++; // eat the comma
586 if (expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
589 if (CHECK_OPTS(OPT_BASE_DISP) && (AnEXVAL == 0))
591 // od=0 so optimise it out
592 AMn = MEMPOST; // let's say it's ([bd,An],Xn,od) with od=0 then
593 AnEXTEN |= EXT_IISPOSN; // No outer displacement
598 // ([bd,An/PC],Xn,od)
599 if (*tok.u32 == DOTL)
602 AnEXTEN |= EXT_IISPOSL; // Long outer displacement
606 // Defined, absolute values from $FFFF8000..$00007FFF get
607 // optimized to absolute short
608 if (CHECK_OPTS(OPT_ABS_SHORT)
609 && ((AnEXATTR & (TDB | DEFINED)) == DEFINED)
610 && (((uint32_t)AnEXVAL + 0x8000) < 0x10000))
612 AnEXTEN |= EXT_IISPOSW; // Word outer displacement
614 warn("outer displacement absolute value from $FFFF8000..$00007FFF optimised to absolute short");
621 AnEXTEN |= EXT_IISPOSW; // Word outer displacement
624 // Is .W forced here?
625 if (*tok.u32 == DOTW)
631 // Check for final closing parenthesis
638 return error("Closing parenthesis missing on addressing mode");
643 if (*tok.u32 == ')') // ([bd,An/PC],Xn)
645 //od is non existant, get out of jail free card
646 AMn = MEMPOST; // let's say it's ([bd,An],Xn,od) with od=0 then
647 AnEXTEN |= EXT_IISNOIN; // No outer displacement
651 else if (*tok.u32!=',')
652 return error("comma expected");
654 tok.u32++; // eat the comma
656 if ((*tok.u32 != CONST) && (*tok.u32 != SYMBOL))
659 expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM);
661 if (CHECK_OPTS(OPT_BASE_DISP) && (AnEXVAL == 0))
663 // od=0 so optimise it out
664 AMn = MEMPOST; // let's say it's ([bd,An],Xn,od) with od=0 then
665 AnEXTEN |= EXT_IISNOIN; // No outer displacement
670 // ([bd,An/PC],Xn,od)
671 if (*tok.u32 == DOTL)
676 AnEXTEN |= EXT_IISNOIL; // Long outer displacement with IS suppressed
681 AnEXTEN |= EXT_IISNOIW; // Word outer displacement with IS suppressed
684 if (*tok.u32 == DOTW)
686 //AnEXTEN|=EXT_IISNOIW; // Word outer displacement
690 // Defined, absolute values from $FFFF8000..$00007FFF get
691 // optimized to absolute short
692 else if (CHECK_OPTS(OPT_BASE_DISP)
693 && ((AnEXATTR & (TDB | DEFINED)) == DEFINED)
694 && (((uint32_t)AnEXVAL + 0x8000) < 0x10000))
696 //AnEXTEN|=EXT_IISNOIW; // Word outer displacement with IS suppressed
697 warn("outer displacement absolute value from $FFFF8000..$00007FFF optimised to absolute short");
701 // Check for final closing parenthesis
708 return error("Closing parenthesis missing on addressing mode");
710 else if (*tok.u32 == ',')
712 *tok.u32++; // ([bd,An,Xn.size*scale],od)
715 if ((*tok.u32 >= KW_A0) && (*tok.u32 <= KW_A7))
717 AnEXTEN |= ((*tok.u32 & 7) << 12);
721 else if ((*tok.u32 >= KW_D0) && (*tok.u32 <= KW_D7))
723 AnEXTEN |= ((*tok.u32 & 7) << 12);
730 // ([bd,An/PC],Xn.W/L...)
731 switch ((int)*tok.u32)
733 // Index reg size: <empty> | .W | .L
744 // .B not allowed here...
750 if (*tok.u32 == '*') // ([bd,An/PC],Xn*...)
751 { // scale: *1, *2, *4, *8
754 if (*tok.u32 == SYMBOL)
756 if (expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
757 return error("scale factor expression must evaluate");
775 else if (*tok.u32++ != CONST || *tok.u32 > 8)
779 switch ((int)*tok.u32++)
800 return error("Expected closing bracket ]");
801 tok.u32++; // Eat the bracket
804 if (*tok.u32 == ')') // ([bd,An/PC,Xn]...
806 //od is non existant, get out of jail free card
807 //AnEXVAL=0; // zero outer displacement
808 AMn = MEMPRE; // let's say it's ([bd,An,Xn],od) with od suppressed then
809 AnEXTEN |= EXT_IISPREN; // No outer displacement
813 else if (*tok.u32++ != ',')
814 return error("comma expected after ]");
816 if (*tok.u32 == SYMBOL || *tok.u32 == CONST)
818 if (expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
821 if (CHECK_OPTS(OPT_BASE_DISP) && (AnEXVAL == 0) && (AnEXATTR & DEFINED))
823 // od=0 so optimise it out
824 AMn = MEMPRE; // let's say it's ([bd,An],Xn,od) with od=0 then
825 AnEXTEN |= EXT_IISPRE0; // No outer displacement
831 // ([bd,An/PC,Xn],od)
832 if (*tok.u32 == DOTL)
837 AnEXTEN |= EXT_IISPREL;
843 int expr_size = EXT_IISPREW; // Assume we have a .w value
845 if ((AnEXVAL + 0x8000) > 0x10000)
847 // Long value, so mark it as such for now
848 expr_size = EXT_IISPREL;
850 // Defined, absolute values from $FFFF8000..$00007FFF
851 // get optimized to absolute short
852 if (CHECK_OPTS(OPT_BASE_DISP)
853 && ((AnEXATTR & (TDB | DEFINED)) == DEFINED)
854 && (((uint32_t)AnEXVAL + 0x8000) < 0x10000))
856 expr_size = EXT_IISPREW;
857 warn("outer displacement absolute value from $FFFF8000..$00007FFF optimised to absolute short");
861 AnEXTEN |= expr_size; // Assume we have a .w value
863 // Is .W forced here?
864 if (*tok.u32 == DOTW)
868 if (expr_size == EXT_IISPREL)
869 return error("outer displacement value does not fit in .w size");
873 // Check for final closing parenthesis
880 return error("Closing parenthesis missing on addressing mode");
888 if (expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
891 // It could be that this is really just an expression prefixing a
892 // register as a displacement...
899 // Otherwise, check for PC & etc displacements...
900 if (*tok.u32++ != ',')
903 if ((*tok.u32 >= KW_A0) && (*tok.u32 <= KW_A7))
905 AnREG = *tok.u32 & 7;
913 else if (*tok.u32 == ')')
922 else if (*tok.u32 == KW_PC)
924 if (*++tok.u32 == ',')
929 else if (*tok.u32 == ')')
931 AMn = PCDISP; // expr(PC)
942 else if (*tok.u32 == '-' && tok.u32[1] == '(' && ((tok.u32[2] >= KW_A0) && (tok.u32[2] <= KW_A7)) && tok.u32[3] == ')')
945 AnREG = tok.u32[2] & 7;
948 else if (*tok.u32 == KW_CCR)
954 else if (*tok.u32 == KW_SR)
960 else if (*tok.u32 == KW_USP)
964 AnREG = 2; //Added this for the case of USP used in movec (see CREGlut in mach.c). Hopefully nothing gets broken!
967 else if ((*tok.u32 >= KW_IC40) && (*tok.u32 <= KW_BC40))
970 AnREG = *tok.u32++ - KW_IC40;
972 // After a cache keyword only a comma or EOL is allowed
973 if ((*tok.u32 != ',') && (*tok.u32 != EOL))
977 else if ((*tok.u32 >= KW_SFC) && (*tok.u32 <= KW_CRP))
980 AnREG = (*tok.u32++) - KW_SFC;
983 else if ((*tok.u32 >= KW_FP0) && (*tok.u32 <= KW_FP7))
986 AnREG = (*tok.u32++ & 7);
988 else if ((*tok.u32 >= KW_FPIAR) && (*tok.u32 <= KW_FPCR))
991 AnREG = (1 << ((*tok.u32++) - KW_FPIAR + 10));
1002 if (expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
1006 if (*tok.u32 == DOTW)
1012 if (((AnEXATTR & (TDB | DEFINED)) == DEFINED) && (AnEXVAL < 0x10000))
1013 AnEXVAL = (int32_t)(int16_t)AnEXVAL; // Sign extend value
1017 else if (*tok.u32 != '(')
1022 // Defined, absolute values from $FFFF8000..$00007FFF get optimized
1023 // to absolute short
1024 if (CHECK_OPTS(OPT_ABS_SHORT)
1025 && ((AnEXATTR & (TDB | DEFINED)) == DEFINED)
1026 && (((uint32_t)AnEXVAL + 0x8000) < 0x10000))
1031 warn("absolute value from $FFFF8000..$00007FFF optimised to absolute short");
1034 // Is .L forced here?
1035 if (*tok.u32 == DOTL)
1046 if ((*tok.u32 >= KW_A0) && (*tok.u32 <= KW_A7))
1048 AnREG = *tok.u32++ & 7;
1050 if (*tok.u32 == ')')
1060 else if (*tok.u32 == KW_PC)
1062 if (*++tok.u32 == ')')
1076 // Addressing mode OK
1081 // Clean up dirty little macros
1096 #undef CHK_FOR_DISPn
1103 #undef IS_SUPPRESSEDn