ELF support for RMAC.
[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 "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, 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 //
504 // movep Dn, disp(An) -- movep disp(An), Dn
505 //
506 int m_movep(WORD inst, WORD siz)
507 {
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         return 0;
533 }
534
535
536 //
537 // Bcc -- BSR
538 //
539 int m_br(WORD inst, WORD siz)
540 {
541         VALUE v;
542
543         if (a0exattr & DEFINED)
544         {
545                 if ((a0exattr & TDB) != cursect)
546 //{
547 //printf("m_br(): a0exattr = %X, cursect = %X, a0exval = %X, sloc = %X\n", a0exattr, cursect, a0exval, sloc);
548                         return error(rel_error);
549 //}
550
551                 v = a0exval - (sloc + 2);
552
553                 // Optimize branch instr. size
554                 if (siz == SIZN)
555                 {
556                         if (optim_flags[OPT_BSR_BCC_S] && v != 0 && v + 0x80 < 0x100)
557                         {
558                                 // Fits in .B
559                                 inst |= v & 0xFF;
560                                 D_word(inst);
561                                 if (sbra_flag)
562                                         warn("Bcc.w/BSR.w converted to .s");
563                                 return 0;
564                         }
565                         else
566                         {
567                                 // Fits in .W
568                                 if (v + 0x8000 > 0x10000)
569                                         return error(range_error);
570
571                                 D_word(inst);
572                                 D_word(v);
573                                 return 0;
574                         }
575                 }
576
577                 if (siz == SIZB)
578                 {
579                         if (v + 0x80 >= 0x100)
580                                 return error(range_error);
581
582                         inst |= v & 0xFF;
583                         D_word(inst);
584                 }
585                 else
586                 {
587                         if (v + 0x8000 >= 0x10000)
588                                 return error(range_error);
589
590                         D_word(inst);
591                         D_word(v);
592                 }
593
594                 return 0;
595         }
596         else if (siz == SIZN)
597                 siz = SIZW;
598
599         if (siz == SIZB)
600         {
601                 // .B
602                 AddFixup(FU_BBRA | FU_PCREL | FU_SEXT, sloc, a0expr);
603                 D_word(inst);
604                 return 0;
605         }
606         else
607         {
608                 // .W
609                 D_word(inst);
610                 AddFixup(FU_WORD | FU_PCREL | FU_LBRA | FU_ISBRA, sloc, a0expr);
611                 D_word(0);
612         }
613
614         return 0;
615 }
616
617
618 //
619 // ADDQ -- SUBQ
620 //
621 int m_addq(WORD inst, WORD siz)
622 {
623         inst |= siz_6[siz] | am1 | a1reg;
624
625         if (a0exattr & DEFINED)
626         {
627                 if (a0exval > 8 ||      a0exval == 0)                       // Range in 1..8
628                         return error(range_error);
629
630                 inst |= (a0exval & 7) << 9;
631                 D_word(inst);
632         }
633         else
634         {
635                 AddFixup(FU_QUICK, sloc, a0expr);
636                 D_word(inst);
637         }
638
639         ea1gen(siz);
640
641         return 0;
642 }
643
644
645 //
646 // trap #n
647 //
648 int m_trap(WORD inst, WORD siz)
649 {
650         siz = siz;
651
652         if (a0exattr & DEFINED)
653         {
654                 if (a0exattr & TDB)
655                         return error(abs_error);
656
657                 if (a0exval >= 16)
658                         return error(range_error);
659
660                 inst |= a0exval;
661                 D_word(inst);
662         }
663         else
664                 return error(undef_error);
665
666         return 0;
667 }
668
669
670 //
671 // movem <rlist>,ea -- movem ea,<rlist>
672 //
673 int m_movem(WORD inst, WORD siz)
674 {
675         VALUE eval;
676         WORD i;
677         WORD w;
678         WORD rmask;
679
680         if (siz & SIZB)
681                 return error("bad size suffix");
682
683         if (siz == SIZL)
684                 inst |= 0x0040;
685
686         if (*tok == '#')
687         {
688                 // Handle #<expr>, ea
689                 tok++;
690
691                 if (abs_expr(&eval) != OK)
692                         return 0;
693
694                 if (eval >= 0x10000L)
695                         return error(range_error);
696
697                 rmask = (WORD)eval;
698                 goto immed1;
699         }
700
701         if (*tok >= KW_D0 && *tok <= KW_A7)
702         {
703                 // <rlist>, ea
704                 if (reglist(&rmask) < 0)
705                         return 0;
706
707 immed1:
708                 if (*tok++ != ',')
709                         return error("missing comma");
710
711                 if (amode(0) < 0)
712                         return 0;
713
714                 inst |= am0 | a0reg;
715
716                 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
717                         return error("invalid addressing mode");
718
719                 // If APREDEC, reverse register mask
720                 if (am0 == APREDEC)
721                 {
722                         w = rmask;
723                         rmask = 0;
724
725                         for(i=0x8000; i; i>>=1, w>>=1)
726                                 rmask = (WORD)((rmask << 1) | w & 1);
727                 }
728         }
729         else
730         {
731                 // ea, <rlist>
732                 if (amode(0) < 0)
733                         return 0;
734
735                 inst |= 0x0400 | am0 | a0reg;
736
737                 if (*tok++ != ',')
738                         return error("missing comma");
739
740                 if (*tok == EOL)
741                         return error("missing register list");
742
743                 if (*tok == '#')
744                 {
745                         // ea, #<expr>
746                         tok++;
747
748                         if (abs_expr(&eval) != OK)
749                                 return 0;
750
751                         if (eval >= 0x10000)
752                                 return error(range_error);
753
754                         rmask = (WORD)eval;
755                 }
756                 else if (reglist(&rmask) < 0)
757                         return 0;
758
759                 if (!(amsktab[am0] & (C_CTRL | M_APOSTINC)))
760                         return error("invalid addressing mode");
761         }
762
763         D_word(inst);
764         D_word(rmask);
765         ea0gen(siz);
766
767         return 0;
768 }
769
770
771 //
772 // CLR.x An ==> SUBA.x An,An
773 //
774 int m_clra(WORD inst, WORD siz)
775 {
776         inst |= a0reg | reg_9[a0reg] | lwsiz_8[siz];
777         D_word(inst);
778
779         return 0;
780 }
781