Fix a bug in +o5 where outer displacement would not optimise to word size
[rmac] / parmode.h
1 //
2 // RMAC - Reboot's Macro Assembler for all Atari computers
3 // PARMODE.C - Addressing Modes Parser Include
4 // Copyright (C) 199x Landon Dyer, 2011-2020 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 // This file is included (twice) to parse two addressing modes, into slightly
10 // different var names
11 {
12         uint64_t scaleval;                      // Expression's value
13         TOKEN scaleexpr[EXPRSIZE];      // Expression
14         WORD scaleattr;                         // Expression's attribute
15         SYM * scaleesym;                        // External symbol involved in expr
16
17         // Dn
18         // An
19         // # expression
20         if ((*tok >= KW_D0) && (*tok <= KW_D7))
21         {
22                 AMn = DREG;
23                 AnREG = *tok++ & 7;
24         }
25         else if ((*tok >= KW_A0) && (*tok <= KW_A7))
26         {
27                 AMn = AREG;
28                 AnREG = *tok++ & 7;
29         }
30         else if (*tok == '#')
31         {
32                 tok++;
33
34                 if (expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
35                         return ERROR;
36
37                 AMn = IMMED;
38         }
39
40         // Small problem with this is that the opening parentheses might be an
41         // expression that's part of a displacement; this code will falsely flag
42         // that as an error.
43
44         // (An)
45         // (An)+
46         // (An,Xn[.siz][*scale])
47         // (PC,Xn[.siz][*scale])
48         // (d16,An)
49         // (d8,An,Xn[.siz][*scale])
50         // (d16,PC)
51         // (d8,PC,Xn[.siz][*scale])
52         // ([bd,An],Xn[.siz][*scale],od)
53         // ([bd,An,Xn[.siz][*scale]],od)
54         // ([bd,PC],Xn[.siz][*scale],od)
55         // ([bd,PC,Xn[.siz][*scale]],od)
56         else if (*tok == '(')
57         {
58                 int ea_PC = 0;                          // Flag that let us know if we have PC or An relative ea
59                 tok++;
60
61                 if ((*tok >= KW_A0) && (*tok <= KW_A7))
62                 {
63                         AnREG = *tok++ & 7;
64
65                         if (*tok == ')')
66                         {
67                                 tok++;
68
69                                 if (*tok == '+')
70                                 {
71                                         tok++;
72                                         AMn = APOSTINC;
73                                 }
74                                 else
75                                         AMn = AIND;
76
77                                 goto AnOK;
78                         }
79
80                         AMn = AINDEXED;
81                         goto AMn_IX0;            // Handle ",Xn[.siz][*scale])"
82                 }
83                 else if ((*tok >= KW_D0) && (*tok <= KW_D7))
84                 {
85                         // Since index register isn't used here, store register number in this field
86                         AnIXREG = *tok++ & 7;                                // (Dn)
87
88                         if (*tok == ')')
89                         {
90                                 tok++;
91                                 AnEXTEN |= EXT_FULLWORD;    // Definitely using full extension format, so set bit 8
92                                 AnEXTEN |= EXT_BS;          // Base register suppressed
93                                 AnEXTEN |= EXT_BDSIZE0;     // Base displacement null
94                                 AnEXTEN |= EXT_IISPOSN;     // Indirect Postindexed with Null Outer Displacement
95                                 AMn = MEMPOST;
96                                 AnREG = 6 << 3;         // stuff 110 to mode field
97                                 goto AnOK;
98                         }
99                         else if (*tok == 'L')
100                         {
101                                 AMn = DINDL;                                                                     // (Dn.l)
102                                 AnEXTEN = 1 << 11;   // Long index size
103                                 tok++;
104                         }
105                         else if (*tok == 'W')                                // (Dn.w)
106                         {
107                                 AMn = DINDW;
108                                 AnEXTEN = 0 << 11;   // Word index size
109                                 tok++;
110                         }
111                         else if (*tok == ',')
112                         {
113                                 // ([bd,An],Xn..) without bd, An
114                                 // Base displacement is suppressed
115                                 AnEXTEN |= EXT_FULLWORD;    // Definitely using full extension format, so set bit 8
116                                 AnEXTEN |= EXT_BS;          // Base register suppressed
117                                 AnEXTEN |= EXT_BDSIZE0;
118                                 AnREG = 6 << 3;         // stuff 110 to mode field
119                                 tok++;
120                                 goto CHECKODn;
121                         }
122                         else
123                         {
124                                 return error("(Dn) error");
125                         }
126
127                         if (*tok == '*')
128                         {                        // scale: *1, *2, *4, *8
129                                 tok++;
130
131                                 if (*tok == SYMBOL)
132                                 {
133                                         if (expr(scaleexpr, &scaleval, &scaleattr, &scaleesym) != OK)
134                                                 return error("scale factor expression must evaluate");
135
136                                         switch (scaleval)
137                                         {
138                                         case 1:
139                                                 break;
140                                         case 2:
141                                                 AnIXSIZ |= TIMES2;
142                                                 AnEXTEN |= 1 << 9;
143                                                 break;
144                                         case 4:
145                                                 AnIXSIZ |= TIMES4;
146                                                 AnEXTEN |= 2 << 9;
147                                                 break;
148                                         case 8:
149                                                 AnIXSIZ |= TIMES8;
150                                                 AnEXTEN |= 3 << 9;
151                                                 break;
152                                         default:
153                                                 goto badmode;
154                                         }
155                                 }
156                                 else if (*tok++ != CONST)
157                                         goto badmode;
158                                 else
159                                 {
160                                         switch ((int)*tok++)
161                                         {
162                                         case 1:
163                                                 break;
164                                         case 2:
165                                                 AnIXSIZ |= TIMES2;
166                                                 AnEXTEN |= 1 << 9;
167                                                 break;
168                                         case 4:
169                                                 AnIXSIZ |= TIMES4;
170                                                 AnEXTEN |= 2 << 9;
171                                                 break;
172                                         case 8:
173                                                 AnIXSIZ |= TIMES8;
174                                                 AnEXTEN |= 3 << 9;
175                                                 break;
176                                         default:
177                                                 goto badmode;
178                                         }
179
180                                         tok++;  // Take into account that constants are 64-bit
181                                 }
182                         }
183
184                         if (*tok == ')')
185                         {
186                                 tok++;
187                                 AnEXTEN |= EXT_FULLWORD;    // Definitely using full extension format, so set bit 8
188                                 AnEXTEN |= EXT_BS;          // Base register suppressed
189                                 AnEXTEN |= EXT_BDSIZE0;     // Base displacement null
190                                 AnEXTEN |= EXT_IISPOSN;     // Indirect Postindexed with Null Outer Displacement
191                                 AnREG = 6 << 3;         // stuff 110 to mode field
192                                 AMn = MEMPOST;
193                                 goto AnOK;
194                         }
195                         else if (*tok == ',')
196                         {
197                                 tok++;  // eat the comma
198                                 // It might be (Dn[.wl][*scale],od)
199                                 // Maybe this is wrong and we have to write some code here
200                                 // instead of reusing that path...
201                                 AnEXTEN |= EXT_FULLWORD;        // Definitely using full extension format, so set bit 8
202                                 AnEXTEN |= EXT_BS;       // Base displacement null - suppressed
203                                 AnEXTEN |= AnIXREG << 12;
204                                 goto CHECKODn;
205                         }
206                         else
207                                 return error("unhandled so far");
208                 }
209                 else if (*tok == KW_PC)
210                 {                            // (PC,Xn[.siz][*scale])
211                         tok++;
212                         AMn = PCINDEXED;
213
214                         // Common index handler; enter here with 'tok' pointing at the
215                         // comma.
216
217 AMn_IX0:                 // Handle indexed with missing expr
218
219                         AnEXVAL = 0;
220                         AnEXATTR = ABS | DEFINED;
221
222 AMn_IXN:                 // Handle any indexed (tok -> a comma)
223
224                         if (*tok++ != ',')
225                                 goto badmode;
226
227                         if (*tok < KW_D0 || *tok > KW_A7)
228                                 goto badmode;
229
230                         AnIXREG = *tok++ & 15;
231
232                         switch ((int)*tok)
233                         {                        // Index reg size: <empty> | .W | .L
234                         case DOTW:
235                                 tok++;
236                         default:
237                                 AnIXSIZ = 0;
238                                 break;
239                         case DOTL:
240                                 AnIXSIZ = 0x0800;
241                                 tok++;
242                                 break;
243                         case DOTB:               // .B not allowed here...
244                                 goto badmode;
245                         }
246
247                         if (*tok == '*')
248                         {                        // scale: *1, *2, *4, *8
249                                 tok++;
250
251                                 if (*tok == SYMBOL)
252                                 {
253                                         if (expr(scaleexpr, &scaleval, &scaleattr, &scaleesym) != OK)
254                                                 return error("scale factor expression must evaluate");
255
256                                         switch (scaleval)
257                                         {
258                                         case 1:
259                                                 break;
260                                         case 2:
261                                                 AnIXSIZ |= TIMES2;
262                                                 break;
263                                         case 4:
264                                                 AnIXSIZ |= TIMES4;
265                                                 break;
266                                         case 8:
267                                                 AnIXSIZ |= TIMES8;
268                                                 break;
269                                         default:
270                                                 goto badmode;
271                                         }
272                                 }
273                                 else if (*tok++ != CONST)
274                                         goto badmode;
275                                 else
276                                 {
277                                         switch ((int)*tok++)
278                                         {
279                                         case 1:
280                                                 break;
281                                         case 2:
282                                                 AnIXSIZ |= TIMES2;
283                                                 break;
284                                         case 4:
285                                                 AnIXSIZ |= TIMES4;
286                                                 break;
287                                         case 8:
288                                                 AnIXSIZ |= TIMES8;
289                                                 break;
290                                         default:
291                                                 goto badmode;
292                                         }
293
294                                         tok++;  // Take into account that constants are 64-bit
295                                 }
296                         }
297
298                         if (*tok == ',')
299                         {
300                                 // If we got here we didn't get any [] stuff
301                                 // so let's suppress base displacement before
302                                 // branching off
303                                 tok++;
304                                 AnEXTEN |= EXT_BDSIZE0;     // Base displacement null - suppressed
305                                 goto CHECKODn;
306                         }
307                         if (*tok++ != ')')         // final ")"
308                                 goto badmode;
309
310                         goto AnOK;
311                 }
312                 else if (*tok == '[')
313                 {                              // ([...
314                         tok++;
315                         AnEXTEN |= EXT_FULLWORD;     // Definitely using full extension format, so set bit 8
316
317                         // Check to see if base displacement is present
318                         if (*tok != CONST && *tok != SYMBOL)
319                         {
320                                 AnEXTEN |= EXT_BDSIZE0;
321                         }
322                         else
323                         {
324                                 expr(AnBEXPR, &AnBEXVAL, &AnBEXATTR, &AnESYM);
325
326                                 if (CHECK_OPTS(OPT_020_DISP) && (AnBEXVAL == 0) && (AnEXATTR != 0))
327                                 {
328                                         // bd = 0 so let's optimise it out
329                                         AnEXTEN |= EXT_BDSIZE0;
330                                 }
331                                 else if (*tok == DOTL)
332                                 {
333                                         // ([bd.l,...
334                                         AnEXTEN |= EXT_BDSIZEL;
335                                         tok++;
336                                 }
337                                 else
338                                 {
339                                         // ([bd[.w],... or ([bd,...
340                                         // Is .W forced here?
341                                         if (*tok == DOTW)
342                                         {
343                                                 AnEXTEN |= EXT_BDSIZEW;
344                                                 tok++;
345                                         }
346                                         else
347                                         {
348                                                 // Defined, absolute values from $FFFF8000..$00007FFF
349                                                 // get optimized to absolute short
350                                                 if (CHECK_OPTS(OPT_020_DISP)
351                                                         && ((AnBEXATTR & (TDB | DEFINED)) == DEFINED)
352                                                         && (((uint32_t)AnBEXVAL + 0x8000) < 0x10000))
353                                                 {
354                                                         AnEXTEN |= EXT_BDSIZEW;
355
356                                                         if (optim_warn_flag)
357                                                                 warn("absolute value in base displacement ranging $FFFF8000..$00007FFF optimised to absolute short");
358                                                 }
359                                                 else
360                                                 {
361                                                         AnEXTEN |= EXT_BDSIZEL;
362                                                 }
363                                         }
364                                 }
365
366                                 if (*tok == ',')
367                                         tok++;
368                         }
369
370                         // Check for address register or PC, 
371                         // suppress base register otherwise
372
373                         if (*tok == KW_PC)
374                         {                                       // ([bd,PC,...
375                                 ea_PC = 3;                              // Set flag in order to set proper value to AMn below when we can make a decision on ea
376                                                                                 // (why "3"? Well, MEMPOST is 3 away from PCMPOST, etc. Have a look at amode.h)
377                                 AnREG = (7 << 3) | 3;   // PC is special case - stuff 011 to register field and 111 to the mode field
378                                 tok++;
379                         }
380                         else if ((*tok >= KW_A0) && (*tok <= KW_A7))
381                         {                                       // ([bd,An,...
382                                 AnREG = (6 << 3) | (*tok & 7);
383                                 tok++;
384                         }
385                         else if ((*tok >= KW_D0) && (*tok <= KW_D7))
386                         {
387                                 // ([bd,Dn,...
388                                 AnREG = (6 << 3);
389                                 AnEXTEN |= ((*tok & 7) << 12);
390                                 AnEXTEN |= EXT_D;
391                                 AnEXTEN |= EXT_BS; // Oh look, a data register! Which means that base register is suppressed
392                                 tok++;
393
394                                 // Check for size
395                                 // ([bd,An/PC],Xn.W/L...)
396                                 switch ((int)*tok)
397                                 {
398                                 // Index reg size: <empty> | .W | .L
399                                 case DOTW:
400                                         tok++;
401                                         break;
402                                 default:
403                                         break;
404                                 case DOTL:
405                                         AnEXTEN |= EXT_L;
406                                         tok++;
407                                         break;
408                                 case DOTB:
409                                         // .B not allowed here...
410                                         goto badmode;
411                                 }
412
413                                 // Check for scale
414                                 if (*tok == '*')                        // ([bd,An/PC],Xn*...)
415                                 {                           // scale: *1, *2, *4, *8
416                                         tok++;
417
418                                         if (*tok == SYMBOL)
419                                         {
420                                                 if (expr(scaleexpr, &scaleval, &scaleattr, &scaleesym) != OK)
421                                                         return error("scale factor expression must evaluate");
422
423                                                 switch (scaleval)
424                                                 {
425                                                 case 1:
426                                                         break;
427                                                 case 2:
428                                                         AnIXSIZ |= TIMES2;
429                                                         break;
430                                                 case 4:
431                                                         AnIXSIZ |= TIMES4;
432                                                         break;
433                                                 case 8:
434                                                         AnIXSIZ |= TIMES8;
435                                                         break;
436                                                 default:
437                                                         goto badmode;
438                                 }
439                                         }
440                                         else if (*tok++ != CONST)
441                                                 goto badmode;
442                                         else
443                                         {
444                                                 switch ((int)*tok++)
445                                                 {
446                                                 case 1:
447                                                         break;
448                                                 case 2:
449                                                         AnIXSIZ |= TIMES2;
450                                                         break;
451                                                 case 4:
452                                                         AnIXSIZ |= TIMES4;
453                                                         break;
454                                                 case 8:
455                                                         AnIXSIZ |= TIMES8;
456                                                         break;
457                                                 default:
458                                                         goto badmode;
459                                                 }
460
461                                                 tok++;  // Take into account that constants are 64-bit
462                                         }
463                                 }
464                                 if (*tok == ']')  // ([bd,Dn]...
465                                 {
466                                         tok++;
467                                         goto IS_SUPPRESSEDn;
468                                 }
469                         }
470                         else if (*tok == ']')
471                         {
472                                 // PC and Xn is suppressed
473                                 AnREG = 6 << 3;         // stuff 110b to mode field
474                                 AnEXTEN |= EXT_BS;
475                         }
476                         else
477                         {
478                                 goto badmode;
479                         }
480
481                         // At a crossroads here. We can accept either ([bd,An/PC],... or ([bd,An/PC,Xn*scale],...
482                         if (*tok == ']')
483                         {
484                                 // ([bd,An/PC],Xn,od)
485                                 // Check for Xn
486                                 tok++;
487
488                                 if (*tok == ')')
489                                 {
490                                         // Xn and od are non existent, get out of jail free card
491                                         tok++;
492                                         AMn = MEMPRE + ea_PC;                           // ([bc,An,Xn],od) with no Xn and od
493                                         AnEXTEN |= EXT_IS | EXT_IISPREN;        // Suppress Xn and od
494                                         goto AnOK;
495                                 }
496                                 else if (*tok != ',')
497                                         return error("comma expected after ]");
498                                 else
499                                         tok++;                          // eat the comma
500
501                                 if ((*tok >= KW_A0) && (*tok <= KW_A7))
502                                 {
503                                         AnIXREG = ((*tok & 7) << 12);
504                                         AnEXTEN |= EXT_A;
505                                         tok++;
506                                 }
507                                 else if ((*tok >= KW_D0) && (*tok <= KW_D7))
508                                 {
509                                         AnEXTEN |= ((*tok & 7) << 12);
510                                         AnEXTEN |= EXT_D;
511                                         tok++;
512                                 }
513                                 else
514                                 {
515                                         // No index found, suppress it
516                                         AnEXTEN |= EXT_IS;
517                                         tok--;                                  // Rewind tok to point to the comma
518                                         goto IS_SUPPRESSEDn;    // https://xkcd.com/292/ - what does he know anyway?
519                                 }
520
521                                 // Check for Xn size
522                                 // ([bd,An/PC],Xn.W/L...)
523                                 switch ((int)*tok)
524                                 {
525                                 // Index reg size: <empty> | .W | .L
526                                 case DOTW:
527                                         tok++;
528                                         break;
529                                 case DOTL:
530                                         AnEXTEN |= EXT_L;
531                                         tok++;
532                                         break;
533                                 case DOTB:
534                                         // .B not allowed here...
535                                         goto badmode;
536                                 default:
537                                         break;
538                                 }
539
540                                 // Check for Xn scale
541                                 if (*tok == '*')                   // ([bd,An/PC],Xn*...)
542                                 {                                  // scale: *1, *2, *4, *8
543                                         tok++;
544
545                                         if (*tok == SYMBOL)
546                                         {
547                                                 if (expr(scaleexpr, &scaleval, &scaleattr, &scaleesym) != OK)
548                                                         return error("scale factor expression must evaluate");
549                                         }
550                                         else if (*tok == CONST)
551                                         {
552                                                 scaleval = (int)*tok++;
553                                                 tok++;  // Take into account that constants are 64-bit
554                                         }
555                                         else
556                                                 goto badmode;
557
558                                         switch (scaleval)
559                                         {
560                                         case 1:
561                                                 break;
562                                         case 2:
563                                                 AnIXSIZ |= TIMES2;
564                                                 break;
565                                         case 4:
566                                                 AnIXSIZ |= TIMES4;
567                                                 break;
568                                         case 8:
569                                                 AnIXSIZ |= TIMES8;
570                                                 break;
571                                         default:
572                                                 goto badmode;
573                                         }
574                                         
575                                 }
576
577                                 // Check for od
578                                 if (*tok == ')')        // ([bd,An/PC],Xn)
579                                 {
580                                         // od is non existent, get out of jail free card
581                                         AMn = MEMPOST + ea_PC;  // let's say it's ([bd,An],Xn,od) with od=0 then
582                                         AnEXTEN |= EXT_IISPOSN; // No outer displacement
583                                         tok++;
584                                         goto AnOK;
585                                 }
586                                 else if (*tok != ',')
587                                         return error("comma expected");
588                                 else
589                                         tok++;  // eat the comma
590
591 CHECKODn:
592                                 if (expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
593                                         goto badmode;
594
595                                 if (CHECK_OPTS(OPT_020_DISP) && (AnEXATTR & DEFINED) && (AnEXVAL == 0))
596                                 {
597                                         // od = 0 so optimise it out
598                                         AMn = MEMPOST + ea_PC;          // let's say it's ([bd,An],Xn,od) with od=0 then
599                                         AnEXTEN |= EXT_IISPOSN;         // No outer displacement
600                                         tok++;
601                                         goto AnOK;
602                                 }
603
604                                 // ([bd,An/PC],Xn,od)
605                                 // Is .W forced here?
606                                 if (*tok == DOTW)
607                                 {
608                                         tok++;
609                                         // od[.W]
610                                         AnEXTEN |= EXT_IISPOSW; // Word outer displacement
611                                         AMn = MEMPOST + ea_PC;
612                                 }
613                                 else
614                                 {
615                                         // Is .L forced here?
616                                         if (*tok == DOTL)
617                                                 tok++;                          // Doesn't matter, we're going for .L anyway
618
619                                         WORD od_ea = 0;
620
621                                         // od.L
622                                         if (!(AnEXTEN & EXT_BS))
623                                                 od_ea = EXT_IISPOSL; // Long outer displacement
624                                         else
625                                         {
626                                                 // bd is suppressed, so sticking the od size in bd
627                                                 od_ea = EXT_BDSIZEL;
628                                                 // And of course the expression has to be copied to
629                                                 // AnBEXPR instead of AnEXPR. Yay. :-/
630                                                 int i = 0;
631
632                                                 do
633                                                 {
634                                                         AnBEXPR[i] = AnEXPR[i];
635                                                         i++;
636                                                 } while (AnEXPR[i] != 'E');
637
638                                                 AnBEXPR[i] = 'E';
639                                         }
640
641                                         AMn = MEMPOST + ea_PC;
642
643                                         // Defined, absolute values from $FFFF8000..$00007FFF get
644                                         // optimized to absolute short
645                                         if (CHECK_OPTS(OPT_020_DISP)
646                                                 && ((AnEXATTR & (TDB | DEFINED)) == DEFINED)
647                                                 && (((uint32_t)AnEXVAL + 0x8000) < 0x10000))
648                                         {
649                                                 od_ea = EXT_IISPOSW; // Word outer displacement
650                                                 AMn = MEMPOST + ea_PC;
651                                                 if (optim_warn_flag)
652                                                         warn("absolute value in outer displacement ranging $FFFF8000..$00007FFF optimised to absolute short");
653                                         }
654                                         AnEXTEN |= od_ea;
655                                 }
656
657                                 // Check for final closing parenthesis
658                                 if (*tok == ')')
659                                 {
660                                         tok++;
661                                         goto AnOK;
662                                 }
663                                 else
664                                         return error("Closing parenthesis missing on addressing mode");
665
666 IS_SUPPRESSEDn:
667
668                                 // Check for od
669                                 if (*tok == ')')        // ([bd,An/PC],Xn)
670                                 {
671                                         // od is non existent, get out of jail free card
672                                         AMn = MEMPOST + ea_PC;          // let's say it's ([bd,An],Xn,od) with od=0 then
673                                         AnEXTEN |= EXT_IISNOIN; // No outer displacement
674                                         tok++;
675                                         goto AnOK;
676                                 }
677                                 else if (*tok!=',')
678                                         return error("comma expected");
679                                 else
680                                         tok++;  // eat the comma
681
682                                 if ((*tok != CONST) && (*tok != SYMBOL))
683                                         goto badmode;
684
685                                 expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM);
686
687                                 if (CHECK_OPTS(OPT_020_DISP) && (AnEXVAL == 0))
688                                 {
689                                         // od=0 so optimise it out
690                                         AMn = MEMPOST + ea_PC;           // let's say it's ([bd,An],Xn,od) with od=0 then
691                                         AnEXTEN |= EXT_IISNOIN; // No outer displacement
692                                         tok++;
693                                         goto AnOK;
694                                 }
695
696                                 // ([bd,An/PC],Xn,od)
697                                 if (*tok == DOTL)
698                                 {
699                                         // expr.L
700                                         tok++;
701                                         AMn = MEMPOST + ea_PC;
702                                         AnEXTEN |= EXT_IISNOIL; // Long outer displacement with IS suppressed
703                                 }
704                                 else
705                                 {
706                                         // expr[.W][]
707                                         AnEXTEN |= EXT_IISNOIW; // Word outer displacement with IS suppressed
708                                         AMn = MEMPRE + ea_PC;;
709
710                                         if (*tok == DOTW)
711                                         {
712                                                 //AnEXTEN|=EXT_IISNOIW; // Word outer displacement
713                                                 AMn = MEMPOST + ea_PC;
714                                                 tok++;
715                                         }
716                                         // Defined, absolute values from $FFFF8000..$00007FFF get
717                                         // optimized to absolute short
718                                         else if (CHECK_OPTS(OPT_020_DISP)
719                                                 && ((AnEXATTR & (TDB | DEFINED)) == DEFINED)
720                                                 && (((uint32_t)AnEXVAL + 0x8000) < 0x10000))
721                                         {
722                                                 //AnEXTEN|=EXT_IISNOIW; // Word outer displacement with IS suppressed
723                                                 if (optim_warn_flag)
724                                                         warn("outer displacement absolute value from $FFFF8000..$00007FFF optimised to absolute short");
725                                         }
726                                 }
727
728                                 // Check for final closing parenthesis
729                                 if (*tok == ')')
730                                 {
731                                         tok++;
732                                         goto AnOK;
733                                 }
734                                 else
735                                         return error("Closing parenthesis missing on addressing mode");
736                         }
737                         else if (*tok == ',')
738                         {
739                                 tok++;                  // ([bd,An,Xn.size*scale],od)
740
741                                 // Check for Xn
742                                 if ((*tok >= KW_A0) && (*tok <= KW_A7))
743                                 {
744                                         AnEXTEN |= ((*tok & 7) << 12);
745                                         AnEXTEN |= EXT_A;
746                                         tok++;
747                                 }
748                                 else if ((*tok >= KW_D0) && (*tok <= KW_D7))
749                                 {
750                                         AnEXTEN |= ((*tok & 7) << 12);
751                                         AnEXTEN |= EXT_D;
752                                         tok++;
753                                 }
754
755                                 // Check for size
756                                 // ([bd,An/PC],Xn.W/L...)
757                                 switch ((int)*tok)
758                                 {
759                                 // Index reg size: <empty> | .W | .L
760                                 case DOTW:
761                                         tok++;
762                                         break;
763                                 default:
764                                         break;
765                                 case DOTL:
766                                         tok++;
767                                         AnEXTEN |= EXT_L;
768                                         break;
769                                 case DOTB:
770                                 // .B not allowed here...
771                                 goto badmode;
772                                 }
773
774                                 // Check for scale
775                                 if (*tok == '*')                                // ([bd,An/PC],Xn*...)
776                                 {                                                               // scale: *1, *2, *4, *8
777                                         tok++;
778
779                                         if (*tok == SYMBOL)
780                                         {
781                                                 if (expr(scaleexpr, &scaleval, &scaleattr, &scaleesym) != OK)
782                                                         return error("scale factor expression must evaluate");
783
784                                                 switch (scaleval)
785                                                 {
786                                                 case 1:
787                                                         break;
788                                                 case 2:
789                                                         AnIXSIZ |= TIMES2;
790                                                         break;
791                                                 case 4:
792                                                         AnIXSIZ |= TIMES4;
793                                                         break;
794                                                 case 8:
795                                                         AnIXSIZ |= TIMES8;
796                                                         break;
797                                                 default:
798                                                         goto badmode;
799                                                 }
800                                         }
801                                         else if (*tok++ != CONST)
802                                                 goto badmode;
803                                         else
804                                         {
805                                                 switch ((int)*tok++)
806                                                 {
807                                                 case 1:
808                                                         break;
809                                                 case 2:
810                                                         AnIXSIZ |= TIMES2;
811                                                         AnEXTEN |= 1 << 9;
812                                                         break;
813                                                 case 4:
814                                                         AnIXSIZ |= TIMES4;
815                                                         AnEXTEN |= 2 << 9;
816                                                         break;
817                                                 case 8:
818                                                         AnIXSIZ |= TIMES8;
819                                                         AnEXTEN |= 3 << 9;
820                                                         break;
821                                                 default:
822                                                         goto badmode;
823                                                 }
824
825                                                 tok++;  // Take into account that constants are 64-bit
826                                         }
827                                 }
828
829                                 // Check for ]
830                                 if (*tok != ']')
831                                         return error("Expected closing bracket ]");
832                                 tok++;                  // Eat the bracket
833
834                                 // Check for od
835                                 if (*tok == ')')        // ([bd,An/PC,Xn]...
836                                 {
837                                         // od is non existent, get out of jail free card
838                                         AMn = MEMPRE + ea_PC;                   // let's say it's ([bd,An,Xn],od) with od suppressed then
839                                         AnEXTEN |= EXT_IISPREN; // No outer displacement
840                                         tok++;
841                                         goto AnOK;
842                                 }
843                                 else if (*tok++ != ',')
844                                         return error("comma expected after ]");
845
846                                 if (*tok == SYMBOL || *tok == CONST)
847                                 {
848                                         if (expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
849                                                 goto badmode;
850
851                                         if (CHECK_OPTS(OPT_020_DISP) && (AnEXVAL == 0) && (AnEXATTR & DEFINED))
852                                         {
853                                                 // od=0 so optimise it out
854                                                 AMn = MEMPRE + ea_PC;            // let's say it's ([bd,An],Xn,od) with od=0 then
855                                                 AnEXTEN |= EXT_IISPRE0; // No outer displacement
856                                                 tok++;
857                                                 goto AnOK;
858                                         }
859                                 }
860
861                                 // ([bd,An/PC,Xn],od)
862                                 if (*tok == DOTL)
863                                 {
864                                         // expr.L
865                                         AMn = MEMPRE + ea_PC;
866                                         tok++;
867                                         AnEXTEN |= EXT_IISPREL;
868                                 }
869                                 else
870                                 {
871                                         // expr.[W]
872                                         AMn = MEMPRE + ea_PC;
873                                         int expr_size = EXT_IISPREW; // Assume we have a .w value
874
875                                         if ((AnEXVAL + 0x8000) > 0x10000)
876                                         {
877                                                 // Long value, so mark it as such for now
878                                                 expr_size = EXT_IISPREL;
879
880                                                 // Defined, absolute values from $FFFF8000..$00007FFF
881                                                 // get optimized to absolute short
882                                                 if (CHECK_OPTS(OPT_020_DISP)
883                                                         && ((AnEXATTR & (TDB | DEFINED)) == DEFINED)
884                                                         && (((uint32_t)AnEXVAL + 0x8000) < 0x10000))
885                                                 {
886                                                         expr_size = EXT_IISPREW;
887
888                                                         if (optim_warn_flag)
889                                                                 warn("outer displacement absolute value from $FFFF8000..$00007FFF optimised to absolute short");
890                                                 }
891                                         }
892
893                                         AnEXTEN |= expr_size; // Assume we have a .w value
894
895                                         // Is .W forced here?
896                                         if (*tok == DOTW)
897                                         {
898                                                 tok++;
899
900                                                 if (expr_size == EXT_IISPREL)
901                                                         return error("outer displacement value does not fit in .w size");
902                                         }
903                                 }
904
905                                 // Check for final closing parenthesis
906                                 if (*tok == ')')
907                                 {
908                                         tok++;
909                                         goto AnOK;
910                                 }
911                                 else
912                                         return error("Closing parenthesis missing on addressing mode");
913                         }
914                         else
915                                 goto badmode;
916                 }
917                 else
918                 {
919                         // (expr...
920                         if (expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
921                                 return ERROR;
922
923                         // It could be that this is really just an expression prefixing a
924                         // register as a displacement...
925                         if (*tok == ')')
926                         {
927                                 tok++;
928                                 goto CHK_FOR_DISPn;
929                         }
930
931                         // Otherwise, check for PC & etc displacements...
932                         if (*tok++ != ',')
933                                 goto badmode;
934
935                         if ((*tok >= KW_A0) && (*tok <= KW_A7))
936                         {
937                                 AnREG = *tok & 7;
938                                 tok++;
939
940                                 if (*tok == ',')
941                                 {
942                                         // Check if we're actually doing d8(An,Dn) or
943                                         // (d16,An,Dn[.size][*scale])
944                                         // TODO: not a very clear cut case from what I can think.
945                                         // The only way to distinguish between the two is to check
946                                         // AnEXVAL and see if it's >127 or <-128. But this doesn't
947                                         // work if AnEXVAL isn't defined yet. For now we fall
948                                         // through to d8(An,Dn) but this might bite us in the arse
949                                         // during fixups...
950                                         if ((AnEXATTR & DEFINED) && (AnEXVAL + 0x80 > 0x100))
951                                         {
952                                                 // We're going to treat it as a full extension format
953                                                 // with no indirect access and no base displacement/
954                                                 // index register suppression
955                                                 AnEXTEN |= EXT_FULLWORD;        // Definitely using full extension format, so set bit 8
956                                                 AnEXTEN |= EXT_IISPRE0;         // No Memory Indirect Action
957                                                 AnEXTEN |= EXT_BDSIZEL;         // Base Displacement Size Long
958                                                 tok++;                                          // Get past the comma
959
960                                                 // Our expression is techically a base displacement,
961                                                 // so let's copy it to the relevant variables so
962                                                 // eagen0.c can pick it up properly
963                                                 AnBEXVAL = AnEXVAL;
964                                                 AnBEXATTR = AnEXATTR;
965
966                                                 if ((*tok >= KW_D0) && (*tok <= KW_D7))
967                                                 {
968                                                         AnEXTEN |= ((*tok++) & 7) << 12;
969                                                         // Check for size
970                                                         {
971                                                                 switch ((int)*tok)
972                                                                 {
973                                                                 // Index reg size: <empty> | .W | .L
974                                                                 case DOTW:
975                                                                         tok++;
976                                                                         break;
977                                                                 default:
978                                                                         break;
979                                                                 case DOTL:
980                                                                         tok++;
981                                                                         AnEXTEN |= EXT_L;
982                                                                         break;
983                                                                 case DOTB:
984                                                                         // .B not allowed here...
985                                                                         goto badmode;
986                                                                 }
987                                                         }
988                                                         // Check for scale
989                                                         if (*tok == '*')                // (d16,An,Dn[.size][*scale])
990                                                         {                                               // scale: *1, *2, *4, *8
991                                                                 tok++;
992
993                                                                 if (*tok == SYMBOL)
994                                                                 {
995                                                                         if (expr(scaleexpr, &scaleval, &scaleattr, &scaleesym) != OK)
996                                                                                 return error("scale factor expression must evaluate");
997
998                                                                         switch (scaleval)
999                                                                         {
1000                                                                         case 1:
1001                                                                                 break;
1002                                                                         case 2:
1003                                                                                 AnIXSIZ |= TIMES2;
1004                                                                                 break;
1005                                                                         case 4:
1006                                                                                 AnIXSIZ |= TIMES4;
1007                                                                                 break;
1008                                                                         case 8:
1009                                                                                 AnIXSIZ |= TIMES8;
1010                                                                                 break;
1011                                                                         default:
1012                                                                                 goto badmode;
1013                                                                         }
1014                                                                 }
1015                                                                 else if (*tok++ != CONST)
1016                                                                         goto badmode;
1017                                                                 else
1018                                                                 {
1019                                                                         switch ((int)*tok++)
1020                                                                         {
1021                                                                         case 1:
1022                                                                                 break;
1023                                                                         case 2:
1024                                                                                 AnIXSIZ |= TIMES2;
1025                                                                                 break;
1026                                                                         case 4:
1027                                                                                 AnIXSIZ |= TIMES4;
1028                                                                                 break;
1029                                                                         case 8:
1030                                                                                 AnIXSIZ |= TIMES8;
1031                                                                                 break;
1032                                                                         default:
1033                                                                                 goto badmode;
1034                                                                         }
1035
1036                                                                         tok++;  // Take into account that constants are 64-bit
1037                                                                 }
1038                                                         }
1039
1040                                                         if (*tok++ != ')')
1041                                                                 return error("Closing parenthesis missing on addressing mode");
1042
1043                                                         // Let's say that this is the closest to our case
1044                                                         AMn = MEMPOST;
1045                                                         goto AnOK;
1046                                                 }
1047                                                 else
1048                                                         goto badmode;
1049                                         }
1050
1051                                         AMn = AINDEXED;
1052                                         goto AMn_IXN;
1053                                 }
1054                                 else if (*tok == ')')
1055                                 {
1056                                         AMn = ADISP;
1057                                         tok++;
1058                                         goto AnOK;
1059                                 }
1060                                 else
1061                                         goto badmode;
1062                         }
1063                         else if (*tok == KW_PC)
1064                         {
1065                                 if (*++tok == ',')
1066                                 {                             // expr(PC,Xn...)
1067                                         AMn = PCINDEXED;
1068                                         goto AMn_IXN;
1069                                 }
1070                                 else if (*tok == ')')
1071                                 {
1072                                         AMn = PCDISP;             // expr(PC)
1073                                         tok++;
1074                                         goto AnOK;
1075                                 }
1076                                 else
1077                                         goto badmode;
1078                         }
1079                         else
1080                                 goto badmode;
1081                 }
1082         }
1083         else if (*tok == '-' && tok[1] == '(' && ((tok[2] >= KW_A0) && (tok[2] <= KW_A7)) && tok[3] == ')')
1084         {
1085                 AMn = APREDEC;
1086                 AnREG = tok[2] & 7;
1087                 tok += 4;
1088         }
1089         else if (*tok == KW_CCR)
1090         {
1091                 AMn = AM_CCR;
1092                 tok++;
1093                 goto AnOK;
1094         }
1095         else if (*tok == KW_SR)
1096         {
1097                 AMn = AM_SR;
1098                 tok++;
1099                 goto AnOK;
1100         }
1101         else if (*tok == KW_USP)
1102         {
1103                 AMn = AM_USP;
1104                 tok++;
1105                 AnREG = 2;      // Added this for the case of USP used in movec (see CREGlut in mach.c). Hopefully nothing gets broken!
1106                 goto AnOK;
1107         }
1108         else if ((*tok >= KW_IC40) && (*tok <= KW_BC40))
1109         {
1110                 AMn = CACHES;
1111                 AnREG = *tok++ - KW_IC40;
1112
1113                 // After a cache keyword only a comma or EOL is allowed
1114                 if ((*tok != ',') && (*tok != EOL))
1115                         return ERROR;
1116                 goto AnOK;
1117         }
1118         else if ((*tok >= KW_SFC) && (*tok <= KW_CRP))
1119         {
1120                 AMn = CREG;
1121                 AnREG = (*tok++) - KW_SFC;
1122                 goto AnOK;
1123         }
1124         else if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
1125         {
1126                 AMn = FREG;
1127                 AnREG = (*tok++ & 7);
1128         }
1129         else if ((*tok >= KW_FPIAR) && (*tok <= KW_FPCR))
1130         {
1131                 AMn = FPSCR;
1132                 AnREG = (1 << ((*tok++) - KW_FPIAR + 10));
1133         }
1134         // expr
1135         // expr.w
1136         // expr.l
1137         // d16(An)
1138         // d8(An,Xn[.siz])
1139         // d16(PC)
1140         // d8(PC,Xn[.siz])
1141         else
1142         {
1143                 if (expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
1144                         return ERROR;
1145
1146 CHK_FOR_DISPn:
1147                 if (*tok == DOTW)
1148                 {
1149                         // expr.W
1150                         tok++;
1151                         AMn = ABSW;
1152
1153                         if (((AnEXATTR & (TDB | DEFINED)) == DEFINED) && (AnEXVAL < 0x10000))
1154                                 AnEXVAL = (int32_t)(int16_t)AnEXVAL;  // Sign extend value
1155
1156                         goto AnOK;
1157                 }
1158                 else if (*tok != '(')
1159                 {
1160                         // expr[.L]
1161                         AMn = ABSL;
1162
1163                         // When PC relative is enforced, check for any symbols that aren't
1164                         // EQU'd, in this case it's an illegal mode
1165                         if ((CHECK_OPTS(OPT_PC_RELATIVE)) && (AnEXATTR & REFERENCED) && (AnEXATTR & DEFINED) && (!(AnEXATTR & EQUATED)))
1166                                 return error("relocation not allowed");
1167
1168                         // .L is forced here
1169                         if (*tok == DOTL)
1170                         {
1171                                 tok++;
1172                                 AMn = ABSL;
1173                         }
1174                         else
1175                         {
1176                                 // Defined, absolute values from $FFFF8000..$00007FFF get
1177                                 // optimized to absolute short
1178                                 if (CHECK_OPTS(OPT_ABS_SHORT)
1179                                         && ((AnEXATTR & (TDB | DEFINED)) == DEFINED)
1180                                         && (((uint32_t)AnEXVAL + 0x8000) < 0x10000))
1181                                 {
1182                                         AMn = ABSW;
1183
1184                                         if (optim_warn_flag)
1185                                                 warn("absolute value from $FFFF8000..$00007FFF optimised to absolute short");
1186                                 }
1187                         }
1188
1189                         goto AnOK;
1190                 }
1191
1192                 tok++;
1193
1194                 if ((*tok >= KW_A0) && (*tok <= KW_A7))
1195                 {
1196                         AnREG = *tok++ & 7;
1197
1198                         if (*tok == ')')
1199                         {
1200                                 AMn = ADISP;
1201                                 tok++;
1202                                 goto AnOK;
1203                         }
1204
1205                         AMn = AINDEXED;
1206                         goto AMn_IXN;
1207                 }
1208                 else if (*tok == KW_PC)
1209                 {
1210                         if (*++tok == ')')
1211                         {
1212                                 AMn = PCDISP;
1213                                 tok++;
1214                                 goto AnOK;
1215                         }
1216
1217                         AMn = PCINDEXED;
1218                         goto AMn_IXN;
1219                 }
1220
1221                 goto badmode;
1222         }
1223
1224         // Addressing mode OK
1225 AnOK:
1226         ;
1227 }
1228
1229 // Clean up dirty little macros
1230 #undef AnOK
1231 #undef AMn
1232 #undef AnREG
1233 #undef AnIXREG
1234 #undef AnIXSIZ
1235 #undef AnEXPR
1236 #undef AnEXVAL
1237 #undef AnEXATTR
1238 #undef AnOEXPR
1239 #undef AnOEXVAL
1240 #undef AnOEXATTR
1241 #undef AnESYM
1242 #undef AMn_IX0
1243 #undef AMn_IXN
1244 #undef CHK_FOR_DISPn
1245 #undef AnBEXPR
1246 #undef AnBEXVAL
1247 #undef AnBEXATTR
1248 #undef AnBZISE
1249 #undef AnEXTEN
1250 #undef AMn_030
1251 #undef IS_SUPPRESSEDn
1252 #undef CHECKODn