2 // RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
3 // AMODE.C - Addressing Modes
4 // Copyright (C) 199x Landon Dyer, 2011 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 VALUE 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 VALUE 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 VALUE 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 VALUE 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 VALUE 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 VALUE 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+)
67 // Parse addressing mode
71 // Initialize global return values
72 nmodes = a0reg = a1reg = 0;
74 a0expr[0] = a0oexpr[0] = a1expr[0] = a1oexpr[0] = ENDEXPR;
75 a0exattr = a0oexattr = a1exattr = a1oexattr = 0;
76 a0esym = a1esym = (SYM *)NULL;
77 a0bexpr[0]=a1bexpr[0]= ENDEXPR;
78 a0bexval=a0bsize=a0extension=a1bexval=a1bsize=a1extension=0;
85 // If at EOL, then no addr modes at all
89 // Parse first addressing mode
93 #define AnIXREG a0ixreg
94 #define AnIXSIZ a0ixsiz
96 #define AnEXVAL a0exval
97 #define AnEXATTR a0exattr
98 #define AnOEXPR a0oexpr
99 #define AnOEXVAL a0oexval
100 #define AnOEXATTR a0oexattr
101 #define AnESYM a0esym
102 #define AMn_IX0 am0_ix0
103 #define AMn_IXN am0_ixn
104 #define CHK_FOR_DISPn CheckForDisp0
105 #define AnBEXPR a0bexpr
106 #define AnBEXVAL a0bexval
107 #define AnBEXATTR a0bexattr
108 #define AnBZISE a0bsize
109 #define AnEXTEN a0extension
110 #define AMn_030 am0_030
111 #define IS_SUPPRESSEDn IS_SUPPRESSED0
112 #define CHECKODn CHECKOD0
115 // If caller wants only one mode, return just one (ignore comma);
116 // If there is no second addressing mode (no comma), then return just one anyway.
120 if (check030bf()==ERROR) // it's a bitfield instruction - check the parameters inside the {} block for validity
123 if (acount == 0 || *tok != ',')
129 // Parse second addressing mode
133 #define AnIXREG a1ixreg
134 #define AnIXSIZ a1ixsiz
135 #define AnEXPR a1expr
136 #define AnEXVAL a1exval
137 #define AnEXATTR a1exattr
138 #define AnOEXPR a1oexpr
139 #define AnOEXVAL a1oexval
140 #define AnOEXATTR a1oexattr
141 #define AnESYM a1esym
142 #define AMn_IX0 am1_ix0
143 #define AMn_IXN am1_ixn
144 #define CHK_FOR_DISPn CheckForDisp1
145 #define AnBEXPR a1bexpr
146 #define AnBEXVAL a1bexval
147 #define AnBEXATTR a1bexattr
148 #define AnBZISE a1bsize
149 #define AnEXTEN a1extension
150 #define AMn_030 am1_030
151 #define IS_SUPPRESSEDn IS_SUPPRESSED1
152 #define CHECKODn CHECKOD1
156 if (check030bf()==ERROR) // it's a bitfield instruction - check the parameters inside the {} block for validity
159 // At this point, it is legal for 020+ to have a ':'. For example divu.l d0,d2:d3
162 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
163 return error(unsupport);
164 // TODO: protect this from combinations like Dx:FPx etc :)
165 tok++; //eat the colon
166 if (*tok >= KW_D0 && *tok <= KW_D7)
168 a2reg = (*tok - KW_D0);
171 else if (*tok >= KW_FP0&&*tok <= KW_FP7)
173 a2reg = (*tok - KW_FP0);
177 return error("a data or FPU register must follow a :");
182 //If no ':' is present then maybe we have something like divs.l d0,d1 which sould translate to divs.l d0,d1:d1
192 return error("addressing mode syntax");
195 //return error("unimplemented addressing mode");
200 // Parse register list
202 int reglist(WORD * a_rmask)
204 static WORD msktab[] = {
205 0x0001, 0x0002, 0x0004, 0x0008,
206 0x0010, 0x0020, 0x0040, 0x0080,
207 0x0100, 0x0200, 0x0400, 0x0800,
208 0x1000, 0x2000, 0x4000, 0x8000
216 if (*tok >= KW_D0 && *tok <= KW_A7)
225 if (*tok >= KW_D0 && *tok <= KW_A7)
228 return error("register list syntax");
231 return error("register list order");
239 rmask |= msktab[r++];
253 // Parse FPU register list
255 int fpu_reglist_left(WORD * a_rmask)
257 static WORD msktab_minus[] = {
258 0x0080, 0x0040, 0x0020, 0x0010,
259 0x0008, 0x0004, 0x0002, 0x0001
267 if (*tok >= KW_FP0 && *tok <= KW_FP7)
276 if (*tok >= KW_FP0 && *tok <= KW_FP7)
279 return error("register list syntax");
282 return error("register list order");
290 rmask |= msktab_minus[r++];
302 int fpu_reglist_right(WORD * a_rmask)
304 static WORD msktab_plus[] = {
305 0x0001, 0x0002, 0x0004, 0x0008,
306 0x0010, 0x0020, 0x0040, 0x0080
314 if (*tok >= KW_FP0 && *tok <= KW_FP7)
323 if (*tok >= KW_FP0 && *tok <= KW_FP7)
326 return error("register list syntax");
329 return error("register list order");
337 rmask |= msktab_plus[r++];
351 // Check for bitfield instructions extra params
352 // These are 020+ instructions and have the following syntax:
353 // bfxxx <ea>{param1,param2}
354 // param1/2 are either data registers or immediate values
359 WARNING (Add more strict checks as well as checks for non defined (yet) labels)
361 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
362 return error(unsupport);
368 bfparam1 = *(int *)tok;
369 if (bfparam1 > 31 || bfparam1 < 0)
370 return error("bfxxx offset: immediate value must be between 0 and 31");
371 bfparam1 = (bfparam1 << 6) | (0 << 11); //Do=0, offset=immediate - shift it to place
374 else if (*tok == SYMBOL)
376 if (expr(bf0expr, &bf0exval, &bf0exattr, &bf0esym) != OK)
379 if (bfparam1 > 31 || bfparam1 < 0)
380 return error("bfxxx offset: immediate value must be between 0 and 31");
381 bfparam1 = (bfparam1 << 6) | (0 << 11); //Do=0, offset=immediate - shift it to place
383 else if (*tok >= KW_D0 && *tok <= KW_D7)
385 bfparam1 = ((*(int *)tok - 128) << 6) | (1 << 11); //Do=1, offset=data register - shift it to place
394 if (*tok == '}' && tok[1] == EOL)
397 return OK; //It is ok to have }, EOL here - it might be "fmove fpn,<ea> {dx}"
404 bfparam2 = *(int *)tok;
405 if (bfparam2 > 31 || bfparam2 < 0)
406 return error("bfxxx width: immediate value must be between 0 and 31");
407 bfparam2 = (bfparam2 << 0) | (0 << 5); //Do=0, offset=immediate - shift it to place
410 else if (*tok == SYMBOL)
412 if (expr(bf0expr, &bf0exval, &bf0exattr, &bf0esym) != OK)
415 if (bfparam2 > 31 || bfparam2 < 0)
416 return error("bfxxx width: immediate value must be between 0 and 31");
417 bfparam2 = (bfparam2 << 0) | (0 << 5); //Do=0, offset=immediate - shift it to place
419 else if (*tok >= KW_D0 && *tok <= KW_D7)
421 bfparam2 = ((*(int *)tok - 128) << 0) | (1 << 5); //Do=1, offset=data register - shift it to place