Extended switch -s to also warn about automatically applied 68000 optimisations....
[rmac] / mach.c
1 //
2 // RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
3 // MACH.C - Code Generation
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 "mach.h"
10 #include "error.h"
11 #include "sect.h"
12 #include "direct.h"
13 #include "token.h"
14 #include "procln.h"
15 #include "riscasm.h"
16 #include "rmac.h"
17
18 #define DEF_KW
19 #include "kwtab.h"
20
21
22 // Fucntion prototypes 
23 int m_unimp(WORD, WORD), m_badmode(WORD, WORD), m_bad6mode(WORD, WORD), m_bad6inst(WORD, WORD);
24 int m_self(WORD, WORD);
25 int m_abcd(WORD, WORD);
26 int m_reg(WORD, WORD);
27 int m_imm(WORD, WORD);
28 int m_imm8(WORD, WORD);
29 int m_shi(WORD, WORD);
30 int m_shr(WORD, WORD);
31 int m_bitop(WORD, WORD);
32 int m_exg(WORD, WORD);
33 int m_ea(WORD, WORD);
34 int m_br(WORD, WORD);
35 int m_dbra(WORD, WORD);
36 int m_link(WORD, WORD);
37 int m_adda(WORD, WORD);
38 int m_addq(WORD, WORD);
39 //int m_move(WORD, int);
40 int m_move(WORD, WORD);
41 int m_moveq(WORD, WORD);
42 int m_usp(WORD, WORD);
43 int m_movep(WORD, WORD);
44 int m_trap(WORD, WORD);
45 int m_movem(WORD, WORD);
46 int m_clra(WORD, WORD);
47
48 // Common error messages
49 char range_error[] = "expression out of range";
50 char abs_error[] = "illegal absolute expression";
51 char seg_error[] = "bad (section) expression";
52 char rel_error[] = "illegal relative address";
53 char siz_error[] = "bad size specified";
54 char undef_error[] = "undefined expression";
55 char fwd_error[] = "forward or undefined expression";
56
57 extern int ea0gen(WORD);
58 extern int ea1gen(WORD);
59
60 // Include code tables
61 MNTAB machtab[] = {
62 //   { (WORD)-1, (unsigned long)-1L, (unsigned long)-1L, 0x0000, 0, m_badmode }, // 0 
63    { 0xFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000, 0, m_badmode }, // 0 
64    #include "68ktab.h"
65    {  0,  0L,  0L, 0x0000, 0, m_unimp   }                   // Last entry
66 };
67
68 // Register number << 9
69 WORD reg_9[8] = {
70       0, 1<<9, 2<<9, 3<<9,
71    4<<9, 5<<9, 6<<9, 7<<9
72 };
73
74 // SIZB==>00, SIZW==>01, SIZL==>10, SIZN==>01 << 6
75 WORD siz_6[] = {
76    (WORD)-1,                                                // n/a 
77    0,                                                       // SIZB
78    1<<6, (WORD)-1,                                          // SIZW, n/a 
79    2<<6, (WORD)-1, (WORD)-1, (WORD)-1,                      // SIZL, n/a, n/a, n/a 
80    1<<6                                                     // SIZN 
81 };
82
83 // Byte/word/long size for MOVE instrs
84 WORD siz_12[] = {
85    (WORD)-1,
86    0x1000,                                                  // Byte 
87    0x3000, (WORD)-1,                                        // Word 
88    0x2000, (WORD)-1, (WORD)-1, (WORD)-1,                    // Long
89    0x3000                                                   // Word (SIZN)
90 };
91
92 // Word/long size (0=.w, 1=.l) in bit 8
93 WORD lwsiz_8[] = {
94    (WORD)-1,                                                // n/a
95    (WORD)-1,                                                // SIZB
96    0, (WORD)-1,                                             // SIZW, n/a
97    1<<8, (WORD)-1, (WORD)-1, (WORD)-1,                      // SIZL, n/a, n/a, n/a
98    0                                                        // SIZN
99 };
100
101 // Addressing mode in bits 6..11 (register/mode fields are reversed)
102 WORD am_6[] = {
103    00000, 01000, 02000, 03000, 04000, 05000, 06000, 07000,
104    00100, 01100, 02100, 03100, 04100, 05100, 06100, 07100,
105    00200, 01200, 02200, 03200, 04200, 05200, 06200, 07200,
106    00300, 01300, 02300, 03300, 04300, 05300, 06300, 07300,
107    00400, 01400, 02400, 03400, 04400, 05400, 06400, 07400,
108    00500, 01500, 02500, 03500, 04500, 05500, 06500, 07500,
109    00600, 01600, 02600, 03600, 04600, 05600, 06600, 07600,
110    00700, 01700, 02700, 03700, 04700, 05700, 06700, 07700
111 };
112
113
114 // Error messages
115 int m_unimp(WORD unused1, WORD unused2)
116 {
117         return (int)error("unimplemented mnemonic");
118 }
119
120
121 //int m_badmode(void)
122 int m_badmode(WORD unused1, WORD unused2)
123 {
124         return (int)error("inappropriate addressing mode");
125 }
126
127
128 int m_self(WORD inst, WORD usused)
129 {
130         D_word(inst);
131         return 0;
132 }
133
134
135 //
136 // Do one EA in bits 0..5
137 // 
138 // Bits in `inst' have the following meaning:
139 // 
140 // Bit zero specifies which ea (ea0 or ea1) to generate in the lower six bits
141 // of the instr.
142 // 
143 // If bit one is set, the OTHER ea (the one that wasn't generated by bit zero)
144 // is generated after the instruction. Regardless of bit 0's value, ea0 is
145 // always deposited in memory before ea1.
146 // 
147 // If bit two is set, standard size bits are set in the instr in bits 6 and 7.
148 // 
149 // If bit four is set, bit three specifies which eaXreg to place in bits 9..11
150 // of the instr.
151 //
152 int m_ea(WORD inst, WORD siz)
153 {
154         WORD flg = inst;                                        // Save flag bits 
155         inst &= ~0x3F;                                          // Clobber flag bits in instr 
156
157         // Install "standard" instr size bits 
158         if (flg & 4)
159                 inst |= siz_6[siz];
160
161         if (flg & 16)
162         {
163                 // OR-in register number 
164                 if (flg & 8)
165                 {
166                         inst |= reg_9[a1reg];           // ea1reg in bits 9..11 
167                 }
168                 else
169                 {
170                         inst |= reg_9[a0reg];           // ea0reg in bits 9..11 
171                 }
172         }
173
174         if (flg & 1)
175         {
176                 // Use am1 
177                 inst |= am1 | a1reg;                    // Get ea1 into instr 
178                 D_word(inst);                                   // Deposit instr 
179
180                 // Generate ea0 if requested 
181                 if (flg & 2)
182                         ea0gen(siz);
183
184                 ea1gen(siz);                                    // Generate ea1 
185         }
186         else
187         {
188                 // Use am0 
189                 inst |= am0 | a0reg;                    // Get ea0 into instr 
190                 D_word(inst);                                   // Deposit instr 
191                 ea0gen(siz);                                    // Generate ea0 
192
193                 // Generate ea1 if requested 
194                 if (flg & 2)
195                         ea1gen(siz);
196         }
197
198         return 0;
199 }
200
201
202 //
203 // Dx,Dy nnnnXXXnssnnnYYY If bit 0 of `inst' is set, install size bits in bits
204 // 6..7
205 //
206 int m_abcd(WORD inst, WORD siz)
207 {
208         if (inst & 1)
209         {
210                 // Install size bits 
211                 inst--;
212                 inst |= siz_6[siz];
213         }
214
215         inst |= a0reg | reg_9[a1reg];
216         D_word(inst);
217
218         return 0;
219 }
220
221
222 //
223 // {adda} ea,AREG
224 //
225 int m_adda(WORD inst, WORD siz)
226 {
227         inst |= am0 | a0reg | lwsiz_8[siz] | reg_9[a1reg];
228         D_word(inst);
229         ea0gen(siz);    // Generate EA 
230
231         return 0;
232 }
233
234
235 //
236 // If bit 0 of `inst' is 1, install size bits in bits 6..7 of instr.
237 // If bit 1 of `inst' is 1, install a1reg in bits 9..11 of instr.
238 // 
239 int m_reg(WORD inst, WORD siz)
240 {
241         if (inst & 1)
242                 // Install size bits 
243                 inst |= siz_6[siz];
244
245         if (inst & 2)
246                 // Install other register (9..11) 
247                 inst |= reg_9[a1reg];
248
249         inst &= ~7;                     // Clear off crufty bits 
250         inst |= a0reg;          // Install first register 
251         D_word(inst);
252
253         return 0;
254 }
255
256
257 //
258 // <op> #expr
259 //
260 int m_imm(WORD inst, WORD siz)
261 {
262         D_word(inst);
263         ea0gen(siz);
264
265         return 0;
266 }
267
268
269 //
270 // <op>.b #expr
271 //
272 int m_imm8(WORD inst, WORD siz)
273 {
274         siz = siz;
275         D_word(inst);
276         ea0gen(SIZB);
277
278         return 0;
279 }
280
281
282 //
283 // <shift> Dn,Dn
284 //
285 int m_shr(WORD inst, WORD siz)
286 {
287         inst |= reg_9[a0reg] | a1reg | siz_6[siz];
288         D_word(inst);
289
290         return 0;
291 }
292
293
294 //
295 // <shift> #n,Dn
296 //
297 int m_shi(WORD inst, WORD siz)
298 {
299         inst |= a1reg | siz_6[siz];
300
301         if (a0exattr & DEFINED)
302         {
303                 if (a0exval > 8)
304                         return error(range_error);
305
306                 inst |= (a0exval & 7) << 9;
307                 D_word(inst);
308         }
309         else
310         {
311                 AddFixup(FU_QUICK, sloc, a0expr);
312                 D_word(inst);
313         }
314
315         return 0;
316 }
317
318
319 //
320 // {bset, btst, bchg, bclr} -- #immed,ea -- Dn,ea
321 //
322 int m_bitop(WORD inst, WORD siz)
323 {
324         // Enforce instruction sizes
325         if (am1 == DREG)
326         {                               // X,Dn must be .n or .l 
327                 if (siz & (SIZB | SIZW))
328                         return error(siz_error);
329         }
330         else if (siz & (SIZW | SIZL))   // X,ea must be .n or .b 
331                 return error(siz_error);
332
333         // Construct instr and EAs
334         inst |= am1 | a1reg;
335
336         if (am0 == IMMED)
337         {
338                 D_word(inst);
339                 ea0gen(SIZB);                           // Immediate bit number 
340         }
341         else
342         {
343                 inst |= reg_9[a0reg];
344                 D_word(inst);
345         }
346
347         // ea to bit-munch 
348         ea1gen(SIZB);
349
350         return 0;
351 }
352
353
354 int m_dbra(WORD inst, WORD siz)
355 {
356         VALUE v;
357
358         siz = siz;
359         inst |= a0reg;
360         D_word(inst);
361
362         if (a1exattr & DEFINED)
363         {
364                 if ((a1exattr & TDB) != cursect)
365                         return error(rel_error);
366
367                 v = a1exval - sloc;
368
369                 if (v + 0x8000 > 0x10000)
370                         return error(range_error);
371
372                 D_word(v);
373         }
374         else
375         {
376                 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
377                 D_word(0);
378         }
379
380         return 0;
381 }
382
383
384 //
385 // EXG
386 //
387 int m_exg(WORD inst, WORD siz)
388 {
389         int m;
390
391         siz = siz;
392
393         if (am0 == DREG && am1 == DREG)
394                 m = 0x0040;                                           // Dn,Dn 
395         else if (am0 == AREG && am1 == AREG)
396                 m = 0x0048;                                           // An,An 
397         else
398         {
399                 if (am0 == AREG)
400                 {                                     // Dn,An or An,Dn 
401                         m = a1reg;                                         // Get AREG into a1reg 
402                         a1reg = a0reg;
403                         a0reg = m;
404                 }
405
406                 m = 0x0088;
407         }
408
409         inst |= m | reg_9[a0reg] | a1reg;
410         D_word(inst);
411
412         return 0;
413 }
414
415
416 //
417 // LINK
418 //
419 int m_link(WORD inst, WORD siz)
420 {
421         siz = siz;
422         inst |= a0reg;
423         D_word(inst);
424         ea1gen(SIZW);
425
426         return 0;
427 }
428
429
430 //
431 // Handle MOVE <C_ALL> <C_ALTDATA>
432 //        MOVE <C_ALL> <M_AREG>
433 // 
434 // Optimize MOVE.L #<smalldata>,D0 to a MOVEQ
435 //
436 //int m_move(WORD inst, int siz)
437 int m_move(WORD inst, WORD size)
438 {
439         // Cast the passed in value to an int
440         int siz = (int)size;
441
442         // Try to optimize to MOVEQ
443         if (optim_flag && siz == SIZL && am0 == IMMED && am1 == DREG
444                 && (a0exattr & (TDB|DEFINED)) == DEFINED && a0exval + 0x80 < 0x100)
445         {
446                 m_moveq((WORD)0x7000, (WORD)0);
447                 if (sbra_flag)
448                         warn("move.l #size,dx converted to moveq");
449         }
450         else
451         {
452                 inst |= siz_12[siz] | am_6[am1] | reg_9[a1reg] | am0 | a0reg;
453
454                 D_word(inst);
455
456                 if (am0 >= ADISP)
457                         ea0gen((WORD)siz);
458
459                 if (am1 >= ADISP)
460                         ea1gen((WORD)siz);
461         }
462
463         return 0;
464 }
465
466
467 //
468 // move USP,An -- move An,USP
469 //
470 int m_usp(WORD inst, WORD siz)
471 {
472         siz = siz;
473
474         if (am0 == AM_USP)
475                 inst |= a1reg;          // USP, An 
476         else
477                 inst |= a0reg;          // An, USP 
478
479         D_word(inst);
480
481         return 0;
482 }
483
484
485 //
486 // moveq
487 //
488 int m_moveq(WORD inst, WORD siz)
489 {
490         siz = siz;
491
492         // Arrange for future fixup 
493         if (!(a0exattr & DEFINED))
494         {
495                 AddFixup(FU_BYTE | FU_SEXT, sloc + 1, a0expr);
496                 a0exval = 0; 
497         }
498         else if (a0exval + 0x100 >= 0x200)
499                 return error(range_error);
500
501         inst |= reg_9[a1reg] | (a0exval & 0xFF);
502         D_word(inst);
503
504         return 0;
505 }
506
507
508 //
509 // movep Dn, disp(An) -- movep disp(An), Dn
510 //
511 int m_movep(WORD inst, WORD siz)
512 {
513         if (siz == SIZL)
514                 inst |= 0x0040;
515
516         if (am0 == DREG)
517         {
518                 inst |= reg_9[a0reg] | a1reg;
519                 D_word(inst);
520
521                 if (am1 == AIND)
522                         D_word(0)
523                 else 
524                         ea1gen(siz);
525         }
526         else
527         {
528                 inst |= reg_9[a1reg] | a0reg;
529                 D_word(inst);
530
531                 if (am0 == AIND)
532                         D_word(0)
533                 else 
534                         ea0gen(siz);
535         }
536
537         return 0;
538 }
539
540
541 //
542 // Bcc -- BSR
543 //
544 int m_br(WORD inst, WORD siz)
545 {
546         VALUE v;
547
548         if (a0exattr & DEFINED)
549         {
550                 if ((a0exattr & TDB) != cursect)
551 //{
552 //printf("m_br(): a0exattr = %X, cursect = %X, a0exval = %X, sloc = %X\n", a0exattr, cursect, a0exval, sloc);
553                         return error(rel_error);
554 //}
555
556                 v = a0exval - (sloc + 2);
557
558                 // Optimize branch instr. size
559                 if (siz == SIZN)
560                 {
561                         if (optim_flag && v != 0 && v + 0x80 < 0x100)
562                         {
563                                 // Fits in .B 
564                                 inst |= v & 0xFF;
565                                 D_word(inst);
566                                 if (sbra_flag)
567                                         warn("Bcc.w/BSR.w converted to .s");
568                                 return 0;
569                         }
570                         else
571                         {
572                                 // Fits in .W 
573                                 if (v + 0x8000 > 0x10000)
574                                         return error(range_error);
575
576                                 D_word(inst);
577                                 D_word(v);
578                                 return 0;
579                         }
580                 }
581
582                 if (siz == SIZB)
583                 {
584                         if (v + 0x80 >= 0x100)
585                                 return error(range_error);
586
587                         inst |= v & 0xFF;
588                         D_word(inst);
589                 }
590                 else
591                 {
592                         if (v + 0x8000 >= 0x10000)
593                                 return error(range_error);
594
595                         D_word(inst);
596                         D_word(v);
597                 }
598
599                 return 0;
600         }
601         else if (siz == SIZN)
602                 siz = SIZW;
603
604         if (siz == SIZB)
605         {
606                 // .B 
607                 AddFixup(FU_BBRA | FU_PCREL | FU_SEXT, sloc, a0expr);
608                 D_word(inst);
609                 return 0;
610         }
611         else
612         {
613                 // .W 
614                 D_word(inst);
615                 AddFixup(FU_WORD | FU_PCREL | FU_LBRA | FU_ISBRA, sloc, a0expr);
616                 D_word(0);
617         }
618
619         return 0;
620 }
621
622
623 //
624 // ADDQ -- SUBQ
625 //
626 int m_addq(WORD inst, WORD siz)
627 {
628         inst |= siz_6[siz] | am1 | a1reg;
629
630         if (a0exattr & DEFINED)
631         {
632                 if (a0exval > 8 ||      a0exval == 0)                       // Range in 1..8 
633                         return error(range_error);
634
635                 inst |= (a0exval & 7) << 9;
636                 D_word(inst);
637         }
638         else
639         {
640                 AddFixup(FU_QUICK, sloc, a0expr);
641                 D_word(inst);
642         }
643
644         ea1gen(siz);
645
646         return 0;
647 }
648
649
650 //
651 // trap #n
652 //
653 int m_trap(WORD inst, WORD siz)
654 {
655         siz = siz;
656
657         if (a0exattr & DEFINED)
658         {
659                 if (a0exattr & TDB)
660                         return error(abs_error);
661
662                 if (a0exval >= 16)
663                         return error(range_error);
664
665                 inst |= a0exval;
666                 D_word(inst);
667         }
668         else 
669                 return error(undef_error);
670
671         return 0;
672 }
673
674
675 //
676 // movem <rlist>,ea -- movem ea,<rlist>
677 //
678 int m_movem(WORD inst, WORD siz)
679 {
680         VALUE eval;
681         WORD i;
682         WORD w;
683         WORD rmask;
684
685         if (siz & SIZB)
686                 return error("bad size suffix");
687
688         if (siz == SIZL)
689                 inst |= 0x0040;
690
691         if (*tok == '#')
692         {
693                 // Handle #<expr>, ea 
694                 tok++;
695
696                 if (abs_expr(&eval) != OK)
697                         return 0;
698
699                 if (eval >= 0x10000L)
700                         return error(range_error);
701
702                 rmask = (WORD)eval;
703                 goto immed1;
704         }
705
706         if (*tok >= KW_D0 && *tok <= KW_A7)
707         {
708                 // <rlist>, ea 
709                 if (reglist(&rmask) < 0)
710                         return 0;
711
712 immed1:
713                 if (*tok++ != ',')
714                         return error("missing comma");
715
716                 if (amode(0) < 0)
717                         return 0;
718
719                 inst |= am0 | a0reg;
720
721                 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
722                         return error("invalid addressing mode");
723
724                 // If APREDEC, reverse register mask
725                 if (am0 == APREDEC)
726                 {
727                         w = rmask;
728                         rmask = 0;
729
730                         for(i=0x8000; i; i>>=1, w>>=1)
731                                 rmask = (WORD)((rmask << 1) | w & 1);
732                 }
733         }
734         else
735         {
736                 // ea, <rlist> 
737                 if (amode(0) < 0)
738                         return 0;
739
740                 inst |= 0x0400 | am0 | a0reg;
741
742                 if (*tok++ != ',')
743                         return error("missing comma");
744
745                 if (*tok == EOL)
746                         return error("missing register list");
747
748                 if (*tok == '#')
749                 {
750                         // ea, #<expr> 
751                         tok++;
752
753                         if (abs_expr(&eval) != OK)
754                                 return 0;
755
756                         if (eval >= 0x10000)
757                                 return error(range_error);
758
759                         rmask = (WORD)eval;
760                 }
761                 else if (reglist(&rmask) < 0)
762                         return 0;
763
764                 if (!(amsktab[am0] & (C_CTRL | M_APOSTINC)))
765                         return error("invalid addressing mode");
766         }
767
768         D_word(inst);
769         D_word(rmask);
770         ea0gen(siz);
771
772         return 0;
773 }
774
775
776 //
777 // CLR.x An ==> SUBA.x An,An
778 //
779 int m_clra(WORD inst, WORD siz)
780 {
781         inst |= a0reg | reg_9[a0reg] | lwsiz_8[siz];
782         D_word(inst);
783
784         return 0;
785 }
786