Multiple fixes for 020+ mode, including:
[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 extern char unsupport[];
24
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
44
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
62
63 int a2reg;                                      // Register for div.l (68020+)
64 WORD mulmode;                           // to distinguish between 32 and 64 bit multiplications (68020+)
65
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 VALUE bf0exval;                         // Expression's value
72 WORD bf0exattr;                         // Expression's attribute
73 SYM * bf0esym;                          // External symbol involved in expr
74
75 // Function prototypes
76 int check030bf(void);
77
78
79 //
80 // Parse addressing mode
81 //
82 int amode(int acount)
83 {
84         // Initialize global return values
85         nmodes = a0reg = a1reg = 0;
86         am0 = am1 = AM_NONE;
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 = a0bsize = a0extension = a1bexval = a1bsize = a1extension = 0;
92         am0_030 = am1_030 = 0;
93         bfparam1 = bfparam2 = 0;
94         bf0expr[0] = ENDEXPR;
95         bf0exattr = 0;
96         bf0esym = NULL;
97
98         // If at EOL, then no addr modes at all
99         if (*tok == EOL)
100                 return 0;
101
102         // Parse first addressing mode
103         #define AnOK      a0ok
104         #define AMn       am0
105         #define AnREG     a0reg
106         #define AnIXREG   a0ixreg
107         #define AnIXSIZ   a0ixsiz
108         #define AnEXPR    a0expr
109         #define AnEXVAL   a0exval
110         #define AnEXATTR  a0exattr
111         #define AnOEXPR   a0oexpr
112         #define AnOEXVAL  a0oexval
113         #define AnOEXATTR a0oexattr
114         #define AnESYM    a0esym
115         #define AMn_IX0   am0_ix0
116         #define AMn_IXN   am0_ixn
117         #define CHK_FOR_DISPn CheckForDisp0
118         #define AnBEXPR   a0bexpr
119         #define AnBEXVAL  a0bexval
120         #define AnBEXATTR a0bexattr
121         #define AnBZISE   a0bsize
122         #define AnEXTEN   a0extension
123         #define AMn_030   am0_030
124         #define IS_SUPPRESSEDn IS_SUPPRESSED0
125         #define CHECKODn CHECKOD0
126         #include "parmode.h"
127
128         // If caller wants only one mode, return just one (ignore comma);. If there
129         // is no second addressing mode (no comma), then return just one anyway.
130         nmodes = 1;
131
132         // it's a bitfield instruction--check the parameters inside the {} block
133         // for validity
134         if (*tok == '{')
135         if (check030bf() == ERROR)
136                 return ERROR;
137
138         if ((acount == 0) || (*tok != ','))
139                 return 1;
140
141         // Eat the comma
142         tok++;
143
144         // Parse second addressing mode
145         #define AnOK      a1ok
146         #define AMn       am1
147         #define AnREG     a1reg
148         #define AnIXREG   a1ixreg
149         #define AnIXSIZ   a1ixsiz
150         #define AnEXPR    a1expr
151         #define AnEXVAL   a1exval
152         #define AnEXATTR  a1exattr
153         #define AnOEXPR   a1oexpr
154         #define AnOEXVAL  a1oexval
155         #define AnOEXATTR a1oexattr
156         #define AnESYM    a1esym
157         #define AMn_IX0   am1_ix0
158         #define AMn_IXN   am1_ixn
159         #define CHK_FOR_DISPn CheckForDisp1
160         #define AnBEXPR   a1bexpr
161         #define AnBEXVAL  a1bexval
162         #define AnBEXATTR a1bexattr
163         #define AnBZISE   a1bsize
164         #define AnEXTEN   a1extension
165         #define AMn_030   am1_030
166         #define IS_SUPPRESSEDn IS_SUPPRESSED1
167         #define CHECKODn CHECKOD1
168         #include "parmode.h"
169
170         // It's a bitfield instruction--check the parameters inside the {} block
171         // for validity
172         if (*tok == '{') 
173         if (check030bf() == ERROR)
174                 return ERROR;
175
176         // At this point, it is legal for 020+ to have a ':'. For example divu.l
177         // d0,d2:d3
178         if (*tok == ':')
179         {
180                 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
181                         return error(unsupport);
182
183                 // TODO: protect this from combinations like Dx:FPx etc :)
184                 tok++;  //eat the colon
185
186                 if ((*tok >= KW_D0) && (*tok <= KW_D7))
187                 {
188                         a2reg = (*tok - KW_D0);
189                         mulmode = 1 << 10;
190                 }
191                 else if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
192                 {
193                         a2reg = (*tok - KW_FP0);
194                         mulmode = 1 << 10;
195                 }
196                 else
197                         return error("a data or FPU register must follow a :");
198
199                 *tok++;
200         }
201         else
202         {
203                 // If no ':' is present then maybe we have something like divs.l d0,d1
204                 // which sould translate to divs.l d0,d1:d1
205                 a2reg = a1reg;
206                 mulmode = 0;
207         }
208
209         nmodes = 2;
210         return 2;
211
212         // Error messages:
213 badmode:
214         return error("addressing mode syntax");
215
216         //unmode:
217         //return error("unimplemented addressing mode");
218 }
219
220
221 //
222 // Parse register list
223 //
224 int reglist(WORD * a_rmask)
225 {
226         static WORD msktab[] = {
227                 0x0001, 0x0002, 0x0004, 0x0008,
228                 0x0010, 0x0020, 0x0040, 0x0080,
229                 0x0100, 0x0200, 0x0400, 0x0800,
230                 0x1000, 0x2000, 0x4000, 0x8000
231         };
232
233         WORD rmask = 0;
234         int r, cnt;
235
236         for(;;)
237         {
238                 if ((*tok >= KW_D0) && (*tok <= KW_A7))
239                         r = *tok++ & 0x0F;
240                 else
241                         break;
242
243                 if (*tok == '-')
244                 {
245                         tok++;
246
247                         if ((*tok >= KW_D0) && (*tok <= KW_A7))
248                                 cnt = *tok++ & 0x0F;
249                         else
250                                 return error("register list syntax");
251
252                         if (cnt < r)
253                                 return error("register list order");
254
255                         cnt -= r;
256                 }
257                 else
258                         cnt = 0;
259
260                 while (cnt-- >= 0)
261                         rmask |= msktab[r++];
262
263                 if (*tok != '/')
264                         break;
265
266                 tok++;
267         }
268
269         *a_rmask = rmask;
270
271         return OK;
272 }
273
274
275 //
276 // Parse FPU register list
277 //
278 int fpu_reglist_left(WORD * a_rmask)
279 {
280         static WORD msktab_minus[] = {
281                 0x0080, 0x0040, 0x0020, 0x0010,
282                 0x0008, 0x0004, 0x0002, 0x0001
283         };
284
285         WORD rmask = 0;
286         int r, cnt;
287
288         for(;;)
289         {
290                 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
291                         r = *tok++ & 0x07;
292                 else
293                         break;
294
295                 if (*tok == '-')
296                 {
297                         tok++;
298
299                         if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
300                                 cnt = *tok++ & 0x07;
301                         else
302                                 return error("register list syntax");
303
304                         if (cnt < r)
305                                 return error("register list order");
306
307                         cnt -= r;
308                 }
309                 else
310                         cnt = 0;
311
312                 r = 0;
313                 while (cnt-- >= 0)
314                         rmask |= msktab_minus[r++];
315
316                 if (*tok != '/')
317                         break;
318
319                 tok++;
320         }
321
322         *a_rmask = rmask;
323
324         return OK;
325 }
326
327
328 int fpu_reglist_right(WORD * a_rmask)
329 {
330         static WORD msktab_plus[] = {
331                 0x0001, 0x0002, 0x0004, 0x0008,
332                 0x0010, 0x0020, 0x0040, 0x0080
333         };
334
335         WORD rmask = 0;
336         int r, cnt;
337
338         for(;;)
339         {
340                 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
341                         r = *tok++ & 0x07;
342                 else
343                         break;
344
345                 if (*tok == '-')
346                 {
347                         tok++;
348
349                         if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
350                                 cnt = *tok++ & 0x07;
351                         else
352                                 return error("register list syntax");
353
354                         if (cnt < r)
355                                 return error("register list order");
356
357                         cnt -= r;
358                 }
359                 else
360                         cnt = 0;
361
362                 while (cnt-- >= 0)
363                         rmask |= msktab_plus[r++];
364
365                 if (*tok != '/')
366                         break;
367
368                 tok++;
369         }
370
371         *a_rmask = rmask;
372
373         return OK;
374 }
375
376
377 //
378 // Check for bitfield instructions extra params
379 // These are 020+ instructions and have the following syntax:
380 // bfxxx <ea>{param1,param2}
381 // param1/2 are either data registers or immediate values
382 //
383 int check030bf(void)
384 {
385         CHECK00;
386
387         tok++;
388
389         if (*tok == CONST)
390         {
391                 tok++;
392                 bfval1 = *(int *)tok;
393
394                 // Do=0, offset=immediate - shift it to place
395                 bfparam1 = (0 << 11);
396                 tok++;
397         }
398         else if (*tok == SYMBOL)
399         {
400                 if (expr(bf0expr, &bf0exval, &bf0exattr, &bf0esym) != OK)
401                         return ERROR;
402
403                 if (!(bf0exattr & DEFINED))
404                         return error("bfxxx offset: immediate value must evaluate");
405
406                 bfval1 = bf0exval;
407
408                 // Do=0, offset=immediate - shift it to place
409                 bfparam1 = (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 = (1 << 11);
415                 bfval1 = (*(int *)tok - 128);
416                 tok++;
417         }
418         else
419                 return ERROR;
420
421         if (*tok==':')
422                 tok++;  //eat the ':'
423
424         if (*tok == '}' && tok[1] == EOL)
425         {
426                 // It is ok to have }, EOL here - it might be "fmove fpn,<ea> {dx}"
427                 tok++;
428                 return OK;
429         }
430
431         if (*tok == CONST)
432         {
433                 tok++;
434                 bfval2 = *(int *)tok;
435
436                 // Do=0, offset=immediate - shift it to place
437                 bfparam2 = (0 << 5);
438                 tok++;
439         }
440         else if (*tok == SYMBOL)
441         {
442                 if (expr(bf0expr, &bf0exval, &bf0exattr, &bf0esym) != OK)
443                         return ERROR;
444
445                 bfval2 = bf0exval;
446
447                 if (!(bf0exattr & DEFINED))
448                         return error("bfxxx width: immediate value must evaluate");
449
450                 // Do=0, offset=immediate - shift it to place
451                 bfparam2 = (0 << 5);
452         }
453         else if ((*tok >= KW_D0) && (*tok <= KW_D7))
454         {
455                 // Do=1, offset=data register - shift it to place
456                 bfval2 = ((*(int *)tok - 128));
457                 bfparam2 = (1 << 5);
458                 tok++;
459         }
460         else
461                 return ERROR;
462
463         tok++;  // Eat the '}'
464
465         return OK;
466 }
467