2608d79793f32493ab4d0cf11dd2f8f678fda7e6
[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 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
44
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
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 uint64_t 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 = a1bexval = 0;
92         a0bsize = a0extension = a1bsize = a1extension = 0;
93         am0_030 = am1_030 = 0;
94         bfparam1 = bfparam2 = 0;
95         bf0expr[0] = ENDEXPR;
96         bf0exattr = 0;
97         bf0esym = NULL;
98
99         // If at EOL, then no addr modes at all
100         if (*tok.u32 == EOL)
101                 return 0;
102
103         // Parse first addressing mode
104         #define AnOK      a0ok
105         #define AMn       am0
106         #define AnREG     a0reg
107         #define AnIXREG   a0ixreg
108         #define AnIXSIZ   a0ixsiz
109         #define AnEXPR    (TOKENPTR)a0expr
110         #define AnEXVAL   a0exval
111         #define AnEXATTR  a0exattr
112         #define AnOEXPR   (TOKENPTR)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   (TOKENPTR)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
127         #include "parmode.h"
128
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.
131         nmodes = 1;
132
133         // it's a bitfield instruction--check the parameters inside the {} block
134         // for validity
135         if (*tok.u32 == '{')
136                 if (check030bf() == ERROR)
137                         return ERROR;
138
139         if ((acount == 0) || (*tok.u32 != ','))
140                 return 1;
141
142         // Eat the comma
143         tok.u32++;
144
145         // Parse second addressing mode
146         #define AnOK      a1ok
147         #define AMn       am1
148         #define AnREG     a1reg
149         #define AnIXREG   a1ixreg
150         #define AnIXSIZ   a1ixsiz
151         #define AnEXPR    (TOKENPTR)a1expr
152         #define AnEXVAL   a1exval
153         #define AnEXATTR  a1exattr
154         #define AnOEXPR   (TOKENPTR)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   (TOKENPTR)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
169         #include "parmode.h"
170
171         // It's a bitfield instruction--check the parameters inside the {} block
172         // for validity
173         if (*tok.u32 == '{')
174         if (check030bf() == ERROR)
175                 return ERROR;
176
177         // At this point, it is legal for 020+ to have a ':'. For example divu.l
178         // d0,d2:d3
179         if (*tok.u32 == ':')
180         {
181                 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
182                         return error(unsupport);
183
184                 // TODO: protect this from combinations like Dx:FPx etc :)
185                 tok.u32++;  //eat the colon
186
187                 if ((*tok.u32 >= KW_D0) && (*tok.u32 <= KW_D7))
188                 {
189                         a2reg = (*tok.u32 - KW_D0);
190                         mulmode = 1 << 10;
191                 }
192                 else if ((*tok.u32 >= KW_FP0) && (*tok.u32 <= KW_FP7))
193                 {
194                         a2reg = (*tok.u32 - KW_FP0);
195                         mulmode = 1 << 10;
196                 }
197                 else
198                         return error("a data or FPU register must follow a :");
199
200                 *tok.u32++;
201         }
202         else
203         {
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
206                 a2reg = a1reg;
207                 mulmode = 0;
208         }
209
210         nmodes = 2;
211         return 2;
212
213         // Error messages:
214 badmode:
215         return error("addressing mode syntax");
216
217         //unmode:
218         //return error("unimplemented addressing mode");
219 }
220
221
222 //
223 // Parse register list
224 //
225 int reglist(WORD * a_rmask)
226 {
227         static WORD msktab[] = {
228                 0x0001, 0x0002, 0x0004, 0x0008,
229                 0x0010, 0x0020, 0x0040, 0x0080,
230                 0x0100, 0x0200, 0x0400, 0x0800,
231                 0x1000, 0x2000, 0x4000, 0x8000
232         };
233
234         WORD rmask = 0;
235         int r, cnt;
236
237         for(;;)
238         {
239                 if ((*tok.u32 >= KW_D0) && (*tok.u32 <= KW_A7))
240                         r = *tok.u32++ & 0x0F;
241                 else
242                         break;
243
244                 if (*tok.u32 == '-')
245                 {
246                         tok.u32++;
247
248                         if ((*tok.u32 >= KW_D0) && (*tok.u32 <= KW_A7))
249                                 cnt = *tok.u32++ & 0x0F;
250                         else
251                                 return error("register list syntax");
252
253                         if (cnt < r)
254                                 return error("register list order");
255
256                         cnt -= r;
257                 }
258                 else
259                         cnt = 0;
260
261                 while (cnt-- >= 0)
262                         rmask |= msktab[r++];
263
264                 if (*tok.u32 != '/')
265                         break;
266
267                 tok.u32++;
268         }
269
270         *a_rmask = rmask;
271
272         return OK;
273 }
274
275
276 //
277 // Parse FPU register list
278 //
279 int fpu_reglist_left(WORD * a_rmask)
280 {
281         static WORD msktab_minus[] = {
282                 0x0080, 0x0040, 0x0020, 0x0010,
283                 0x0008, 0x0004, 0x0002, 0x0001
284         };
285
286         WORD rmask = 0;
287         int r, cnt;
288
289         for(;;)
290         {
291                 if ((*tok.u32 >= KW_FP0) && (*tok.u32 <= KW_FP7))
292                         r = *tok.u32++ & 0x07;
293                 else
294                         break;
295
296                 if (*tok.u32 == '-')
297                 {
298                         tok.u32++;
299
300                         if ((*tok.u32 >= KW_FP0) && (*tok.u32 <= KW_FP7))
301                                 cnt = *tok.u32++ & 0x07;
302                         else
303                                 return error("register list syntax");
304
305                         if (cnt < r)
306                                 return error("register list order");
307
308                         cnt -= r;
309                 }
310                 else
311                         cnt = 0;
312
313                 r = 0;
314
315                 while (cnt-- >= 0)
316                         rmask |= msktab_minus[r++];
317
318                 if (*tok.u32 != '/')
319                         break;
320
321                 tok.u32++;
322         }
323
324         *a_rmask = rmask;
325
326         return OK;
327 }
328
329
330 int fpu_reglist_right(WORD * a_rmask)
331 {
332         static WORD msktab_plus[] = {
333                 0x0001, 0x0002, 0x0004, 0x0008,
334                 0x0010, 0x0020, 0x0040, 0x0080
335         };
336
337         WORD rmask = 0;
338         int r, cnt;
339
340         for(;;)
341         {
342                 if ((*tok.u32 >= KW_FP0) && (*tok.u32 <= KW_FP7))
343                         r = *tok.u32++ & 0x07;
344                 else
345                         break;
346
347                 if (*tok.u32 == '-')
348                 {
349                         tok.u32++;
350
351                         if ((*tok.u32 >= KW_FP0) && (*tok.u32 <= KW_FP7))
352                                 cnt = *tok.u32++ & 0x07;
353                         else
354                                 return error("register list syntax");
355
356                         if (cnt < r)
357                                 return error("register list order");
358
359                         cnt -= r;
360                 }
361                 else
362                         cnt = 0;
363
364                 while (cnt-- >= 0)
365                         rmask |= msktab_plus[r++];
366
367                 if (*tok.u32 != '/')
368                         break;
369
370                 tok.u32++;
371         }
372
373         *a_rmask = rmask;
374
375         return OK;
376 }
377
378
379 //
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
384 //
385 int check030bf(void)
386 {
387         CHECK00;
388         tok.u32++;
389
390         if (*tok.u32 == CONST)
391         {
392                 tok.u32++;
393 //              bfval1 = (int)*(uint64_t *)tok.u32;
394                 bfval1 = (int)*tok.u64;
395
396                 // Do=0, offset=immediate - shift it to place
397                 bfparam1 = (0 << 11);
398 //              tok.u32++;
399 //              tok.u32++;
400                 tok.u64++;
401         }
402         else if (*tok.u32 == SYMBOL)
403         {
404                 if (expr((TOKENPTR)bf0expr, &bf0exval, &bf0exattr, &bf0esym) != OK)
405                         return ERROR;
406
407                 if (!(bf0exattr & DEFINED))
408                         return error("bfxxx offset: immediate value must evaluate");
409
410                 bfval1 = (int)bf0exval;
411
412                 // Do=0, offset=immediate - shift it to place
413                 bfparam1 = (0 << 11);
414         }
415         else if ((*tok.u32 >= KW_D0) && (*tok.u32 <= KW_D7))
416         {
417                 // Do=1, offset=data register - shift it to place
418                 bfparam1 = (1 << 11);
419                 bfval1 = (*(int *)tok.u32 - 128);
420                 tok.u32++;
421         }
422         else
423                 return ERROR;
424
425         // Eat the ':', if any
426         if (*tok.u32 == ':')
427                 tok.u32++;
428
429         if (*tok.u32 == '}' && tok.u32[1] == EOL)
430         {
431                 // It is ok to have }, EOL here - it might be "fmove fpn,<ea> {dx}"
432                 tok.u32++;
433                 return OK;
434         }
435
436         if (*tok.u32 == CONST)
437         {
438                 tok.u32++;
439 //              bfval2 = (int)*(uint64_t *)tok.u32;
440                 bfval2 = (int)*tok.u64;
441
442                 // Do=0, offset=immediate - shift it to place
443                 bfparam2 = (0 << 5);
444 //              tok.u32++;
445 //              tok.u32++;
446                 tok.u64++;
447         }
448         else if (*tok.u32 == SYMBOL)
449         {
450                 if (expr((TOKENPTR)bf0expr, &bf0exval, &bf0exattr, &bf0esym) != OK)
451                         return ERROR;
452
453                 bfval2 = (int)bf0exval;
454
455                 if (!(bf0exattr & DEFINED))
456                         return error("bfxxx width: immediate value must evaluate");
457
458                 // Do=0, offset=immediate - shift it to place
459                 bfparam2 = (0 << 5);
460         }
461         else if ((*tok.u32 >= KW_D0) && (*tok.u32 <= KW_D7))
462         {
463                 // Do=1, offset=data register - shift it to place
464                 bfval2 = ((*(int *)tok.u32 - 128));
465                 bfparam2 = (1 << 5);
466                 tok.u32++;
467         }
468         else
469                 return ERROR;
470
471         tok.u32++;      // Eat the '}'
472
473         return OK;
474 }
475