2 // RMAC - Reboot's Macro Assembler for all Atari computers
3 // AMODE.C - Addressing Modes
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
24 // Address-mode information
25 int nmodes; // Number of addr'ing modes found
26 int am0; // Addressing mode
27 int a0reg; // Register
28 TOKEN a0expr[EXPRSIZE]; // Expression
29 VALUE a0exval; // Expression's value
30 WORD a0exattr; // Expression's attribute
31 int a0ixreg; // Index register
32 int a0ixsiz; // Index register size (and scale)
33 TOKEN a0oexpr[EXPRSIZE]; // Outer displacement expression
34 VALUE a0oexval; // Outer displacement value
35 WORD a0oexattr; // Outer displacement attribute
36 SYM * a0esym; // External symbol involved in expr
37 TOKEN a0bexpr[EXPRSIZE]; // Base displacement expression
38 VALUE a0bexval; // Base displacement value
39 WORD a0bexattr; // Base displacement attribute
40 WORD a0bsize; // Base displacement size
41 WORD a0extension; // 020+ extension address word
42 WORD am0_030; // ea bits for 020+ addressing modes
44 int am1; // Addressing mode
45 int a1reg; // Register
46 TOKEN a1expr[EXPRSIZE]; // Expression
47 VALUE a1exval; // Expression's value
48 WORD a1exattr; // Expression's attribute
49 int a1ixreg; // Index register
50 int a1ixsiz; // Index register size (and scale)
51 TOKEN a1oexpr[EXPRSIZE]; // Outer displacement expression
52 VALUE a1oexval; // Outer displacement value
53 WORD a1oexattr; // Outer displacement attribute
54 SYM * a1esym; // External symbol involved in expr
55 TOKEN a1bexpr[EXPRSIZE]; // Base displacement expression
56 VALUE a1bexval; // Base displacement value
57 WORD a1bexattr; // Base displacement attribute
58 WORD a1bsize; // Base displacement size
59 WORD a1extension; // 020+ extension address word
60 WORD am1_030; // ea bits for 020+ addressing modes
62 int a2reg; // Register for div.l (68020+)
63 WORD mulmode; // To distinguish between 32 and 64 bit multiplications (68020+)
65 int bfparam1; // bfxxx instruction parameter 1
66 int bfparam2; // bfxxx instruction parameter 2
67 TOKEN bf0expr[EXPRSIZE]; // Expression
68 VALUE bf0exval; // Expression's value
69 WORD bf0exattr; // Expression's attribute
70 SYM * bf0esym; // External symbol involved in expr
72 // Function prototypes
77 // Parse addressing mode
81 // Initialize global return values
82 nmodes = a0reg = a1reg = 0;
84 a0expr[0] = a0oexpr[0] = a1expr[0] = a1oexpr[0] = ENDEXPR;
85 a0exattr = a0oexattr = a1exattr = a1oexattr = 0;
86 a0esym = a1esym = NULL;
87 a0bexpr[0] = a1bexpr[0] = ENDEXPR;
88 a0bexval = a0bsize = a0extension = a1bexval = a1bsize = a1extension = 0;
89 am0_030 = am1_030 = 0;
90 bfparam1 = bfparam2 = 0;
95 // If at EOL, then no addr modes at all
99 // Parse first addressing mode
103 #define AnIXREG a0ixreg
104 #define AnIXSIZ a0ixsiz
105 #define AnEXPR a0expr
106 #define AnEXVAL a0exval
107 #define AnEXATTR a0exattr
108 #define AnOEXPR a0oexpr
109 #define AnOEXVAL a0oexval
110 #define AnOEXATTR a0oexattr
111 #define AnESYM a0esym
112 #define AMn_IX0 am0_ix0
113 #define AMn_IXN am0_ixn
114 #define CHK_FOR_DISPn CheckForDisp0
115 #define AnBEXPR a0bexpr
116 #define AnBEXVAL a0bexval
117 #define AnBEXATTR a0bexattr
118 #define AnBZISE a0bsize
119 #define AnEXTEN a0extension
120 #define AMn_030 am0_030
121 #define IS_SUPPRESSEDn IS_SUPPRESSED0
122 #define CHECKODn CHECKOD0
125 // If caller wants only one mode, return just one (ignore comma);. If there
126 // is no second addressing mode (no comma), then return just one anyway.
129 // it's a bitfield instruction--check the parameters inside the {} block
131 if ((*tok == '{') && (check030bf() == ERROR))
134 if ((acount == 0) || (*tok != ','))
140 // Parse second addressing mode
144 #define AnIXREG a1ixreg
145 #define AnIXSIZ a1ixsiz
146 #define AnEXPR a1expr
147 #define AnEXVAL a1exval
148 #define AnEXATTR a1exattr
149 #define AnOEXPR a1oexpr
150 #define AnOEXVAL a1oexval
151 #define AnOEXATTR a1oexattr
152 #define AnESYM a1esym
153 #define AMn_IX0 am1_ix0
154 #define AMn_IXN am1_ixn
155 #define CHK_FOR_DISPn CheckForDisp1
156 #define AnBEXPR a1bexpr
157 #define AnBEXVAL a1bexval
158 #define AnBEXATTR a1bexattr
159 #define AnBZISE a1bsize
160 #define AnEXTEN a1extension
161 #define AMn_030 am1_030
162 #define IS_SUPPRESSEDn IS_SUPPRESSED1
163 #define CHECKODn CHECKOD1
166 // It's a bitfield instruction--check the parameters inside the {} block
168 if ((*tok == '{') && (check030bf() == ERROR))
171 // At this point, it is legal for 020+ to have a ':'. For example divu.l
175 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
176 return error(unsupport);
178 // TODO: protect this from combinations like Dx:FPx etc :)
179 tok++; //eat the colon
181 if ((*tok >= KW_D0) && (*tok <= KW_D7))
183 a2reg = (*tok - KW_D0);
186 else if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
188 a2reg = (*tok - KW_FP0);
192 return error("a data or FPU register must follow a :");
198 // If no ':' is present then maybe we have something like divs.l d0,d1
199 // which sould translate to divs.l d0,d1:d1
209 return error("addressing mode syntax");
212 //return error("unimplemented addressing mode");
217 // Parse register list
219 int reglist(WORD * a_rmask)
221 static WORD msktab[] = {
222 0x0001, 0x0002, 0x0004, 0x0008,
223 0x0010, 0x0020, 0x0040, 0x0080,
224 0x0100, 0x0200, 0x0400, 0x0800,
225 0x1000, 0x2000, 0x4000, 0x8000
233 if ((*tok >= KW_D0) && (*tok <= KW_A7))
242 if ((*tok >= KW_D0) && (*tok <= KW_A7))
245 return error("register list syntax");
248 return error("register list order");
256 rmask |= msktab[r++];
271 // Parse FPU register list
273 int fpu_reglist_left(WORD * a_rmask)
275 static WORD msktab_minus[] = {
276 0x0080, 0x0040, 0x0020, 0x0010,
277 0x0008, 0x0004, 0x0002, 0x0001
285 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
294 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
297 return error("register list syntax");
300 return error("register list order");
308 rmask |= msktab_minus[r++];
322 int fpu_reglist_right(WORD * a_rmask)
324 static WORD msktab_plus[] = {
325 0x0001, 0x0002, 0x0004, 0x0008,
326 0x0010, 0x0020, 0x0040, 0x0080
334 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
343 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
346 return error("register list syntax");
349 return error("register list order");
357 rmask |= msktab_plus[r++];
372 // Check for bitfield instructions extra params
373 // These are 020+ instructions and have the following syntax:
374 // bfxxx <ea>{param1,param2}
375 // param1/2 are either data registers or immediate values
379 WARNING(Add more strict checks as well as checks for non defined (yet) labels)
381 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
382 return error(unsupport);
389 bfparam1 = *(int *)tok;
391 if ((bfparam1 > 31) || (bfparam1 < 0))
392 return error("bfxxx offset: immediate value must be between 0 and 31");
394 // Do=0, offset=immediate - shift it to place
395 bfparam1 = (bfparam1 << 6) | (0 << 11);
398 else if (*tok == SYMBOL)
400 if (expr(bf0expr, &bf0exval, &bf0exattr, &bf0esym) != OK)
405 if ((bfparam1 > 31) || (bfparam1 < 0))
406 return error("bfxxx offset: immediate value must be between 0 and 31");
408 // Do=0, offset=immediate - shift it to place
409 bfparam1 = (bfparam1 << 6) | (0 << 11);
411 else if ((*tok >= KW_D0) && (*tok <= KW_D7))
413 // Do=1, offset=data register - shift it to place
414 bfparam1 = ((*(int *)tok - 128) << 6) | (1 << 11);
423 if (*tok == '}' && tok[1] == EOL)
425 // It is ok to have }, EOL here - it might be "fmove fpn,<ea> {dx}"
433 bfparam2 = *(int *)tok;
435 if (bfparam2 > 31 || bfparam2 < 0)
436 return error("bfxxx width: immediate value must be between 0 and 31");
438 // Do=0, offset=immediate - shift it to place
439 bfparam2 = (bfparam2 << 0) | (0 << 5);
442 else if (*tok == SYMBOL)
444 if (expr(bf0expr, &bf0exval, &bf0exattr, &bf0esym) != OK)
449 if (bfparam2 > 31 || bfparam2 < 0)
450 return error("bfxxx width: immediate value must be between 0 and 31");
452 // Do=0, offset=immediate - shift it to place
453 bfparam2 = (bfparam2 << 0) | (0 << 5);
455 else if ((*tok >= KW_D0) && (*tok <= KW_D7))
457 // Do=1, offset=data register - shift it to place
458 bfparam2 = ((*(int *)tok - 128) << 0) | (1 << 5);
464 tok++; // Eat the '}'