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