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