be5162b28cebab3d79483bbbef6c676ee30ebf04
[rmac] / amode.c
1 //
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
7 //
8
9 #include "amode.h"
10 #include "error.h"
11 #include "token.h"
12 #include "expr.h"
13 #include "rmac.h"
14 #include "procln.h"
15 #include "sect.h"
16
17 #define DEF_KW
18 #include "kwtab.h"
19 #define DEF_MN
20 #include "mntab.h"
21
22 extern int activecpu;
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 //
67 // Parse addressing mode
68 //
69 int amode(int acount)
70 {
71         // Initialize global return values
72         nmodes = a0reg = a1reg = 0;
73         am0 = am1 = AM_NONE;
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;
79         am0_030=am1_030=0;
80         bfparam1=bfparam2=0;
81         bf0expr[0]=ENDEXPR;
82         bf0exattr=0;
83         bf0esym= (SYM *)NULL;
84
85         // If at EOL, then no addr modes at all
86         if (*tok == EOL)
87                 return 0;
88
89         // Parse first addressing mode
90         #define AnOK      a0ok
91         #define AMn       am0
92         #define AnREG     a0reg
93         #define AnIXREG   a0ixreg
94         #define AnIXSIZ   a0ixsiz
95         #define AnEXPR    a0expr
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
113         #include "parmode.h"
114
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.
117         nmodes = 1;
118
119         if (*tok == '{')
120                 if (check030bf()==ERROR)                        // it's a bitfield instruction - check the parameters inside the {} block for validity
121                     return ERROR;
122
123         if (acount == 0 || *tok != ',')
124                 return 1;
125
126         // Eat the comma
127         tok++;
128
129         // Parse second addressing mode
130         #define AnOK      a1ok
131         #define AMn       am1
132         #define AnREG     a1reg
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
153         #include "parmode.h"
154
155         if (*tok == '{')
156                 if (check030bf()==ERROR)                        // it's a bitfield instruction - check the parameters inside the {} block for validity
157                         return ERROR;
158
159         // At this point, it is legal for 020+ to have a ':'. For example divu.l d0,d2:d3
160         if (*tok == ':')
161         {
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)
167             {
168                 a2reg = (*tok - KW_D0);
169                 mulmode=1<<10;
170             }
171             else if (*tok >= KW_FP0&&*tok <= KW_FP7)
172             {
173                 a2reg = (*tok - KW_FP0);
174                 mulmode=1<<10;
175             }
176             else
177                 return error("a data or FPU register must follow a :");
178             *tok++;
179         }
180         else
181         {
182             //If no ':' is present then maybe we have something like divs.l d0,d1 which sould translate to divs.l d0,d1:d1
183             a2reg = a1reg;
184             mulmode=0;
185         }
186
187         nmodes = 2;
188         return 2;
189
190         // Error messages:
191         badmode:
192         return error("addressing mode syntax");
193
194         //unmode:
195         //return error("unimplemented addressing mode");
196 }
197
198
199 //
200 // Parse register list
201 //
202 int reglist(WORD * a_rmask)
203 {
204         static WORD msktab[] = {
205                 0x0001, 0x0002, 0x0004, 0x0008,
206                 0x0010, 0x0020, 0x0040, 0x0080,
207                 0x0100, 0x0200, 0x0400, 0x0800,
208                 0x1000, 0x2000, 0x4000, 0x8000
209         };
210
211         WORD rmask = 0;
212         int r, cnt;
213
214         for(;;)
215         {
216                 if (*tok >= KW_D0 && *tok <= KW_A7)
217                         r = *tok++ & 15;
218                 else
219                         break;
220
221                 if (*tok == '-')
222                 {
223                         tok++;
224
225                         if (*tok >= KW_D0 && *tok <= KW_A7)
226                                 cnt = *tok++ & 15;
227                         else 
228                                 return error("register list syntax");
229
230                         if (cnt < r)
231                                 return error("register list order");
232
233                         cnt -= r;
234                 }
235                 else 
236                         cnt = 0;
237
238                 while (cnt-- >= 0)
239                         rmask |= msktab[r++];
240
241                 if (*tok != '/')
242                         break;
243
244                 tok++;
245         }
246
247         *a_rmask = rmask;
248
249         return OK;
250 }
251
252 //
253 // Parse FPU register list
254 //
255 int fpu_reglist_left(WORD * a_rmask)
256 {
257         static WORD msktab_minus[] = {
258                 0x0080, 0x0040, 0x0020, 0x0010,
259                 0x0008, 0x0004, 0x0002, 0x0001
260         };
261
262         WORD rmask = 0;
263         int r, cnt;
264
265         for(;;)
266         {
267                 if (*tok >= KW_FP0 && *tok <= KW_FP7)
268                         r = *tok++ & 7;
269                 else
270                         break;
271
272                 if (*tok == '-')
273                 {
274                         tok++;
275
276                         if (*tok >= KW_FP0 && *tok <= KW_FP7)
277                                 cnt = *tok++ & 7;
278                         else 
279                                 return error("register list syntax");
280
281                         if (cnt < r)
282                                 return error("register list order");
283
284                         cnt -= r;
285                 }
286                 else 
287                         cnt = 0;
288
289                 while (cnt-- >= 0)
290                         rmask |= msktab_minus[r++];
291
292                 if (*tok != '/')
293                         break;
294
295                 tok++;
296         }
297
298         *a_rmask = rmask;
299
300         return OK;
301 }
302 int fpu_reglist_right(WORD * a_rmask)
303 {
304         static WORD msktab_plus[] = {
305                 0x0001, 0x0002, 0x0004, 0x0008,
306                 0x0010, 0x0020, 0x0040, 0x0080
307         };
308
309         WORD rmask = 0;
310         int r, cnt;
311
312         for(;;)
313         {
314                 if (*tok >= KW_FP0 && *tok <= KW_FP7)
315                         r = *tok++ & 7;
316                 else
317                         break;
318
319                 if (*tok == '-')
320                 {
321                         tok++;
322
323                         if (*tok >= KW_FP0 && *tok <= KW_FP7)
324                                 cnt = *tok++ & 7;
325                         else 
326                                 return error("register list syntax");
327
328                         if (cnt < r)
329                                 return error("register list order");
330
331                         cnt -= r;
332                 }
333                 else 
334                         cnt = 0;
335
336                 while (cnt-- >= 0)
337                         rmask |= msktab_plus[r++];
338
339                 if (*tok != '/')
340                         break;
341
342                 tok++;
343         }
344
345         *a_rmask = rmask;
346
347         return OK;
348 }
349
350 //
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
355 //
356
357 int check030bf(void)
358 {
359     WARNING (Add more strict checks as well as checks for non defined (yet) labels)
360
361     if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
362         return error(unsupport);
363
364     tok++;
365     if (*tok == CONST)
366     {
367         tok++;
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
372         tok++;
373     }
374     else if (*tok == SYMBOL)
375     {
376         if (expr(bf0expr, &bf0exval, &bf0exattr, &bf0esym) != OK)
377             return ERROR;
378         bfparam1 = bf0exval;
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
382     }
383     else if (*tok >= KW_D0 && *tok <= KW_D7)
384     {
385         bfparam1 = ((*(int *)tok - 128) << 6) | (1 << 11);      //Do=1, offset=data register - shift it to place
386         tok++;
387     }
388     else
389         return ERROR;
390
391     if (*tok==':')
392         tok++;  //eat the ':'
393
394     if (*tok == '}' && tok[1] == EOL)
395     {
396         tok++;
397         return OK;      //It is ok to have }, EOL here - it might be "fmove fpn,<ea> {dx}"
398     }
399
400
401     if (*tok == CONST)
402     {
403         tok++;
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
408         tok++;
409     }
410     else if (*tok == SYMBOL)
411     {
412         if (expr(bf0expr, &bf0exval, &bf0exattr, &bf0esym) != OK)
413             return ERROR;
414         bfparam2 = bf0exval;
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
418     }
419     else if (*tok >= KW_D0 && *tok <= KW_D7)
420     {
421         bfparam2 = ((*(int *)tok - 128) << 0) | (1 << 5);       //Do=1, offset=data register - shift it to place
422         tok++;
423     }
424     else
425         return ERROR;
426
427     tok++;      //eat the '}'
428
429     return OK;
430 }