e0640e554a6bdcbd2a1bf2772535fef15e8bf5e7
[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
17 #define DEF_KW
18 #include "kwtab.h"
19
20
21 // Fucntion prototypes 
22 int m_unimp(WORD, WORD), m_badmode(WORD, WORD), m_bad6mode(WORD, WORD), m_bad6inst(WORD, WORD);
23 int m_self(WORD, WORD);
24 int m_abcd(WORD, WORD);
25 int m_reg(WORD, WORD);
26 int m_imm(WORD, WORD);
27 int m_imm8(WORD, WORD);
28 int m_shi(WORD, WORD);
29 int m_shr(WORD, WORD);
30 int m_bitop(WORD, WORD);
31 int m_exg(WORD, WORD);
32 int m_ea(WORD, WORD);
33 int m_br(WORD, WORD);
34 int m_dbra(WORD, WORD);
35 int m_link(WORD, WORD);
36 int m_adda(WORD, WORD);
37 int m_addq(WORD, WORD);
38 //int m_move(WORD, int);
39 int m_move(WORD, WORD);
40 int m_moveq(WORD, WORD);
41 int m_usp(WORD, WORD);
42 int m_movep(WORD, WORD);
43 int m_trap(WORD, WORD);
44 int m_movem(WORD, WORD);
45 int m_clra(WORD, WORD);
46
47 // Common error messages
48 char range_error[] = "expression out of range";
49 char abs_error[] = "illegal absolute expression";
50 char seg_error[] = "bad (section) expression";
51 char rel_error[] = "illegal relative address";
52 char siz_error[] = "bad size specified";
53 char undef_error[] = "undefined expression";
54 char fwd_error[] = "forward or undefined expression";
55
56 extern int ea0gen(WORD);
57 extern int ea1gen(WORD);
58
59 // Include code tables
60 MNTAB machtab[] = {
61 //   { (WORD)-1, (unsigned long)-1L, (unsigned long)-1L, 0x0000, 0, m_badmode }, // 0 
62    { 0xFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000, 0, m_badmode }, // 0 
63    #include "68ktab.h"
64    {  0,  0L,  0L, 0x0000, 0, m_unimp   }                   // Last entry
65 };
66
67 // Register number << 9
68 WORD reg_9[8] = {
69       0, 1<<9, 2<<9, 3<<9,
70    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                 {
165                         inst |= reg_9[a1reg];           // ea1reg in bits 9..11 
166                 }
167                 else
168                 {
169                         inst |= reg_9[a0reg];           // ea0reg in bits 9..11 
170                 }
171         }
172
173         if (flg & 1)
174         {
175                 // Use am1 
176                 inst |= am1 | a1reg;                    // Get ea1 into instr 
177                 D_word(inst);                                   // Deposit instr 
178
179                 // Generate ea0 if requested 
180                 if (flg & 2)
181                         ea0gen(siz);
182
183                 ea1gen(siz);                                    // Generate ea1 
184         }
185         else
186         {
187                 // Use am0 
188                 inst |= am0 | a0reg;                    // Get ea0 into instr 
189                 D_word(inst);                                   // Deposit instr 
190                 ea0gen(siz);                                    // Generate ea0 
191
192                 // Generate ea1 if requested 
193                 if (flg & 2)
194                         ea1gen(siz);
195         }
196
197         return 0;
198 }
199
200
201 //
202 // Dx,Dy nnnnXXXnssnnnYYY If bit 0 of `inst' is set, install size bits in bits
203 // 6..7
204 //
205 int m_abcd(WORD inst, WORD siz)
206 {
207         if (inst & 1)
208         {
209                 // Install size bits 
210                 inst--;
211                 inst |= siz_6[siz];
212         }
213
214         inst |= a0reg | reg_9[a1reg];
215         D_word(inst);
216
217         return 0;
218 }
219
220
221 //
222 // {adda} ea,AREG
223 //
224 int m_adda(WORD inst, WORD siz)
225 {
226         inst |= am0 | a0reg | lwsiz_8[siz] | reg_9[a1reg];
227         D_word(inst);
228         ea0gen(siz);    // Generate EA 
229
230         return 0;
231 }
232
233
234 //
235 // If bit 0 of `inst' is 1, install size bits in bits 6..7 of instr.
236 // If bit 1 of `inst' is 1, install a1reg in bits 9..11 of instr.
237 // 
238 int m_reg(WORD inst, WORD siz)
239 {
240         if (inst & 1)
241                 // Install size bits 
242                 inst |= siz_6[siz];
243
244         if (inst & 2)
245                 // Install other register (9..11) 
246                 inst |= reg_9[a1reg];
247
248         inst &= ~7;                     // Clear off crufty bits 
249         inst |= a0reg;          // Install first register 
250         D_word(inst);
251
252         return 0;
253 }
254
255
256 //
257 // <op> #expr
258 //
259 int m_imm(WORD inst, WORD siz)
260 {
261         D_word(inst);
262         ea0gen(siz);
263
264         return 0;
265 }
266
267
268 //
269 // <op>.b #expr
270 //
271 int m_imm8(WORD inst, WORD siz)
272 {
273         siz = siz;
274         D_word(inst);
275         ea0gen(SIZB);
276
277         return 0;
278 }
279
280
281 //
282 // <shift> Dn,Dn
283 //
284 int m_shr(WORD inst, WORD siz)
285 {
286         inst |= reg_9[a0reg] | a1reg | siz_6[siz];
287         D_word(inst);
288
289         return 0;
290 }
291
292
293 //
294 // <shift> #n,Dn
295 //
296 int m_shi(WORD inst, WORD siz)
297 {
298         inst |= a1reg | siz_6[siz];
299
300         if (a0exattr & DEFINED)
301         {
302                 if (a0exval > 8)
303                         return error(range_error);
304
305                 inst |= (a0exval & 7) << 9;
306                 D_word(inst);
307         }
308         else
309         {
310                 fixup(FU_QUICK, sloc, a0expr);
311                 D_word(inst);
312         }
313
314         return 0;
315 }
316
317
318 //
319 // {bset, btst, bchg, bclr} -- #immed,ea -- Dn,ea
320 //
321 int m_bitop(WORD inst, WORD siz)
322 {
323         // Enforce instruction sizes
324         if (am1 == DREG)
325         {                               // X,Dn must be .n or .l 
326                 if (siz & (SIZB | SIZW))
327                         return error(siz_error);
328         }
329         else if (siz & (SIZW | SIZL))   // X,ea must be .n or .b 
330                 return error(siz_error);
331
332         // Construct instr and EAs
333         inst |= am1 | a1reg;
334
335         if (am0 == IMMED)
336         {
337                 D_word(inst);
338                 ea0gen(SIZB);                           // Immediate bit number 
339         }
340         else
341         {
342                 inst |= reg_9[a0reg];
343                 D_word(inst);
344         }
345
346         // ea to bit-munch 
347         ea1gen(SIZB);
348
349         return 0;
350 }
351
352
353 int m_dbra(WORD inst, WORD siz)
354 {
355         VALUE v;
356
357         siz = siz;
358         inst |= a0reg;
359         D_word(inst);
360
361         if (a1exattr & DEFINED)
362         {
363                 if ((a1exattr & TDB) != cursect)
364                         return error(rel_error);
365
366                 v = a1exval - sloc;
367
368                 if (v + 0x8000 > 0x10000)
369                         return error(range_error);
370
371                 D_word(v);
372         }
373         else
374         {
375                 fixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
376                 D_word(0);
377         }
378
379         return 0;
380 }
381
382
383 //
384 // EXG
385 //
386 int m_exg(WORD inst, WORD siz)
387 {
388         int m;
389
390         siz = siz;
391
392         if (am0 == DREG && am1 == DREG)
393                 m = 0x0040;                                           // Dn,Dn 
394         else if (am0 == AREG && am1 == AREG)
395                 m = 0x0048;                                           // An,An 
396         else
397         {
398                 if (am0 == AREG)
399                 {                                     // Dn,An or An,Dn 
400                         m = a1reg;                                         // Get AREG into a1reg 
401                         a1reg = a0reg;
402                         a0reg = m;
403                 }
404
405                 m = 0x0088;
406         }
407
408         inst |= m | reg_9[a0reg] | a1reg;
409         D_word(inst);
410
411         return 0;
412 }
413
414
415 //
416 // LINK
417 //
418 int m_link(WORD inst, WORD siz)
419 {
420         siz = siz;
421         inst |= a0reg;
422         D_word(inst);
423         ea1gen(SIZW);
424
425         return 0;
426 }
427
428
429 //
430 // Handle MOVE <C_ALL> <C_ALTDATA>
431 //        MOVE <C_ALL> <M_AREG>
432 // 
433 // Optimize MOVE.L #<smalldata>,D0 to a MOVEQ
434 //
435 //int m_move(WORD inst, int siz)
436 int m_move(WORD inst, WORD size)
437 {
438         // Cast the passed in value to an int
439         int siz = (int)size;
440
441         // Try to optimize to MOVEQ
442         if (siz == SIZL && am0 == IMMED && am1 == DREG
443                 && (a0exattr & (TDB|DEFINED)) == DEFINED && a0exval + 0x80 < 0x100)
444         {
445                 m_moveq((WORD)0x7000, (WORD)0);
446         }
447         else
448         {
449                 inst |= siz_12[siz] | am_6[am1] | reg_9[a1reg] | am0 | a0reg;
450
451                 D_word(inst);
452
453                 if (am0 >= ADISP)
454                         ea0gen((WORD)siz);
455
456                 if (am1 >= ADISP)
457                         ea1gen((WORD)siz);
458         }
459
460         return 0;
461 }
462
463
464 //
465 // move USP,An -- move An,USP
466 //
467 int m_usp(WORD inst, WORD siz)
468 {
469         siz = siz;
470
471         if (am0 == AM_USP)
472                 inst |= a1reg;          // USP, An 
473         else
474                 inst |= a0reg;          // An, USP 
475
476         D_word(inst);
477
478         return 0;
479 }
480
481
482 //
483 // moveq
484 //
485 int m_moveq(WORD inst, WORD siz)
486 {
487         siz = siz;
488
489         // Arrange for future fixup 
490         if (!(a0exattr & DEFINED))
491         {
492                 fixup(FU_BYTE | FU_SEXT, sloc + 1, a0expr);
493                 a0exval = 0; 
494         }
495         else if (a0exval + 0x100 >= 0x200)
496                 return error(range_error);
497
498         inst |= reg_9[a1reg] | (a0exval & 0xFF);
499         D_word(inst);
500
501         return 0;
502 }
503
504
505 //
506 // movep Dn, disp(An) -- movep disp(An), Dn
507 //
508 int m_movep(WORD inst, WORD siz)
509 {
510         if (siz == SIZL)
511                 inst |= 0x0040;
512
513         if (am0 == DREG)
514         {
515                 inst |= reg_9[a0reg] | a1reg;
516                 D_word(inst);
517
518                 if (am1 == AIND)
519                         D_word(0)
520                 else 
521                         ea1gen(siz);
522         }
523         else
524         {
525                 inst |= reg_9[a1reg] | a0reg;
526                 D_word(inst);
527
528                 if (am0 == AIND)
529                         D_word(0)
530                 else 
531                         ea0gen(siz);
532         }
533
534         return 0;
535 }
536
537
538 //
539 // Bcc -- BSR
540 //
541 int m_br(WORD inst, WORD siz)
542 {
543         VALUE v;
544
545         if (a0exattr & DEFINED)
546         {
547                 if ((a0exattr & TDB) != cursect)
548                         return error(rel_error);
549
550                 v = a0exval - (sloc + 2);
551
552                 // Optimize branch instr. size
553                 if (siz == SIZN)
554                 {
555                         if (v != 0 && v + 0x80 < 0x100)
556                         {
557                                 // Fits in .B 
558                                 inst |= v & 0xFF;
559                                 D_word(inst);
560                                 return 0;
561                         }
562                         else
563                         {
564                                 // Fits in .W 
565                                 if (v + 0x8000 > 0x10000)
566                                         return error(range_error);
567
568                                 D_word(inst);
569                                 D_word(v);
570                                 return 0;
571                         }
572                 }
573
574                 if (siz == SIZB)
575                 {
576                         if (v + 0x80 >= 0x100)
577                                 return error(range_error);
578
579                         inst |= v & 0xFF;
580                         D_word(inst);
581                 }
582                 else
583                 {
584                         if (v + 0x8000 >= 0x10000)
585                                 return error(range_error);
586
587                         D_word(inst);
588                         D_word(v);
589                 }
590
591                 return 0;
592         }
593         else if (siz == SIZN)
594                 siz = SIZW;
595
596         if (siz == SIZB)
597         {
598                 // .B 
599                 fixup(FU_BBRA | FU_PCREL | FU_SEXT, sloc, a0expr);
600                 D_word(inst);
601                 return 0;
602         }
603         else
604         {
605                 // .W 
606                 D_word(inst);
607                 fixup(FU_WORD | FU_PCREL | FU_LBRA | FU_ISBRA, sloc, a0expr);
608                 D_word(0);
609         }
610
611         return 0;
612 }
613
614
615 //
616 // ADDQ -- SUBQ
617 //
618 int m_addq(WORD inst, WORD siz)
619 {
620         inst |= siz_6[siz] | am1 | a1reg;
621
622         if (a0exattr & DEFINED)
623         {
624                 if (a0exval > 8 ||      a0exval == 0)                       // Range in 1..8 
625                         return error(range_error);
626
627                 inst |= (a0exval & 7) << 9;
628                 D_word(inst);
629         }
630         else
631         {
632                 fixup(FU_QUICK, sloc, a0expr);
633                 D_word(inst);
634         }
635
636         ea1gen(siz);
637
638         return 0;
639 }
640
641
642 //
643 // trap #n
644 //
645 int m_trap(WORD inst, WORD siz)
646 {
647         siz = siz;
648
649         if (a0exattr & DEFINED)
650         {
651                 if (a0exattr & TDB)
652                         return error(abs_error);
653
654                 if (a0exval >= 16)
655                         return error(range_error);
656
657                 inst |= a0exval;
658                 D_word(inst);
659         }
660         else 
661                 return error(undef_error);
662
663         return 0;
664 }
665
666
667 //
668 // movem <rlist>,ea -- movem ea,<rlist>
669 //
670 int m_movem(WORD inst, WORD siz)
671 {
672         VALUE eval;
673         WORD i;
674         WORD w;
675         WORD rmask;
676
677         if (siz & SIZB)
678                 return error("bad size suffix");
679
680         if (siz == SIZL)
681                 inst |= 0x0040;
682
683         if (*tok == '#')
684         {
685                 // Handle #<expr>, ea 
686                 tok++;
687
688                 if (abs_expr(&eval) != OK)
689                         return 0;
690
691                 if (eval >= 0x10000L)
692                         return error(range_error);
693
694                 rmask = (WORD)eval;
695                 goto immed1;
696         }
697
698         if (*tok >= KW_D0 && *tok <= KW_A7)
699         {
700                 // <rlist>, ea 
701                 if (reglist(&rmask) < 0)
702                         return 0;
703
704 immed1:
705                 if (*tok++ != ',')
706                         return error("missing comma");
707
708                 if (amode(0) < 0)
709                         return 0;
710
711                 inst |= am0 | a0reg;
712
713                 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
714                         return error("invalid addressing mode");
715
716                 // If APREDEC, reverse register mask
717                 if (am0 == APREDEC)
718                 {
719                         w = rmask;
720                         rmask = 0;
721
722                         for(i=0x8000; i; i>>=1, w>>=1)
723                                 rmask = (WORD)((rmask << 1) | w & 1);
724                 }
725         }
726         else
727         {
728                 // ea, <rlist> 
729                 if (amode(0) < 0)
730                         return 0;
731
732                 inst |= 0x0400 | am0 | a0reg;
733
734                 if (*tok++ != ',')
735                         return error("missing comma");
736
737                 if (*tok == EOL)
738                         return error("missing register list");
739
740                 if (*tok == '#')
741                 {
742                         // ea, #<expr> 
743                         tok++;
744
745                         if (abs_expr(&eval) != OK)
746                                 return 0;
747
748                         if (eval >= 0x10000)
749                                 return error(range_error);
750
751                         rmask = (WORD)eval;
752                 }
753                 else if (reglist(&rmask) < 0)
754                         return 0;
755
756                 if (!(amsktab[am0] & (C_CTRL | M_APOSTINC)))
757                         return error("invalid addressing mode");
758         }
759
760         D_word(inst);
761         D_word(rmask);
762         ea0gen(siz);
763
764         return 0;
765 }
766
767
768 //
769 // CLR.x An ==> SUBA.x An,An
770 //
771 int m_clra(WORD inst, WORD siz)
772 {
773         inst |= a0reg | reg_9[a0reg] | lwsiz_8[siz];
774         D_word(inst);
775
776         return 0;
777 }
778