511e168610c74bdd36c02b7e5209ca58393142ee
[rmac] / amode.c
1 //
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
7 //
8
9 #include "amode.h"
10 #include "error.h"
11 #include "expr.h"
12 #include "mach.h"
13 #include "procln.h"
14 #include "rmac.h"
15 #include "sect.h"
16 #include "token.h"
17
18 #define DEF_KW
19 #include "kwtab.h"
20 #define DEF_MN
21 #include "mntab.h"
22
23
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
43
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
61
62 int a2reg;                                      // Register for div.l (68020+)
63 WORD mulmode;                           // To distinguish between 32 and 64 bit multiplications (68020+)
64
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
71
72 // Function prototypes
73 int check030bf(void);
74
75
76 //
77 // Parse addressing mode
78 //
79 int amode(int acount)
80 {
81         // Initialize global return values
82         nmodes = a0reg = a1reg = 0;
83         am0 = am1 = AM_NONE;
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;
91         bf0expr[0] = ENDEXPR;
92         bf0exattr = 0;
93         bf0esym = NULL;
94
95         // If at EOL, then no addr modes at all
96         if (*tok == EOL)
97                 return 0;
98
99         // Parse first addressing mode
100         #define AnOK      a0ok
101         #define AMn       am0
102         #define AnREG     a0reg
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
123         #include "parmode.h"
124
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.
127         nmodes = 1;
128
129         // it's a bitfield instruction--check the parameters inside the {} block
130         // for validity
131         if ((*tok == '{') && (check030bf() == ERROR))
132                 return ERROR;
133
134         if ((acount == 0) || (*tok != ','))
135                 return 1;
136
137         // Eat the comma
138         tok++;
139
140         // Parse second addressing mode
141         #define AnOK      a1ok
142         #define AMn       am1
143         #define AnREG     a1reg
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
164         #include "parmode.h"
165
166         // It's a bitfield instruction--check the parameters inside the {} block
167         // for validity
168         if ((*tok == '{') && (check030bf() == ERROR))
169                 return ERROR;
170
171         // At this point, it is legal for 020+ to have a ':'. For example divu.l
172         // d0,d2:d3
173         if (*tok == ':')
174         {
175                 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
176                         return error(unsupport);
177
178                 // TODO: protect this from combinations like Dx:FPx etc :)
179                 tok++;  //eat the colon
180
181                 if ((*tok >= KW_D0) && (*tok <= KW_D7))
182                 {
183                         a2reg = (*tok - KW_D0);
184                         mulmode = 1 << 10;
185                 }
186                 else if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
187                 {
188                         a2reg = (*tok - KW_FP0);
189                         mulmode = 1 << 10;
190                 }
191                 else
192                         return error("a data or FPU register must follow a :");
193
194                 *tok++;
195         }
196         else
197         {
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
200                 a2reg = a1reg;
201                 mulmode = 0;
202         }
203
204         nmodes = 2;
205         return 2;
206
207         // Error messages:
208 badmode:
209         return error("addressing mode syntax");
210
211         //unmode:
212         //return error("unimplemented addressing mode");
213 }
214
215
216 //
217 // Parse register list
218 //
219 int reglist(WORD * a_rmask)
220 {
221         static WORD msktab[] = {
222                 0x0001, 0x0002, 0x0004, 0x0008,
223                 0x0010, 0x0020, 0x0040, 0x0080,
224                 0x0100, 0x0200, 0x0400, 0x0800,
225                 0x1000, 0x2000, 0x4000, 0x8000
226         };
227
228         WORD rmask = 0;
229         int r, cnt;
230
231         for(;;)
232         {
233                 if ((*tok >= KW_D0) && (*tok <= KW_A7))
234                         r = *tok++ & 0x0F;
235                 else
236                         break;
237
238                 if (*tok == '-')
239                 {
240                         tok++;
241
242                         if ((*tok >= KW_D0) && (*tok <= KW_A7))
243                                 cnt = *tok++ & 0x0F;
244                         else
245                                 return error("register list syntax");
246
247                         if (cnt < r)
248                                 return error("register list order");
249
250                         cnt -= r;
251                 }
252                 else
253                         cnt = 0;
254
255                 while (cnt-- >= 0)
256                         rmask |= msktab[r++];
257
258                 if (*tok != '/')
259                         break;
260
261                 tok++;
262         }
263
264         *a_rmask = rmask;
265
266         return OK;
267 }
268
269
270 //
271 // Parse FPU register list
272 //
273 int fpu_reglist_left(WORD * a_rmask)
274 {
275         static WORD msktab_minus[] = {
276                 0x0080, 0x0040, 0x0020, 0x0010,
277                 0x0008, 0x0004, 0x0002, 0x0001
278         };
279
280         WORD rmask = 0;
281         int r, cnt;
282
283         for(;;)
284         {
285                 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
286                         r = *tok++ & 0x07;
287                 else
288                         break;
289
290                 if (*tok == '-')
291                 {
292                         tok++;
293
294                         if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
295                                 cnt = *tok++ & 0x07;
296                         else
297                                 return error("register list syntax");
298
299                         if (cnt < r)
300                                 return error("register list order");
301
302                         cnt -= r;
303                 }
304                 else
305                         cnt = 0;
306
307                 while (cnt-- >= 0)
308                         rmask |= msktab_minus[r++];
309
310                 if (*tok != '/')
311                         break;
312
313                 tok++;
314         }
315
316         *a_rmask = rmask;
317
318         return OK;
319 }
320
321
322 int fpu_reglist_right(WORD * a_rmask)
323 {
324         static WORD msktab_plus[] = {
325                 0x0001, 0x0002, 0x0004, 0x0008,
326                 0x0010, 0x0020, 0x0040, 0x0080
327         };
328
329         WORD rmask = 0;
330         int r, cnt;
331
332         for(;;)
333         {
334                 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
335                         r = *tok++ & 0x07;
336                 else
337                         break;
338
339                 if (*tok == '-')
340                 {
341                         tok++;
342
343                         if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
344                                 cnt = *tok++ & 0x07;
345                         else
346                                 return error("register list syntax");
347
348                         if (cnt < r)
349                                 return error("register list order");
350
351                         cnt -= r;
352                 }
353                 else
354                         cnt = 0;
355
356                 while (cnt-- >= 0)
357                         rmask |= msktab_plus[r++];
358
359                 if (*tok != '/')
360                         break;
361
362                 tok++;
363         }
364
365         *a_rmask = rmask;
366
367         return OK;
368 }
369
370
371 //
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
376 //
377 int check030bf(void)
378 {
379         WARNING(Add more strict checks as well as checks for non defined (yet) labels)
380
381         if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
382                 return error(unsupport);
383
384         tok++;
385
386         if (*tok == CONST)
387         {
388                 tok++;
389                 bfparam1 = *(int *)tok;
390
391                 if ((bfparam1 > 31) || (bfparam1 < 0))
392                         return error("bfxxx offset: immediate value must be between 0 and 31");
393
394                 // Do=0, offset=immediate - shift it to place
395                 bfparam1 = (bfparam1 << 6) | (0 << 11);
396                 tok++;
397         }
398         else if (*tok == SYMBOL)
399         {
400                 if (expr(bf0expr, &bf0exval, &bf0exattr, &bf0esym) != OK)
401                         return ERROR;
402
403                 bfparam1 = bf0exval;
404
405                 if ((bfparam1 > 31) || (bfparam1 < 0))
406                         return error("bfxxx offset: immediate value must be between 0 and 31");
407
408                 // Do=0, offset=immediate - shift it to place
409                 bfparam1 = (bfparam1 << 6) | (0 << 11);
410         }
411         else if ((*tok >= KW_D0) && (*tok <= KW_D7))
412         {
413                 // Do=1, offset=data register - shift it to place
414                 bfparam1 = ((*(int *)tok - 128) << 6) | (1 << 11);
415                 tok++;
416         }
417         else
418                 return ERROR;
419
420         if (*tok==':')
421                 tok++;  //eat the ':'
422
423         if (*tok == '}' && tok[1] == EOL)
424         {
425                 // It is ok to have }, EOL here - it might be "fmove fpn,<ea> {dx}"
426                 tok++;
427                 return OK;
428         }
429
430         if (*tok == CONST)
431         {
432                 tok++;
433                 bfparam2 = *(int *)tok;
434
435                 if (bfparam2 > 31 || bfparam2 < 0)
436                         return error("bfxxx width: immediate value must be between 0 and 31");
437
438                 // Do=0, offset=immediate - shift it to place
439                 bfparam2 = (bfparam2 << 0) | (0 << 5);
440                 tok++;
441         }
442         else if (*tok == SYMBOL)
443         {
444                 if (expr(bf0expr, &bf0exval, &bf0exattr, &bf0esym) != OK)
445                         return ERROR;
446
447                 bfparam2 = bf0exval;
448
449                 if (bfparam2 > 31 || bfparam2 < 0)
450                         return error("bfxxx width: immediate value must be between 0 and 31");
451
452                 // Do=0, offset=immediate - shift it to place
453                 bfparam2 = (bfparam2 << 0) | (0 << 5);
454         }
455         else if ((*tok >= KW_D0) && (*tok <= KW_D7))
456         {
457                 // Do=1, offset=data register - shift it to place
458                 bfparam2 = ((*(int *)tok - 128) << 0) | (1 << 5);
459                 tok++;
460         }
461         else
462                 return ERROR;
463
464         tok++;  // Eat the '}'
465
466         return OK;
467 }
468