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
19 // Common error messages
20 char *range_error = "expression out of range";
21 char *abs_error = "illegal absolute expression";
22 char *seg_error = "bad (section) expression";
23 char *rel_error = "illegal relative address";
24 char *siz_error = "bad size specified";
25 char *undef_error = "undefined expression";
26 char *fwd_error = "forward or undefined expression";
28 extern int ea0gen(WORD);
29 extern int ea1gen(WORD);
31 // Include code tables
33 { (WORD)-1, (unsigned long)-1L, (unsigned long)-1L, 0x0000, 0, m_badmode }, // 0
35 { 0, 0L, 0L, 0x0000, 0, m_unimp } // Last entry
38 // Register number << 9
41 4<<9, 5<<9, 6<<9, 7<<9
44 // SIZB==>00, SIZW==>01, SIZL==>10, SIZN==>01 << 6
48 1<<6, (WORD)-1, // SIZW, n/a
49 2<<6, (WORD)-1, (WORD)-1, (WORD)-1, // SIZL, n/a, n/a, n/a
53 // Byte/word/long size for MOVE instrs
57 0x3000, (WORD)-1, // Word
58 0x2000, (WORD)-1, (WORD)-1, (WORD)-1, // Long
62 // Word/long size (0=.w, 1=.l) in bit 8
66 0, (WORD)-1, // SIZW, n/a
67 1<<8, (WORD)-1, (WORD)-1, (WORD)-1, // SIZL, n/a, n/a, n/a
71 // Addressing mode in bits 6..11 (register/mode fields are reversed)
73 00000, 01000, 02000, 03000, 04000, 05000, 06000, 07000,
74 00100, 01100, 02100, 03100, 04100, 05100, 06100, 07100,
75 00200, 01200, 02200, 03200, 04200, 05200, 06200, 07200,
76 00300, 01300, 02300, 03300, 04300, 05300, 06300, 07300,
77 00400, 01400, 02400, 03400, 04400, 05400, 06400, 07400,
78 00500, 01500, 02500, 03500, 04500, 05500, 06500, 07500,
79 00600, 01600, 02600, 03600, 04600, 05600, 06600, 07600,
80 00700, 01700, 02700, 03700, 04700, 05700, 06700, 07700
84 int m_unimp(void) { return((int)error("unimplemented mnemonic")); }
85 int m_badmode(void) { return((int)error("inappropriate addressing mode")); }
87 int m_self(WORD inst) { D_word(inst); return(0);}
90 // -------------------------------------------------------------------------------------------------
91 // Do one EA in bits 0..5
93 // Bits in `inst' have the following meaning:
95 // Bit zero specifies which ea (ea0 or ea1) to generate in the lower six bits of the instr.
97 // If bit one is set, the OTHER ea (the one that wasn't generated by bit zero) is generated after
98 // the instruction. Regardless of bit 0's value, ea0 is always deposited in memory before ea1.
100 // If bit two is set, standard size bits are set in the instr in bits 6 and 7.
102 // If bit four is set, bit three specifies which eaXreg to place in bits 9..11 of the instr.
103 // -------------------------------------------------------------------------------------------------
106 int m_ea(WORD inst, WORD siz) {
109 flg = inst; // Save flag bits
110 inst &= ~0x3f; // Clobber flag bits in instr
112 if(flg & 4) // Install "standard" instr size bits
115 if(flg & 16) { // OR-in register number
117 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
119 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
123 if(flg & 1) { // Use am1
124 inst |= am1 | a1reg; // Get ea1 into instr
125 D_word(inst); // Deposit instr
126 if(flg & 2) // Generate ea0 if requested
128 ea1gen(siz); // Generate ea1
130 inst |= am0 | a0reg; // Get ea0 into instr
131 D_word(inst); // Deposit instr
132 ea0gen(siz); // Generate ea0
133 if(flg & 2) // Generate ea1 if requested
141 // --- Dx,Dy nnnnXXXnssnnnYYY If bit 0 of `inst' is set, install size bits in bits 6..7 ------------
144 int m_abcd(WORD inst, WORD siz) {
145 if(inst & 1) { // Install size bits
150 inst |= a0reg | reg_9[a1reg];
157 // --- {adda} ea,AREG ------------------------------------------------------------------------------
160 int m_adda(WORD inst, WORD siz) {
161 inst |= am0 | a0reg | lwsiz_8[siz] | reg_9[a1reg];
163 ea0gen(siz); // Gen EA
169 // -------------------------------------------------------------------------------------------------
170 // If bit 0 of `inst' is 1, install size bits in bits 6..7 of instr.
171 // If bit 1 of `inst' is 1, install a1reg in bits 9..11 of instr.
172 // -------------------------------------------------------------------------------------------------
175 int m_reg(WORD inst, WORD siz) {
176 if(inst & 1) // Install size bits
178 if(inst & 2) // Install other register (9..11)
179 inst |= reg_9[a1reg];
181 inst &= ~7; // Clear off crufty bits
182 inst |= a0reg; // Install first register
189 // --- <op> #expr ----------------------------------------------------------------------------------
192 int m_imm(WORD inst, WORD siz) {
200 // --- <op>.b #expr --------------------------------------------------------------------------------
203 int m_imm8(WORD inst, WORD siz) {
212 // --- <shift> Dn,Dn -------------------------------------------------------------------------------
215 int m_shr(WORD inst, WORD siz) {
216 inst |= reg_9[a0reg] | a1reg | siz_6[siz];
223 // --- <shift> #n,Dn -------------------------------------------------------------------------------
226 int m_shi(WORD inst, WORD siz) {
227 inst |= a1reg | siz_6[siz];
229 if(a0exattr & DEFINED) {
231 return(error(range_error));
232 inst |= (a0exval & 7) << 9;
235 fixup(FU_QUICK, sloc, a0expr);
243 // --- {bset, btst, bchg, bclr} -- #immed,ea -- Dn,ea ----------------------------------------------
246 int m_bitop(WORD inst, WORD siz) {
247 // Enforce instruction sizes
248 if(am1 == DREG) { // X,Dn must be .n or .l
249 if(siz & (SIZB|SIZW))
250 return(error(siz_error));
252 if(siz & (SIZW|SIZL)) // X,ea must be .n or .b
253 return error(siz_error);
255 // Construct instr and EAs
259 ea0gen(SIZB); // Immediate bit number
261 inst |= reg_9[a0reg];
265 ea1gen(SIZB); // ea to bit-munch
270 int m_dbra(WORD inst, WORD siz) {
276 if(a1exattr & DEFINED) {
277 if((a1exattr & TDB) != cursect)
278 return(error(rel_error));
281 if(v + 0x8000 > 0x10000)
282 return(error(range_error));
285 fixup(FU_WORD|FU_PCREL|FU_ISBRA, sloc, a1expr);
293 // --- EXG -----------------------------------------------------------------------------------------
296 int m_exg(WORD inst, WORD siz) {
300 if(am0 == DREG && am1 == DREG)
302 else if(am0 == AREG && am1 == AREG)
305 if(am0 == AREG) { // Dn,An or An,Dn
306 m = a1reg; // Get AREG into a1reg
312 inst |= m | reg_9[a0reg] | a1reg;
319 // --- LINK ----------------------------------------------------------------------------------------
322 int m_link(WORD inst, WORD siz) {
332 // -------------------------------------------------------------------------------------------------
333 // Handle MOVE <C_ALL> <C_ALTDATA>
334 // MOVE <C_ALL> <M_AREG>
336 // Optimize MOVE.L #<smalldata>,D0 to a MOVEQ
337 // -------------------------------------------------------------------------------------------------
340 int m_move(WORD inst, int siz) {
341 // Try to optimize to MOVEQ
342 if(siz == SIZL && am0 == IMMED && am1 == DREG && (a0exattr & (TDB|DEFINED)) == DEFINED &&
343 a0exval + 0x80 < 0x100) {
344 m_moveq((WORD)0x7000, (WORD)0);
346 inst |= siz_12[siz] | am_6[am1] | reg_9[a1reg] | am0 | a0reg;
349 if(am0 >= ADISP) ea0gen((WORD)siz);
350 if(am1 >= ADISP) ea1gen((WORD)siz);
357 // --- move USP,An -- move An,USP ------------------------------------------------------------------
360 int m_usp(WORD inst, WORD siz) {
362 if(am0 == AM_USP) inst |= a1reg; // USP,An
363 else inst |= a0reg; // An,USP
370 // --- moveq ---------------------------------------------------------------------------------------
373 int m_moveq(WORD inst, WORD siz) {
375 if(!(a0exattr & DEFINED)) { // Arrange for future fixup
376 fixup(FU_BYTE|FU_SEXT, sloc+1, a0expr);
379 if(a0exval + 0x100 >= 0x200)
380 return(error(range_error));
382 inst |= reg_9[a1reg] | (a0exval & 0xff);
389 // --- movep Dn,disp(An) -- movep disp(An),Dn ------------------------------------------------------
392 int m_movep(WORD inst, WORD siz) {
399 inst |= reg_9[a0reg] | a1reg;
406 inst |= reg_9[a1reg] | a0reg;
418 // --- Bcc -- BSR ----------------------------------------------------------------------------------
421 int m_br(WORD inst, WORD siz) {
424 if(a0exattr & DEFINED) {
425 if((a0exattr & TDB) != cursect)
426 return(error(rel_error));
428 v = a0exval - (sloc + 2);
430 // Optimize branch instr. size
432 if(v != 0 && v + 0x80 < 0x100) { // Fits in .B
436 } else { // Fits in .W
437 if(v + 0x8000 > 0x10000)
438 return(error(range_error));
446 if(v + 0x80 >= 0x100)
447 return(error(range_error));
451 if(v + 0x8000 >= 0x10000)
452 return(error(range_error));
461 if(siz == SIZB) { // .B
462 fixup(FU_BBRA|FU_PCREL|FU_SEXT, sloc, a0expr);
467 fixup(FU_WORD|FU_PCREL|FU_LBRA|FU_ISBRA, sloc, a0expr);
475 // --- ADDQ -- SUBQ --------------------------------------------------------------------------------
478 int m_addq(WORD inst, WORD siz) {
479 inst |= siz_6[siz] | am1 | a1reg;
481 if(a0exattr & DEFINED) {
482 if(a0exval > 8 || a0exval == 0) // Range in 1..8
483 return(error(range_error));
484 inst |= (a0exval & 7) << 9;
487 fixup(FU_QUICK, sloc, a0expr);
496 // --- trap #n -------------------------------------------------------------------------------------
499 int m_trap(WORD inst, WORD siz) {
501 if(a0exattr & DEFINED) {
503 return(error(abs_error));
505 return(error(range_error));
509 return(error(undef_error));
515 // --- movem <rlist>,ea -- movem ea,<rlist> --------------------------------------------------------
518 int m_movem(WORD inst, WORD siz) {
524 if(siz & SIZB) return(error("bad size suffix"));
526 if(siz == SIZL) inst |= 0x0040;
528 if(*tok == '#') { // Handle #<expr>,ea
530 if(abs_expr(&eval) != OK) return(0);
531 if(eval >= 0x10000L) return(error(range_error));
536 if(*tok >= KW_D0 && *tok <= KW_A7) { // <rlist>,ea
537 if(reglist(&rmask) < 0) return(0);
541 if(*tok++ != ',') return(error("missing comma"));
542 if(amode(0) < 0) return(0);
545 if(!(amsktab[am0] & (C_ALTCTRL|M_APREDEC)))
546 return(error("invalid addressing mode"));
548 // If APREDEC, reverse register mask
552 for(i = 0x8000; i; i >>= 1, w >>= 1)
553 rmask = (WORD)((rmask << 1) | w & 1);
555 } else { // ea,<rlist>
556 if(amode(0) < 0) return(0);
557 inst |= 0x0400 | am0 | a0reg;
558 if(*tok++ != ',') return(error("missing comma"));
559 if(*tok == EOL) return(error("missing register list"));
561 if(*tok == '#') { // ea,#<expr>
563 if(abs_expr(&eval) != OK) return(0);
564 if(eval >= 0x10000) return(error(range_error));
567 if(reglist(&rmask) < 0) return(0);
569 if(!(amsktab[am0] & (C_CTRL|M_APOSTINC)))
570 return(error("invalid addressing mode"));
581 // --- CLR.x An ==> SUBA.x An,An -------------------------------------------------------------------
584 int m_clra(WORD inst, WORD siz) {
585 inst |= a0reg | reg_9[a0reg] | lwsiz_8[siz];