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
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);
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);
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";
57 extern int ea0gen(WORD);
58 extern int ea1gen(WORD);
60 // Include code tables
62 // { (WORD)-1, (unsigned long)-1L, (unsigned long)-1L, 0x0000, 0, m_badmode }, // 0
63 { 0xFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000, 0, m_badmode }, // 0
65 { 0, 0L, 0L, 0x0000, 0, m_unimp } // Last entry
68 // Register number << 9
70 0, 1 << 9, 2 << 9, 3 << 9, 4 << 9, 5 << 9, 6 << 9, 7 << 9
73 // SIZB==>00, SIZW==>01, SIZL==>10, SIZN==>01 << 6
77 1<<6, (WORD)-1, // SIZW, n/a
78 2<<6, (WORD)-1, (WORD)-1, (WORD)-1, // SIZL, n/a, n/a, n/a
82 // Byte/word/long size for MOVE instrs
86 0x3000, (WORD)-1, // Word
87 0x2000, (WORD)-1, (WORD)-1, (WORD)-1, // Long
91 // Word/long size (0=.w, 1=.l) in bit 8
95 0, (WORD)-1, // SIZW, n/a
96 1<<8, (WORD)-1, (WORD)-1, (WORD)-1, // SIZL, n/a, n/a, n/a
100 // Addressing mode in bits 6..11 (register/mode fields are reversed)
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
114 int m_unimp(WORD unused1, WORD unused2)
116 return (int)error("unimplemented mnemonic");
120 //int m_badmode(void)
121 int m_badmode(WORD unused1, WORD unused2)
123 return (int)error("inappropriate addressing mode");
127 int m_self(WORD inst, WORD usused)
135 // Do one EA in bits 0..5
137 // Bits in `inst' have the following meaning:
139 // Bit zero specifies which ea (ea0 or ea1) to generate in the lower six bits
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.
146 // If bit two is set, standard size bits are set in the instr in bits 6 and 7.
148 // If bit four is set, bit three specifies which eaXreg to place in bits 9..11
151 int m_ea(WORD inst, WORD siz)
153 WORD flg = inst; // Save flag bits
154 inst &= ~0x3F; // Clobber flag bits in instr
156 // Install "standard" instr size bits
162 // OR-in register number
164 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
166 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
172 inst |= am1 | a1reg; // Get ea1 into instr
173 D_word(inst); // Deposit instr
175 // Generate ea0 if requested
179 ea1gen(siz); // Generate ea1
184 inst |= am0 | a0reg; // Get ea0 into instr
185 D_word(inst); // Deposit instr
186 ea0gen(siz); // Generate ea0
188 // Generate ea1 if requested
198 // Dx,Dy nnnnXXXnssnnnYYY If bit 0 of `inst' is set, install size bits in bits
201 int m_abcd(WORD inst, WORD siz)
210 inst |= a0reg | reg_9[a1reg];
220 int m_adda(WORD inst, WORD siz)
222 inst |= am0 | a0reg | lwsiz_8[siz] | reg_9[a1reg];
224 ea0gen(siz); // Generate EA
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.
234 int m_reg(WORD inst, WORD siz)
241 // Install other register (9..11)
242 inst |= reg_9[a1reg];
244 inst &= ~7; // Clear off crufty bits
245 inst |= a0reg; // Install first register
255 int m_imm(WORD inst, WORD siz)
267 int m_imm8(WORD inst, WORD siz)
280 int m_shr(WORD inst, WORD siz)
282 inst |= reg_9[a0reg] | a1reg | siz_6[siz];
292 int m_shi(WORD inst, WORD siz)
294 inst |= a1reg | siz_6[siz];
296 if (a0exattr & DEFINED)
299 return error(range_error);
301 inst |= (a0exval & 7) << 9;
306 AddFixup(FU_QUICK, sloc, a0expr);
315 // {bset, btst, bchg, bclr} -- #immed,ea -- Dn,ea
317 int m_bitop(WORD inst, WORD siz)
319 // Enforce instruction sizes
321 { // X,Dn must be .n or .l
322 if (siz & (SIZB | SIZW))
323 return error(siz_error);
325 else if (siz & (SIZW | SIZL)) // X,ea must be .n or .b
326 return error(siz_error);
328 // Construct instr and EAs
334 ea0gen(SIZB); // Immediate bit number
338 inst |= reg_9[a0reg];
349 int m_dbra(WORD inst, WORD siz)
357 if (a1exattr & DEFINED)
359 if ((a1exattr & TDB) != cursect)
360 return error(rel_error);
364 if (v + 0x8000 > 0x10000)
365 return error(range_error);
371 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
382 int m_exg(WORD inst, WORD siz)
388 if (am0 == DREG && am1 == DREG)
390 else if (am0 == AREG && am1 == AREG)
396 m = a1reg; // Get AREG into a1reg
404 inst |= m | reg_9[a0reg] | a1reg;
414 int m_link(WORD inst, WORD siz)
426 // Handle MOVE <C_ALL> <C_ALTDATA>
427 // MOVE <C_ALL> <M_AREG>
429 // Optimize MOVE.L #<smalldata>,D0 to a MOVEQ
431 int m_move(WORD inst, WORD size)
433 // Cast the passed in value to an int
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)
440 m_moveq((WORD)0x7000, (WORD)0);
443 warn("move.l #size,dx converted to moveq");
447 inst |= siz_12[siz] | am_6[am1] | reg_9[a1reg] | am0 | a0reg;
455 ea1gen((WORD)siz | 0x8000); // Tell ea1gen we're move ea,ea
463 // move USP,An -- move An,USP
465 int m_usp(WORD inst, WORD siz)
470 inst |= a1reg; // USP, An
472 inst |= a0reg; // An, USP
483 int m_moveq(WORD inst, WORD siz)
487 // Arrange for future fixup
488 if (!(a0exattr & DEFINED))
490 AddFixup(FU_BYTE | FU_SEXT, sloc + 1, a0expr);
493 else if (a0exval + 0x100 >= 0x200)
494 return error(range_error);
496 inst |= reg_9[a1reg] | (a0exval & 0xFF);
502 int movep = 0; // Global flag to indicate we're generating a movep instruction
504 // movep Dn, disp(An) -- movep disp(An), Dn
506 int m_movep(WORD inst, WORD siz)
508 movep = 1; // Tell ea0gen to lay off the 0(a0) optimisations on this one
514 inst |= reg_9[a0reg] | a1reg;
524 inst |= reg_9[a1reg] | a0reg;
541 int m_br(WORD inst, WORD siz)
545 if (a0exattr & DEFINED)
547 if ((a0exattr & TDB) != cursect)
549 //printf("m_br(): a0exattr = %X, cursect = %X, a0exval = %X, sloc = %X\n", a0exattr, cursect, a0exval, sloc);
550 return error(rel_error);
553 v = a0exval - (sloc + 2);
555 // Optimize branch instr. size
558 if (optim_flags[OPT_BSR_BCC_S] && v != 0 && v + 0x80 < 0x100)
564 warn("Bcc.w/BSR.w converted to .s");
570 if (v + 0x8000 > 0x10000)
571 return error(range_error);
581 if (v + 0x80 >= 0x100)
582 return error(range_error);
589 if (v + 0x8000 >= 0x10000)
590 return error(range_error);
598 else if (siz == SIZN)
604 AddFixup(FU_BBRA | FU_PCREL | FU_SEXT, sloc, a0expr);
612 AddFixup(FU_WORD | FU_PCREL | FU_LBRA | FU_ISBRA, sloc, a0expr);
623 int m_addq(WORD inst, WORD siz)
625 inst |= siz_6[siz] | am1 | a1reg;
627 if (a0exattr & DEFINED)
629 if (a0exval > 8 || a0exval == 0) // Range in 1..8
630 return error(range_error);
632 inst |= (a0exval & 7) << 9;
637 AddFixup(FU_QUICK, sloc, a0expr);
650 int m_trap(WORD inst, WORD siz)
654 if (a0exattr & DEFINED)
657 return error(abs_error);
660 return error(range_error);
666 return error(undef_error);
673 // movem <rlist>,ea -- movem ea,<rlist>
675 int m_movem(WORD inst, WORD siz)
683 return error("bad size suffix");
690 // Handle #<expr>, ea
693 if (abs_expr(&eval) != OK)
696 if (eval >= 0x10000L)
697 return error(range_error);
703 if (*tok >= KW_D0 && *tok <= KW_A7)
706 if (reglist(&rmask) < 0)
711 return error("missing comma");
718 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
719 return error("invalid addressing mode");
721 // If APREDEC, reverse register mask
727 for(i=0x8000; i; i>>=1, w>>=1)
728 rmask = (WORD)((rmask << 1) | w & 1);
737 inst |= 0x0400 | am0 | a0reg;
740 return error("missing comma");
743 return error("missing register list");
750 if (abs_expr(&eval) != OK)
754 return error(range_error);
758 else if (reglist(&rmask) < 0)
761 if (!(amsktab[am0] & (C_CTRL | M_APOSTINC)))
762 return error("invalid addressing mode");
774 // CLR.x An ==> SUBA.x An,An
776 int m_clra(WORD inst, WORD siz)
778 inst |= a0reg | reg_9[a0reg] | lwsiz_8[siz];