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
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
71 4<<9, 5<<9, 6<<9, 7<<9
74 // SIZB==>00, SIZW==>01, SIZL==>10, SIZN==>01 << 6
78 1<<6, (WORD)-1, // SIZW, n/a
79 2<<6, (WORD)-1, (WORD)-1, (WORD)-1, // SIZL, n/a, n/a, n/a
83 // Byte/word/long size for MOVE instrs
87 0x3000, (WORD)-1, // Word
88 0x2000, (WORD)-1, (WORD)-1, (WORD)-1, // Long
92 // Word/long size (0=.w, 1=.l) in bit 8
96 0, (WORD)-1, // SIZW, n/a
97 1<<8, (WORD)-1, (WORD)-1, (WORD)-1, // SIZL, n/a, n/a, n/a
101 // Addressing mode in bits 6..11 (register/mode fields are reversed)
103 00000, 01000, 02000, 03000, 04000, 05000, 06000, 07000,
104 00100, 01100, 02100, 03100, 04100, 05100, 06100, 07100,
105 00200, 01200, 02200, 03200, 04200, 05200, 06200, 07200,
106 00300, 01300, 02300, 03300, 04300, 05300, 06300, 07300,
107 00400, 01400, 02400, 03400, 04400, 05400, 06400, 07400,
108 00500, 01500, 02500, 03500, 04500, 05500, 06500, 07500,
109 00600, 01600, 02600, 03600, 04600, 05600, 06600, 07600,
110 00700, 01700, 02700, 03700, 04700, 05700, 06700, 07700
115 int m_unimp(WORD unused1, WORD unused2)
117 return (int)error("unimplemented mnemonic");
121 //int m_badmode(void)
122 int m_badmode(WORD unused1, WORD unused2)
124 return (int)error("inappropriate addressing mode");
128 int m_self(WORD inst, WORD usused)
136 // Do one EA in bits 0..5
138 // Bits in `inst' have the following meaning:
140 // Bit zero specifies which ea (ea0 or ea1) to generate in the lower six bits
143 // If bit one is set, the OTHER ea (the one that wasn't generated by bit zero)
144 // is generated after the instruction. Regardless of bit 0's value, ea0 is
145 // always deposited in memory before ea1.
147 // If bit two is set, standard size bits are set in the instr in bits 6 and 7.
149 // If bit four is set, bit three specifies which eaXreg to place in bits 9..11
152 int m_ea(WORD inst, WORD siz)
154 WORD flg = inst; // Save flag bits
155 inst &= ~0x3F; // Clobber flag bits in instr
157 // Install "standard" instr size bits
163 // OR-in register number
166 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
170 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
177 inst |= am1 | a1reg; // Get ea1 into instr
178 D_word(inst); // Deposit instr
180 // Generate ea0 if requested
184 ea1gen(siz); // Generate ea1
189 inst |= am0 | a0reg; // Get ea0 into instr
190 D_word(inst); // Deposit instr
191 ea0gen(siz); // Generate ea0
193 // Generate ea1 if requested
203 // Dx,Dy nnnnXXXnssnnnYYY If bit 0 of `inst' is set, install size bits in bits
206 int m_abcd(WORD inst, WORD siz)
215 inst |= a0reg | reg_9[a1reg];
225 int m_adda(WORD inst, WORD siz)
227 inst |= am0 | a0reg | lwsiz_8[siz] | reg_9[a1reg];
229 ea0gen(siz); // Generate EA
236 // If bit 0 of `inst' is 1, install size bits in bits 6..7 of instr.
237 // If bit 1 of `inst' is 1, install a1reg in bits 9..11 of instr.
239 int m_reg(WORD inst, WORD siz)
246 // Install other register (9..11)
247 inst |= reg_9[a1reg];
249 inst &= ~7; // Clear off crufty bits
250 inst |= a0reg; // Install first register
260 int m_imm(WORD inst, WORD siz)
272 int m_imm8(WORD inst, WORD siz)
285 int m_shr(WORD inst, WORD siz)
287 inst |= reg_9[a0reg] | a1reg | siz_6[siz];
297 int m_shi(WORD inst, WORD siz)
299 inst |= a1reg | siz_6[siz];
301 if (a0exattr & DEFINED)
304 return error(range_error);
306 inst |= (a0exval & 7) << 9;
311 AddFixup(FU_QUICK, sloc, a0expr);
320 // {bset, btst, bchg, bclr} -- #immed,ea -- Dn,ea
322 int m_bitop(WORD inst, WORD siz)
324 // Enforce instruction sizes
326 { // X,Dn must be .n or .l
327 if (siz & (SIZB | SIZW))
328 return error(siz_error);
330 else if (siz & (SIZW | SIZL)) // X,ea must be .n or .b
331 return error(siz_error);
333 // Construct instr and EAs
339 ea0gen(SIZB); // Immediate bit number
343 inst |= reg_9[a0reg];
354 int m_dbra(WORD inst, WORD siz)
362 if (a1exattr & DEFINED)
364 if ((a1exattr & TDB) != cursect)
365 return error(rel_error);
369 if (v + 0x8000 > 0x10000)
370 return error(range_error);
376 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
387 int m_exg(WORD inst, WORD siz)
393 if (am0 == DREG && am1 == DREG)
395 else if (am0 == AREG && am1 == AREG)
401 m = a1reg; // Get AREG into a1reg
409 inst |= m | reg_9[a0reg] | a1reg;
419 int m_link(WORD inst, WORD siz)
431 // Handle MOVE <C_ALL> <C_ALTDATA>
432 // MOVE <C_ALL> <M_AREG>
434 // Optimize MOVE.L #<smalldata>,D0 to a MOVEQ
436 //int m_move(WORD inst, int siz)
437 int m_move(WORD inst, WORD size)
439 // Cast the passed in value to an int
442 // Try to optimize to MOVEQ
443 if (optim_flag && siz == SIZL && am0 == IMMED && am1 == DREG
444 && (a0exattr & (TDB|DEFINED)) == DEFINED && a0exval + 0x80 < 0x100)
446 m_moveq((WORD)0x7000, (WORD)0);
448 warn("move.l #size,dx converted to moveq");
452 inst |= siz_12[siz] | am_6[am1] | reg_9[a1reg] | am0 | a0reg;
468 // move USP,An -- move An,USP
470 int m_usp(WORD inst, WORD siz)
475 inst |= a1reg; // USP, An
477 inst |= a0reg; // An, USP
488 int m_moveq(WORD inst, WORD siz)
492 // Arrange for future fixup
493 if (!(a0exattr & DEFINED))
495 AddFixup(FU_BYTE | FU_SEXT, sloc + 1, a0expr);
498 else if (a0exval + 0x100 >= 0x200)
499 return error(range_error);
501 inst |= reg_9[a1reg] | (a0exval & 0xFF);
509 // movep Dn, disp(An) -- movep disp(An), Dn
511 int m_movep(WORD inst, WORD siz)
518 inst |= reg_9[a0reg] | a1reg;
528 inst |= reg_9[a1reg] | a0reg;
544 int m_br(WORD inst, WORD siz)
548 if (a0exattr & DEFINED)
550 if ((a0exattr & TDB) != cursect)
552 //printf("m_br(): a0exattr = %X, cursect = %X, a0exval = %X, sloc = %X\n", a0exattr, cursect, a0exval, sloc);
553 return error(rel_error);
556 v = a0exval - (sloc + 2);
558 // Optimize branch instr. size
561 if (optim_flag && v != 0 && v + 0x80 < 0x100)
567 warn("Bcc.w/BSR.w converted to .s");
573 if (v + 0x8000 > 0x10000)
574 return error(range_error);
584 if (v + 0x80 >= 0x100)
585 return error(range_error);
592 if (v + 0x8000 >= 0x10000)
593 return error(range_error);
601 else if (siz == SIZN)
607 AddFixup(FU_BBRA | FU_PCREL | FU_SEXT, sloc, a0expr);
615 AddFixup(FU_WORD | FU_PCREL | FU_LBRA | FU_ISBRA, sloc, a0expr);
626 int m_addq(WORD inst, WORD siz)
628 inst |= siz_6[siz] | am1 | a1reg;
630 if (a0exattr & DEFINED)
632 if (a0exval > 8 || a0exval == 0) // Range in 1..8
633 return error(range_error);
635 inst |= (a0exval & 7) << 9;
640 AddFixup(FU_QUICK, sloc, a0expr);
653 int m_trap(WORD inst, WORD siz)
657 if (a0exattr & DEFINED)
660 return error(abs_error);
663 return error(range_error);
669 return error(undef_error);
676 // movem <rlist>,ea -- movem ea,<rlist>
678 int m_movem(WORD inst, WORD siz)
686 return error("bad size suffix");
693 // Handle #<expr>, ea
696 if (abs_expr(&eval) != OK)
699 if (eval >= 0x10000L)
700 return error(range_error);
706 if (*tok >= KW_D0 && *tok <= KW_A7)
709 if (reglist(&rmask) < 0)
714 return error("missing comma");
721 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
722 return error("invalid addressing mode");
724 // If APREDEC, reverse register mask
730 for(i=0x8000; i; i>>=1, w>>=1)
731 rmask = (WORD)((rmask << 1) | w & 1);
740 inst |= 0x0400 | am0 | a0reg;
743 return error("missing comma");
746 return error("missing register list");
753 if (abs_expr(&eval) != OK)
757 return error(range_error);
761 else if (reglist(&rmask) < 0)
764 if (!(amsktab[am0] & (C_CTRL | M_APOSTINC)))
765 return error("invalid addressing mode");
777 // CLR.x An ==> SUBA.x An,An
779 int m_clra(WORD inst, WORD siz)
781 inst |= a0reg | reg_9[a0reg] | lwsiz_8[siz];