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
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);
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);
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";
56 extern int ea0gen(WORD);
57 extern int ea1gen(WORD);
59 // Include code tables
61 // { (WORD)-1, (unsigned long)-1L, (unsigned long)-1L, 0x0000, 0, m_badmode }, // 0
62 { 0xFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000, 0, m_badmode }, // 0
64 { 0, 0L, 0L, 0x0000, 0, m_unimp } // Last entry
67 // Register number << 9
70 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
165 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
169 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
176 inst |= am1 | a1reg; // Get ea1 into instr
177 D_word(inst); // Deposit instr
179 // Generate ea0 if requested
183 ea1gen(siz); // Generate ea1
188 inst |= am0 | a0reg; // Get ea0 into instr
189 D_word(inst); // Deposit instr
190 ea0gen(siz); // Generate ea0
192 // Generate ea1 if requested
202 // Dx,Dy nnnnXXXnssnnnYYY If bit 0 of `inst' is set, install size bits in bits
205 int m_abcd(WORD inst, WORD siz)
214 inst |= a0reg | reg_9[a1reg];
224 int m_adda(WORD inst, WORD siz)
226 inst |= am0 | a0reg | lwsiz_8[siz] | reg_9[a1reg];
228 ea0gen(siz); // Generate EA
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.
238 int m_reg(WORD inst, WORD siz)
245 // Install other register (9..11)
246 inst |= reg_9[a1reg];
248 inst &= ~7; // Clear off crufty bits
249 inst |= a0reg; // Install first register
259 int m_imm(WORD inst, WORD siz)
271 int m_imm8(WORD inst, WORD siz)
284 int m_shr(WORD inst, WORD siz)
286 inst |= reg_9[a0reg] | a1reg | siz_6[siz];
296 int m_shi(WORD inst, WORD siz)
298 inst |= a1reg | siz_6[siz];
300 if (a0exattr & DEFINED)
303 return error(range_error);
305 inst |= (a0exval & 7) << 9;
310 fixup(FU_QUICK, sloc, a0expr);
319 // {bset, btst, bchg, bclr} -- #immed,ea -- Dn,ea
321 int m_bitop(WORD inst, WORD siz)
323 // Enforce instruction sizes
325 { // X,Dn must be .n or .l
326 if (siz & (SIZB | SIZW))
327 return error(siz_error);
329 else if (siz & (SIZW | SIZL)) // X,ea must be .n or .b
330 return error(siz_error);
332 // Construct instr and EAs
338 ea0gen(SIZB); // Immediate bit number
342 inst |= reg_9[a0reg];
353 int m_dbra(WORD inst, WORD siz)
361 if (a1exattr & DEFINED)
363 if ((a1exattr & TDB) != cursect)
364 return error(rel_error);
368 if (v + 0x8000 > 0x10000)
369 return error(range_error);
375 fixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
386 int m_exg(WORD inst, WORD siz)
392 if (am0 == DREG && am1 == DREG)
394 else if (am0 == AREG && am1 == AREG)
400 m = a1reg; // Get AREG into a1reg
408 inst |= m | reg_9[a0reg] | a1reg;
418 int m_link(WORD inst, WORD siz)
430 // Handle MOVE <C_ALL> <C_ALTDATA>
431 // MOVE <C_ALL> <M_AREG>
433 // Optimize MOVE.L #<smalldata>,D0 to a MOVEQ
435 //int m_move(WORD inst, int siz)
436 int m_move(WORD inst, WORD size)
438 // Cast the passed in value to an int
441 // Try to optimize to MOVEQ
442 if (siz == SIZL && am0 == IMMED && am1 == DREG
443 && (a0exattr & (TDB|DEFINED)) == DEFINED && a0exval + 0x80 < 0x100)
445 m_moveq((WORD)0x7000, (WORD)0);
449 inst |= siz_12[siz] | am_6[am1] | reg_9[a1reg] | am0 | a0reg;
465 // move USP,An -- move An,USP
467 int m_usp(WORD inst, WORD siz)
472 inst |= a1reg; // USP, An
474 inst |= a0reg; // An, USP
485 int m_moveq(WORD inst, WORD siz)
489 // Arrange for future fixup
490 if (!(a0exattr & DEFINED))
492 fixup(FU_BYTE | FU_SEXT, sloc + 1, a0expr);
495 else if (a0exval + 0x100 >= 0x200)
496 return error(range_error);
498 inst |= reg_9[a1reg] | (a0exval & 0xFF);
506 // movep Dn, disp(An) -- movep disp(An), Dn
508 int m_movep(WORD inst, WORD siz)
515 inst |= reg_9[a0reg] | a1reg;
525 inst |= reg_9[a1reg] | a0reg;
541 int m_br(WORD inst, WORD siz)
545 if (a0exattr & DEFINED)
547 if ((a0exattr & TDB) != cursect)
548 return error(rel_error);
550 v = a0exval - (sloc + 2);
552 // Optimize branch instr. size
555 if (v != 0 && v + 0x80 < 0x100)
565 if (v + 0x8000 > 0x10000)
566 return error(range_error);
576 if (v + 0x80 >= 0x100)
577 return error(range_error);
584 if (v + 0x8000 >= 0x10000)
585 return error(range_error);
593 else if (siz == SIZN)
599 fixup(FU_BBRA | FU_PCREL | FU_SEXT, sloc, a0expr);
607 fixup(FU_WORD | FU_PCREL | FU_LBRA | FU_ISBRA, sloc, a0expr);
618 int m_addq(WORD inst, WORD siz)
620 inst |= siz_6[siz] | am1 | a1reg;
622 if (a0exattr & DEFINED)
624 if (a0exval > 8 || a0exval == 0) // Range in 1..8
625 return error(range_error);
627 inst |= (a0exval & 7) << 9;
632 fixup(FU_QUICK, sloc, a0expr);
645 int m_trap(WORD inst, WORD siz)
649 if (a0exattr & DEFINED)
652 return error(abs_error);
655 return error(range_error);
661 return error(undef_error);
668 // movem <rlist>,ea -- movem ea,<rlist>
670 int m_movem(WORD inst, WORD siz)
678 return error("bad size suffix");
685 // Handle #<expr>, ea
688 if (abs_expr(&eval) != OK)
691 if (eval >= 0x10000L)
692 return error(range_error);
698 if (*tok >= KW_D0 && *tok <= KW_A7)
701 if (reglist(&rmask) < 0)
706 return error("missing comma");
713 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
714 return error("invalid addressing mode");
716 // If APREDEC, reverse register mask
722 for(i=0x8000; i; i>>=1, w>>=1)
723 rmask = (WORD)((rmask << 1) | w & 1);
732 inst |= 0x0400 | am0 | a0reg;
735 return error("missing comma");
738 return error("missing register list");
745 if (abs_expr(&eval) != OK)
749 return error(range_error);
753 else if (reglist(&rmask) < 0)
756 if (!(amsktab[am0] & (C_CTRL | M_APOSTINC)))
757 return error("invalid addressing mode");
769 // CLR.x An ==> SUBA.x An,An
771 int m_clra(WORD inst, WORD siz)
773 inst |= a0reg | reg_9[a0reg] | lwsiz_8[siz];