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 if (!(a0exattr & DEFINED))
449 { // Arrange for future fixup
450 fixup(FU_BYTE|FU_SEXT, sloc+1, a0expr);
453 else if (a0exval + 0x100 >= 0x200)
454 return error(range_error);
456 inst |= reg_9[a1reg] | (a0exval & 0xff);
464 // movep Dn,disp(An) -- movep disp(An),Dn
466 int m_movep(WORD inst, WORD siz)
475 inst |= reg_9[a0reg] | a1reg;
487 inst |= reg_9[a1reg] | a0reg;
505 int m_br(WORD inst, WORD siz)
509 if (a0exattr & DEFINED)
511 if ((a0exattr & TDB) != cursect)
512 return error(rel_error);
514 v = a0exval - (sloc + 2);
516 // Optimize branch instr. size
519 if (v != 0 && v + 0x80 < 0x100)
527 if (v + 0x8000 > 0x10000)
528 return error(range_error);
538 if (v + 0x80 >= 0x100)
539 return error(range_error);
546 if (v + 0x8000 >= 0x10000)
547 return error(range_error);
555 else if (siz == SIZN)
560 fixup(FU_BBRA|FU_PCREL|FU_SEXT, sloc, a0expr);
567 fixup(FU_WORD|FU_PCREL|FU_LBRA|FU_ISBRA, sloc, a0expr);
578 int m_addq(WORD inst, WORD siz)
580 inst |= siz_6[siz] | am1 | a1reg;
582 if (a0exattr & DEFINED)
584 if (a0exval > 8 || a0exval == 0) // Range in 1..8
585 return error(range_error);
587 inst |= (a0exval & 7) << 9;
592 fixup(FU_QUICK, sloc, a0expr);
605 int m_trap(WORD inst, WORD siz)
609 if (a0exattr & DEFINED)
612 return error(abs_error);
615 return error(range_error);
621 return error(undef_error);
628 // movem <rlist>,ea -- movem ea,<rlist>
630 int m_movem(WORD inst, WORD siz)
638 return error("bad size suffix");
644 { // Handle #<expr>,ea
647 if (abs_expr(&eval) != OK)
650 if (eval >= 0x10000L)
651 return error(range_error);
657 if (*tok >= KW_D0 && *tok <= KW_A7)
659 if (reglist(&rmask) < 0)
664 return error("missing comma");
671 if (!(amsktab[am0] & (C_ALTCTRL|M_APREDEC)))
672 return error("invalid addressing mode");
674 // If APREDEC, reverse register mask
680 for(i=0x8000; i; i>>=1, w>>=1)
681 rmask = (WORD)((rmask << 1) | w & 1);
689 inst |= 0x0400 | am0 | a0reg;
692 return error("missing comma");
695 return error("missing register list");
701 if (abs_expr(&eval) != OK)
705 return error(range_error);
709 else if (reglist(&rmask) < 0)
712 if (!(amsktab[am0] & (C_CTRL|M_APOSTINC)))
713 return error("invalid addressing mode");
725 // CLR.x An ==> SUBA.x An,An
727 int m_clra(WORD inst, WORD siz)
729 inst |= a0reg | reg_9[a0reg] | lwsiz_8[siz];