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
20 // Common error messages
21 char range_error[] = "expression out of range";
22 char abs_error[] = "illegal absolute expression";
23 char seg_error[] = "bad (section) expression";
24 char rel_error[] = "illegal relative address";
25 char siz_error[] = "bad size specified";
26 char undef_error[] = "undefined expression";
27 char fwd_error[] = "forward or undefined expression";
29 extern int ea0gen(WORD);
30 extern int ea1gen(WORD);
32 // Include code tables
34 { (WORD)-1, (unsigned long)-1L, (unsigned long)-1L, 0x0000, 0, m_badmode }, // 0
36 { 0, 0L, 0L, 0x0000, 0, m_unimp } // Last entry
39 // Register number << 9
42 4<<9, 5<<9, 6<<9, 7<<9
45 // SIZB==>00, SIZW==>01, SIZL==>10, SIZN==>01 << 6
49 1<<6, (WORD)-1, // SIZW, n/a
50 2<<6, (WORD)-1, (WORD)-1, (WORD)-1, // SIZL, n/a, n/a, n/a
54 // Byte/word/long size for MOVE instrs
58 0x3000, (WORD)-1, // Word
59 0x2000, (WORD)-1, (WORD)-1, (WORD)-1, // Long
63 // Word/long size (0=.w, 1=.l) in bit 8
67 0, (WORD)-1, // SIZW, n/a
68 1<<8, (WORD)-1, (WORD)-1, (WORD)-1, // SIZL, n/a, n/a, n/a
72 // Addressing mode in bits 6..11 (register/mode fields are reversed)
74 00000, 01000, 02000, 03000, 04000, 05000, 06000, 07000,
75 00100, 01100, 02100, 03100, 04100, 05100, 06100, 07100,
76 00200, 01200, 02200, 03200, 04200, 05200, 06200, 07200,
77 00300, 01300, 02300, 03300, 04300, 05300, 06300, 07300,
78 00400, 01400, 02400, 03400, 04400, 05400, 06400, 07400,
79 00500, 01500, 02500, 03500, 04500, 05500, 06500, 07500,
80 00600, 01600, 02600, 03600, 04600, 05600, 06600, 07600,
81 00700, 01700, 02700, 03700, 04700, 05700, 06700, 07700
88 return (int)error("unimplemented mnemonic");
94 return (int)error("inappropriate addressing mode");
106 // Do one EA in bits 0..5
108 // Bits in `inst' have the following meaning:
110 // Bit zero specifies which ea (ea0 or ea1) to generate in the lower six bits
113 // If bit one is set, the OTHER ea (the one that wasn't generated by bit zero)
114 // is generated after the instruction. Regardless of bit 0's value, ea0 is
115 // always deposited in memory before ea1.
117 // If bit two is set, standard size bits are set in the instr in bits 6 and 7.
119 // If bit four is set, bit three specifies which eaXreg to place in bits 9..11
122 int m_ea(WORD inst, WORD siz)
126 flg = inst; // Save flag bits
127 inst &= ~0x3f; // Clobber flag bits in instr
129 if (flg & 4) // Install "standard" instr size bits
133 { // OR-in register number
136 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
140 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
146 inst |= am1 | a1reg; // Get ea1 into instr
147 D_word(inst); // Deposit instr
149 if (flg & 2) // Generate ea0 if requested
152 ea1gen(siz); // Generate ea1
156 inst |= am0 | a0reg; // Get ea0 into instr
157 D_word(inst); // Deposit instr
158 ea0gen(siz); // Generate ea0
160 if (flg & 2) // Generate ea1 if requested
169 // Dx,Dy nnnnXXXnssnnnYYY If bit 0 of `inst' is set, install size bits in bits
172 int m_abcd(WORD inst, WORD siz)
175 { // Install size bits
180 inst |= a0reg | reg_9[a1reg];
190 int m_adda(WORD inst, WORD siz)
192 inst |= am0 | a0reg | lwsiz_8[siz] | reg_9[a1reg];
194 ea0gen(siz); // Gen EA
201 // If bit 0 of `inst' is 1, install size bits in bits 6..7 of instr.
202 // If bit 1 of `inst' is 1, install a1reg in bits 9..11 of instr.
204 int m_reg(WORD inst, WORD siz)
206 if (inst & 1) // Install size bits
209 if (inst & 2) // Install other register (9..11)
210 inst |= reg_9[a1reg];
212 inst &= ~7; // Clear off crufty bits
213 inst |= a0reg; // Install first register
223 int m_imm(WORD inst, WORD siz)
235 int m_imm8(WORD inst, WORD siz)
248 int m_shr(WORD inst, WORD siz)
250 inst |= reg_9[a0reg] | a1reg | siz_6[siz];
260 int m_shi(WORD inst, WORD siz)
262 inst |= a1reg | siz_6[siz];
264 if (a0exattr & DEFINED)
267 return error(range_error);
269 inst |= (a0exval & 7) << 9;
274 fixup(FU_QUICK, sloc, a0expr);
283 // {bset, btst, bchg, bclr} -- #immed,ea -- Dn,ea
285 int m_bitop(WORD inst, WORD siz)
287 // Enforce instruction sizes
289 { // X,Dn must be .n or .l
290 if (siz & (SIZB|SIZW))
291 return error(siz_error);
293 else if (siz & (SIZW|SIZL)) // X,ea must be .n or .b
294 return error(siz_error);
296 // Construct instr and EAs
302 ea0gen(SIZB); // Immediate bit number
306 inst |= reg_9[a0reg];
310 ea1gen(SIZB); // ea to bit-munch
316 int m_dbra(WORD inst, WORD siz)
324 if (a1exattr & DEFINED)
326 if ((a1exattr & TDB) != cursect)
327 return error(rel_error);
331 if (v + 0x8000 > 0x10000)
332 return error(range_error);
338 fixup(FU_WORD|FU_PCREL|FU_ISBRA, sloc, a1expr);
349 int m_exg(WORD inst, WORD siz)
355 if (am0 == DREG && am1 == DREG)
357 else if (am0 == AREG && am1 == AREG)
363 m = a1reg; // Get AREG into a1reg
371 inst |= m | reg_9[a0reg] | a1reg;
381 int m_link(WORD inst, WORD siz)
393 // Handle MOVE <C_ALL> <C_ALTDATA>
394 // MOVE <C_ALL> <M_AREG>
396 // Optimize MOVE.L #<smalldata>,D0 to a MOVEQ
398 int m_move(WORD inst, int siz)
400 // Try to optimize to MOVEQ
401 if (siz == SIZL && am0 == IMMED && am1 == DREG
402 && (a0exattr & (TDB|DEFINED)) == DEFINED && a0exval + 0x80 < 0x100)
404 m_moveq((WORD)0x7000, (WORD)0);
408 inst |= siz_12[siz] | am_6[am1] | reg_9[a1reg] | am0 | a0reg;
424 // move USP,An -- move An,USP
426 int m_usp(WORD inst, WORD siz)
431 inst |= a1reg; // USP,An
433 inst |= a0reg; // An,USP
444 int m_moveq(WORD inst, WORD siz)
448 // Arrange for future fixup
449 if (!(a0exattr & DEFINED))
451 fixup(FU_BYTE | FU_SEXT, sloc + 1, a0expr);
454 else if (a0exval + 0x100 >= 0x200)
455 return error(range_error);
457 inst |= reg_9[a1reg] | (a0exval & 0xff);
465 // movep Dn,disp(An) -- movep disp(An),Dn
467 int m_movep(WORD inst, WORD siz)
476 inst |= reg_9[a0reg] | a1reg;
488 inst |= reg_9[a1reg] | a0reg;
506 int m_br(WORD inst, WORD siz)
510 if (a0exattr & DEFINED)
512 if ((a0exattr & TDB) != cursect)
513 return error(rel_error);
515 v = a0exval - (sloc + 2);
517 // Optimize branch instr. size
520 if (v != 0 && v + 0x80 < 0x100)
528 if (v + 0x8000 > 0x10000)
529 return error(range_error);
539 if (v + 0x80 >= 0x100)
540 return error(range_error);
547 if (v + 0x8000 >= 0x10000)
548 return error(range_error);
556 else if (siz == SIZN)
561 fixup(FU_BBRA|FU_PCREL|FU_SEXT, sloc, a0expr);
568 fixup(FU_WORD|FU_PCREL|FU_LBRA|FU_ISBRA, sloc, a0expr);
579 int m_addq(WORD inst, WORD siz)
581 inst |= siz_6[siz] | am1 | a1reg;
583 if (a0exattr & DEFINED)
585 if (a0exval > 8 || a0exval == 0) // Range in 1..8
586 return error(range_error);
588 inst |= (a0exval & 7) << 9;
593 fixup(FU_QUICK, sloc, a0expr);
606 int m_trap(WORD inst, WORD siz)
610 if (a0exattr & DEFINED)
613 return error(abs_error);
616 return error(range_error);
622 return error(undef_error);
629 // movem <rlist>,ea -- movem ea,<rlist>
631 int m_movem(WORD inst, WORD siz)
639 return error("bad size suffix");
645 { // Handle #<expr>,ea
648 if (abs_expr(&eval) != OK)
651 if (eval >= 0x10000L)
652 return error(range_error);
658 if (*tok >= KW_D0 && *tok <= KW_A7)
660 if (reglist(&rmask) < 0)
665 return error("missing comma");
672 if (!(amsktab[am0] & (C_ALTCTRL|M_APREDEC)))
673 return error("invalid addressing mode");
675 // If APREDEC, reverse register mask
681 for(i=0x8000; i; i>>=1, w>>=1)
682 rmask = (WORD)((rmask << 1) | w & 1);
690 inst |= 0x0400 | am0 | a0reg;
693 return error("missing comma");
696 return error("missing register list");
702 if (abs_expr(&eval) != OK)
706 return error(range_error);
710 else if (reglist(&rmask) < 0)
713 if (!(amsktab[am0] & (C_CTRL|M_APOSTINC)))
714 return error("invalid addressing mode");
726 // CLR.x An ==> SUBA.x An,An
728 int m_clra(WORD inst, WORD siz)
730 inst |= a0reg | reg_9[a0reg] | lwsiz_8[siz];