2 // RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
3 // PARMODE.C - Addressing Modes Parser Include
4 // Copyright (C) 199x Landon Dyer, 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)
84 AnEXTEN |= EXT_FULLWORD; // Definitely using full extension format, so set bit 8
85 AnEXTEN |= EXT_BS; // Base register suppressed
86 AnEXTEN |= EXT_BDSIZE0; // Base displacement null
87 AnEXTEN |= EXT_IISPOSN; // Indirect Postindexed with Null Outer Displacement
89 AnREG = 6 << 3; // stuff 110 to mode field
94 // TODO: does DINDL gets used at all?
95 //AMn=DINDL; // (Dn.l)
96 //AnEXTEN = 1 << 1; // Long index size
99 else if (*tok == 'W') // (Dn.w)
101 // TODO: does DINDW gets used at all?
103 //AnEXTEN = 1 << 1; // Word index size
106 else if (*tok == ',')
108 // ([bd,An],Xn..) without bd, An
109 // Base displacement is suppressed
110 AnEXTEN |= EXT_FULLWORD; // Definitely using full extension format, so set bit 8
111 AnEXTEN |= EXT_BS; // Base register suppressed
112 AnEXTEN |= EXT_BDSIZE0;
113 AnREG = 6 << 3; // stuff 110 to mode field
118 return error("(Dn) error");
123 AnEXTEN |= EXT_FULLWORD; // Definitely using full extension format, so set bit 8
124 AnEXTEN |= EXT_BS; // Base register suppressed
125 AnEXTEN |= EXT_BDSIZE0; // Base displacement null
126 AnEXTEN |= EXT_IISPOSN; // Indirect Postindexed with Null Outer Displacement
127 AnREG = 6 << 3; // stuff 110 to mode field
132 return error("unhandled so far");
134 else if (*tok == KW_PC)
135 { // (PC,Xn[.siz][*scale])
139 // Common index handler; enter here with 'tok' pointing at the
142 AMn_IX0: // Handle indexed with missing expr
145 AnEXATTR = ABS | DEFINED;
147 AMn_IXN: // Handle any indexed (tok -> a comma)
152 if (*tok < KW_D0 || *tok > KW_A7)
155 AnIXREG = *tok++ & 15;
158 { // Index reg size: <empty> | .W | .L
168 case DOTB: // .B not allowed here...
173 { // scale: *1, *2, *4, *8
176 if (*tok++ != CONST || *tok > 8)
197 if (*tok++ != ')') // final ")"
202 else if (*tok == '[')
205 AnEXTEN|=EXT_FULLWORD; //Definitely using full extension format, so set bit 8
206 // Check to see if base displacement is present
207 //WARNING("expr will return a bad expression error here but this is expected, it needs to be silenced!");
208 if (*tok!=CONST && *tok !=SYMBOL)
209 //if (expr(AnBEXPR, &AnBEXVAL, &AnBEXATTR, &AnESYM) != OK)
211 AnEXTEN|=EXT_BDSIZE0;
213 //tok--; //Rewind tok since expr advances it forward
217 expr(AnBEXPR, &AnBEXVAL, &AnBEXATTR, &AnESYM);
218 if (optim_flags[OPT_BASE_DISP] && AnBEXVAL==0 && AnEXATTR!=0)
220 // bd=0 so let's optimise it out
221 AnEXTEN|=EXT_BDSIZE0;
225 AnEXTEN|=EXT_BDSIZEL;
229 { // ([bd[.w],... or ([bd,...
230 // Is .W forced here?
233 AnEXTEN|=EXT_BDSIZEW;
238 // Defined, absolute values from $FFFF8000..$00007FFF get optimized
240 if (optim_flags[OPT_ABS_SHORT]
241 && ((AnBEXATTR & (TDB | DEFINED)) == DEFINED)
242 && ((AnBEXVAL + 0x8000) < 0x10000))
244 AnEXTEN |= EXT_BDSIZEW;
245 warn("absolute value in base displacement ranging $FFFF8000..$00007FFF optimised to absolute short");
249 AnEXTEN |= EXT_BDSIZEL;
257 // return error("Comma expected after base displacement");
260 // Check for address register or PC, suppress base register
265 AnREG = (7 << 3) | 3; // PC is special case - stuff 011 to register field and 111 to the mode field
268 else if ((*tok >= KW_A0) && (*tok <= KW_A7))
270 AnREG = (6<<3)|*tok & 7;
273 else if ((*tok >= KW_D0) && (*tok <= KW_D7))
277 AnEXTEN |= ((*tok & 7) << 12);
279 AnEXTEN |= EXT_BS; // Oh look, a data register! Which means that base register is suppressed
284 // ([bd,An/PC],Xn.W/L...)
287 // Index reg size: <empty> | .W | .L
298 // .B not allowed here...
304 if (*tok == '*') // ([bd,An/PC],Xn*...)
308 if (*tok == CONST) // TODO: I suppose the scale is stored as a CONST and nothing else? So prolly the if is not needed?
316 AnEXTEN |= EXT_TIMES2;
319 AnEXTEN |= EXT_TIMES4;
322 AnEXTEN |= EXT_TIMES8;
329 if (*tok == ']') // ([bd,Dn]...
335 else if (*tok == ']')
337 // PC and Xn is suppressed
338 AnREG = 6 << 3; // stuff 110 to mode field
339 //AnEXTEN|=EXT_BS|EXT_IS;
347 // At a crossroads here. We can accept either ([bd,An/PC],... or ([bd,An/PC,Xn*scale],...
356 //Xn and od are non existent, get out of jail free card
357 AMn = MEMPRE; // ([bc,An,Xn],od) with no Xn and od
358 AnEXTEN |= EXT_IS | EXT_IISPREN; //Suppress Xn and od
362 else if (*tok != ',')
363 return error("comma expected after ]");
365 tok++; // eat the comma
367 if ((*tok >= KW_A0) && (*tok <= KW_A7))
369 AnIXREG = ((*tok & 7) << 12);
373 else if ((*tok >= KW_D0) && (*tok <= KW_D7))
375 AnEXTEN |= ((*tok & 7) << 12);
381 //No index found, suppress it
383 tok--; // Rewind tok to point to the comma
384 goto IS_SUPPRESSEDn; // https://xkcd.com/292/ - what does he know anyway?
389 // ([bd,An/PC],Xn.W/L...)
392 // Index reg size: <empty> | .W | .L
403 // .B not allowed here...
411 // ([bd,An/PC],Xn*...)
414 if (*tok == CONST) // TODO: I suppose the scale is stored as a CONST and nothing else? So prolly the if is not needed?
422 AnEXTEN |= EXT_TIMES2;
425 AnEXTEN |= EXT_TIMES4;
428 AnEXTEN |= EXT_TIMES8;
436 if (*tok == ')') // ([bd,An/PC],Xn)
438 //od is non existant, get out of jail free card
439 AMn = MEMPOST; // let's say it's ([bd,An],Xn,od) with od=0 then
440 AnEXTEN |= EXT_IISPOSN; // No outer displacement
445 return error("comma expected");
447 tok++; // eat the comma
451 if (expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
454 if (optim_flags[OPT_BASE_DISP] && (AnEXVAL == 0))
456 // od=0 so optimise it out
457 AMn = MEMPOST; // let's say it's ([bd,An],Xn,od) with od=0 then
458 AnEXTEN |= EXT_IISPOSN; // No outer displacement
463 // ([bd,An/PC],Xn,od)
467 AnEXTEN |= EXT_IISPOSL; // Long outer displacement
470 // Defined, absolute values from $FFFF8000..$00007FFF get
471 // optimized to absolute short
472 if (optim_flags[OPT_ABS_SHORT]
473 && ((AnEXATTR & (TDB | DEFINED)) == DEFINED)
474 && ((AnEXVAL + 0x8000) < 0x10000))
476 AnEXTEN |= EXT_IISPOSW; // Word outer displacement
478 warn("outer displacement absolute value from $FFFF8000..$00007FFF optimised to absolute short");
485 AnEXTEN |= EXT_IISPOSW; // Word outer displacement
488 // Is .W forced here?
495 // Check for final closing parenthesis
502 return error("Closing parenthesis missing on addressing mode");
507 if (*tok == ')') // ([bd,An/PC],Xn)
509 //od is non existant, get out of jail free card
510 AMn = MEMPOST; // let's say it's ([bd,An],Xn,od) with od=0 then
511 AnEXTEN |= EXT_IISNOIN; // No outer displacement
516 return error("comma expected");
518 tok++; // eat the comma
520 if ((*tok != CONST) && (*tok != SYMBOL))
523 expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM);
525 if (optim_flags[OPT_BASE_DISP] && (AnEXVAL == 0))
527 // od=0 so optimise it out
528 AMn = MEMPOST; // let's say it's ([bd,An],Xn,od) with od=0 then
529 AnEXTEN |= EXT_IISNOIN; // No outer displacement
534 // ([bd,An/PC],Xn,od)
540 AnEXTEN |= EXT_IISNOIL; // Long outer displacement with IS suppressed
545 AnEXTEN |= EXT_IISNOIW; // Word outer displacement with IS suppressed
550 //AnEXTEN|=EXT_IISNOIW; // Word outer displacement
555 // Defined, absolute values from $FFFF8000..$00007FFF get
556 // optimized to absolute short
557 else if (optim_flags[OPT_BASE_DISP]
558 && ((AnEXATTR & (TDB | DEFINED)) == DEFINED)
559 && ((AnEXVAL + 0x8000) < 0x10000))
561 //AnEXTEN|=EXT_IISNOIW; // Word outer displacement with IS suppressed
562 warn("outer displacement absolute value from $FFFF8000..$00007FFF optimised to absolute short");
566 // Check for final closing parenthesis
573 return error("Closing parenthesis missing on addressing mode");
575 else if (*tok == ',')
577 *tok++; // ([bd,An,Xn.size*scale],od)
580 if ((*tok >= KW_A0) && (*tok <= KW_A7))
582 AnEXTEN |= ((*tok & 7) << 12);
586 else if ((*tok >= KW_D0) && (*tok <= KW_D7))
588 AnEXTEN |= ((*tok & 7) << 12);
595 // ([bd,An/PC],Xn.W/L...)
598 // Index reg size: <empty> | .W | .L
609 // .B not allowed here...
615 if (*tok == '*') // ([bd,An/PC],Xn*...)
619 if (*tok == CONST) // TODO: I suppose the scale is stored as a CONST and nothing else? So prolly the if is not needed?
627 AnEXTEN |= EXT_TIMES2;
630 AnEXTEN |= EXT_TIMES4;
633 AnEXTEN |= EXT_TIMES8;
642 return error("Expected closing bracket ]");
644 tok++; // Eat the bracket
647 if (*tok == ')') // ([bd,An/PC,Xn]...
649 //od is non existant, get out of jail free card
650 //AnEXVAL=0; // zero outer displacement
651 AMn = MEMPRE; // let's say it's ([bd,An,Xn],od) with od suppressed then
652 AnEXTEN |= EXT_IISPREN; // No outer displacement
656 else if (*tok++!=',')
657 return error("comma expected after ]");
659 WARNING(Put symbol and constant checks here!)
661 if (expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
664 if (optim_flags[OPT_BASE_DISP] && (AnEXVAL == 0))
666 // od=0 so optimise it out
667 AMn = MEMPRE; // let's say it's ([bd,An],Xn,od) with od=0 then
668 AnEXTEN |= EXT_IISPRE0; // No outer displacement
673 // ([bd,An/PC,Xn],od)
679 AnEXTEN |= EXT_IISPREL;
686 AnEXTEN |= EXT_IISPREW;
689 // Is .W forced here?
695 // Defined, absolute values from $FFFF8000..$00007FFF get optimized
697 else if (optim_flags[OPT_BASE_DISP]
698 && ((AnEXATTR & (TDB | DEFINED)) == DEFINED)
699 && ((AnEXVAL + 0x8000) < 0x10000))
701 AnEXTEN |= EXT_IISPREW;
702 warn("outer displacement absolute value from $FFFF8000..$00007FFF optimised to absolute short");
706 // Check for final closing parenthesis
713 return error("Closing parenthesis missing on addressing mode");
721 if (expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
724 // It could be that this is really just an expression prefixing a
725 // register as a displacement...
732 // Otherwise, check for PC & etc displacements...
736 if ((*tok >= KW_A0) && (*tok <= KW_A7))
746 else if (*tok == ')')
755 else if (*tok == KW_PC)
762 else if (*tok == ')')
764 AMn = PCDISP; // expr(PC)
775 else if (*tok == '-' && tok[1] == '(' && ((tok[2] >= KW_A0) && (tok[2] <= KW_A7)) && tok[3] == ')')
781 else if (*tok == KW_CCR)
787 else if (*tok == KW_SR)
793 else if (*tok == KW_USP)
797 AnREG = 2; //Added this for the case of USP used in movec (see CREGlut in mach.c). Hopefully nothing gets broken!
800 else if ((*tok >= KW_IC40) && (*tok <= KW_BC40))
803 AnREG = *tok++ - KW_IC40;
805 // After a cache keyword only a comma or EOL is allowed
806 if ((*tok != ',') && (*tok != EOL))
811 else if ((*tok >= KW_SFC) && (*tok <= KW_CRP))
814 AnREG = (*tok++) - KW_SFC;
817 else if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
820 AnREG = (*tok++ & 7);
822 else if ((*tok >= KW_FPIAR) && (*tok <= KW_FPCR))
825 AnREG = (1 << ((*tok++) - KW_FPIAR + 10));
836 if (expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
846 if (((AnEXATTR & (TDB | DEFINED)) == DEFINED) && (AnEXVAL < 0x10000))
847 AnEXVAL = (int32_t)(int16_t)AnEXVAL; // Sign extend value
851 else if (*tok != '(')
856 // Defined, absolute values from $FFFF8000..$00007FFF get optimized
858 if (optim_flags[OPT_ABS_SHORT]
859 && ((AnEXATTR & (TDB | DEFINED)) == DEFINED)
860 && ((AnEXVAL + 0x8000) < 0x10000))
865 warn("absolute value from $FFFF8000..$00007FFF optimised to absolute short");
868 // Is .L forced here?
880 if ((*tok >= KW_A0) && (*tok <= KW_A7))
894 else if (*tok == KW_PC)
909 // Addressing mode OK
914 // Clean up dirty little macros
936 #undef IS_SUPPRESSEDn