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
23 extern char unsupport[];
25 // Address-mode information
26 int nmodes; // Number of addr'ing modes found
27 int am0; // Addressing mode
28 int a0reg; // Register
29 TOKEN a0expr[EXPRSIZE]; // Expression
30 uint64_t a0exval; // Expression's value
31 WORD a0exattr; // Expression's attribute
32 int a0ixreg; // Index register
33 int a0ixsiz; // Index register size (and scale)
34 TOKEN a0oexpr[EXPRSIZE]; // Outer displacement expression
35 uint64_t a0oexval; // Outer displacement value
36 WORD a0oexattr; // Outer displacement attribute
37 SYM * a0esym; // External symbol involved in expr
38 TOKEN a0bexpr[EXPRSIZE]; // Base displacement expression
39 uint64_t a0bexval; // Base displacement value
40 WORD a0bexattr; // Base displacement attribute
41 WORD a0bsize; // Base displacement size
42 WORD a0extension; // 020+ extension address word
43 WORD am0_030; // ea bits for 020+ addressing modes
45 int am1; // Addressing mode
46 int a1reg; // Register
47 TOKEN a1expr[EXPRSIZE]; // Expression
48 uint64_t a1exval; // Expression's value
49 WORD a1exattr; // Expression's attribute
50 int a1ixreg; // Index register
51 int a1ixsiz; // Index register size (and scale)
52 TOKEN a1oexpr[EXPRSIZE]; // Outer displacement expression
53 uint64_t a1oexval; // Outer displacement value
54 WORD a1oexattr; // Outer displacement attribute
55 SYM * a1esym; // External symbol involved in expr
56 TOKEN a1bexpr[EXPRSIZE]; // Base displacement expression
57 uint64_t a1bexval; // Base displacement value
58 WORD a1bexattr; // Base displacement attribute
59 WORD a1bsize; // Base displacement size
60 WORD a1extension; // 020+ extension address word
61 WORD am1_030; // ea bits for 020+ addressing modes
63 int a2reg; // Register for div.l (68020+)
64 WORD mulmode; // to distinguish between 32 and 64 bit multiplications (68020+)
66 int bfparam1; // bfxxx / fmove instruction parameter 1
67 int bfparam2; // bfxxx / fmove instruction parameter 2
68 int bfval1; //bfxxx / fmove value 1
69 int bfval2; //bfxxx / fmove value 2
70 TOKEN bf0expr[EXPRSIZE]; // Expression
71 uint64_t bf0exval; // Expression's value
72 WORD bf0exattr; // Expression's attribute
73 SYM * bf0esym; // External symbol involved in expr
75 // Function prototypes
80 // Parse addressing mode
84 // Initialize global return values
85 nmodes = a0reg = a1reg = 0;
87 a0expr[0] = a0oexpr[0] = a1expr[0] = a1oexpr[0] = ENDEXPR;
88 a0exattr = a0oexattr = a1exattr = a1oexattr = 0;
89 a0esym = a1esym = NULL;
90 a0bexpr[0] = a1bexpr[0] = ENDEXPR;
91 a0bexval = a1bexval = 0;
92 a0bsize = a0extension = a1bsize = a1extension = 0;
93 am0_030 = am1_030 = 0;
94 bfparam1 = bfparam2 = 0;
99 // If at EOL, then no addr modes at all
103 // Parse first addressing mode
107 #define AnIXREG a0ixreg
108 #define AnIXSIZ a0ixsiz
109 #define AnEXPR a0expr
110 #define AnEXVAL a0exval
111 #define AnEXATTR a0exattr
112 #define AnOEXPR a0oexpr
113 #define AnOEXVAL a0oexval
114 #define AnOEXATTR a0oexattr
115 #define AnESYM a0esym
116 #define AMn_IX0 am0_ix0
117 #define AMn_IXN am0_ixn
118 #define CHK_FOR_DISPn CheckForDisp0
119 #define AnBEXPR a0bexpr
120 #define AnBEXVAL a0bexval
121 #define AnBEXATTR a0bexattr
122 #define AnBZISE a0bsize
123 #define AnEXTEN a0extension
124 #define AMn_030 am0_030
125 #define IS_SUPPRESSEDn IS_SUPPRESSED0
126 #define CHECKODn CHECKOD0
129 // If caller wants only one mode, return just one (ignore comma);. If there
130 // is no second addressing mode (no comma), then return just one anyway.
133 // it's a bitfield instruction--check the parameters inside the {} block
136 if (check030bf() == ERROR)
139 if ((acount == 0) || (*tok != ','))
145 // Parse second addressing mode
149 #define AnIXREG a1ixreg
150 #define AnIXSIZ a1ixsiz
151 #define AnEXPR a1expr
152 #define AnEXVAL a1exval
153 #define AnEXATTR a1exattr
154 #define AnOEXPR a1oexpr
155 #define AnOEXVAL a1oexval
156 #define AnOEXATTR a1oexattr
157 #define AnESYM a1esym
158 #define AMn_IX0 am1_ix0
159 #define AMn_IXN am1_ixn
160 #define CHK_FOR_DISPn CheckForDisp1
161 #define AnBEXPR a1bexpr
162 #define AnBEXVAL a1bexval
163 #define AnBEXATTR a1bexattr
164 #define AnBZISE a1bsize
165 #define AnEXTEN a1extension
166 #define AMn_030 am1_030
167 #define IS_SUPPRESSEDn IS_SUPPRESSED1
168 #define CHECKODn CHECKOD1
171 // It's a bitfield instruction--check the parameters inside the {} block
174 if (check030bf() == ERROR)
177 // At this point, it is legal for 020+ to have a ':'. For example divu.l
181 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
182 return error(unsupport);
184 // TODO: protect this from combinations like Dx:FPx etc :)
185 tok++; //eat the colon
187 if ((*tok >= KW_D0) && (*tok <= KW_D7))
189 a2reg = (*tok - KW_D0);
192 else if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
194 a2reg = (*tok - KW_FP0);
198 return error("a data or FPU register must follow a :");
204 // If no ':' is present then maybe we have something like divs.l d0,d1
205 // which sould translate to divs.l d0,d1:d1
215 return error("addressing mode syntax");
218 //return error("unimplemented addressing mode");
223 // Parse register list
225 int reglist(WORD * a_rmask)
227 static WORD msktab[] = {
228 0x0001, 0x0002, 0x0004, 0x0008,
229 0x0010, 0x0020, 0x0040, 0x0080,
230 0x0100, 0x0200, 0x0400, 0x0800,
231 0x1000, 0x2000, 0x4000, 0x8000
239 if ((*tok >= KW_D0) && (*tok <= KW_A7))
248 if ((*tok >= KW_D0) && (*tok <= KW_A7))
251 return error("register list syntax");
254 return error("register list order");
262 rmask |= msktab[r++];
277 // Parse FPU register list
279 int fpu_reglist_left(WORD * a_rmask)
281 static WORD msktab_minus[] = {
282 0x0080, 0x0040, 0x0020, 0x0010,
283 0x0008, 0x0004, 0x0002, 0x0001
291 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
300 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
303 return error("register list syntax");
306 return error("register list order");
316 rmask |= msktab_minus[r++];
330 int fpu_reglist_right(WORD * a_rmask)
332 static WORD msktab_plus[] = {
333 0x0001, 0x0002, 0x0004, 0x0008,
334 0x0010, 0x0020, 0x0040, 0x0080
342 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
351 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
354 return error("register list syntax");
357 return error("register list order");
365 rmask |= msktab_plus[r++];
380 // Check for bitfield instructions extra params
381 // These are 020+ instructions and have the following syntax:
382 // bfxxx <ea>{param1,param2}
383 // param1/2 are either data registers or immediate values
393 bfval1 = (int)*(uint64_t *)tok;
395 // Do=0, offset=immediate - shift it to place
396 bfparam1 = (0 << 11);
400 else if (*tok == SYMBOL)
402 if (expr(bf0expr, &bf0exval, &bf0exattr, &bf0esym) != OK)
405 if (!(bf0exattr & DEFINED))
406 return error("bfxxx offset: immediate value must evaluate");
408 bfval1 = (int)bf0exval;
410 // Do=0, offset=immediate - shift it to place
411 bfparam1 = (0 << 11);
413 else if ((*tok >= KW_D0) && (*tok <= KW_D7))
415 // Do=1, offset=data register - shift it to place
416 bfparam1 = (1 << 11);
417 bfval1 = (*(int *)tok - 128);
426 if (*tok == '}' && tok[1] == EOL)
428 // It is ok to have }, EOL here - it might be "fmove fpn,<ea> {dx}"
436 bfval2 = (int)*(uint64_t *)tok;
438 // Do=0, offset=immediate - shift it to place
443 else if (*tok == SYMBOL)
445 if (expr(bf0expr, &bf0exval, &bf0exattr, &bf0esym) != OK)
448 bfval2 = (int)bf0exval;
450 if (!(bf0exattr & DEFINED))
451 return error("bfxxx width: immediate value must evaluate");
453 // Do=0, offset=immediate - shift it to place
456 else if ((*tok >= KW_D0) && (*tok <= KW_D7))
458 // Do=1, offset=data register - shift it to place
459 bfval2 = ((*(int *)tok - 128));
466 tok++; // Eat the '}'