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
85 int m_unimp(void) { return((int)error("unimplemented mnemonic")); }
86 int m_badmode(void) { return((int)error("inappropriate addressing mode")); }
88 int m_self(WORD inst) { D_word(inst); return(0);}
91 // -------------------------------------------------------------------------------------------------
92 // Do one EA in bits 0..5
94 // Bits in `inst' have the following meaning:
96 // Bit zero specifies which ea (ea0 or ea1) to generate in the lower six bits of the instr.
98 // If bit one is set, the OTHER ea (the one that wasn't generated by bit zero) is generated after
99 // the instruction. Regardless of bit 0's value, ea0 is always deposited in memory before ea1.
101 // If bit two is set, standard size bits are set in the instr in bits 6 and 7.
103 // If bit four is set, bit three specifies which eaXreg to place in bits 9..11 of the instr.
104 // -------------------------------------------------------------------------------------------------
107 int m_ea(WORD inst, WORD siz) {
110 flg = inst; // Save flag bits
111 inst &= ~0x3f; // Clobber flag bits in instr
113 if(flg & 4) // Install "standard" instr size bits
116 if(flg & 16) { // OR-in register number
118 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
120 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
124 if(flg & 1) { // Use am1
125 inst |= am1 | a1reg; // Get ea1 into instr
126 D_word(inst); // Deposit instr
127 if(flg & 2) // Generate ea0 if requested
129 ea1gen(siz); // Generate ea1
131 inst |= am0 | a0reg; // Get ea0 into instr
132 D_word(inst); // Deposit instr
133 ea0gen(siz); // Generate ea0
134 if(flg & 2) // Generate ea1 if requested
142 // --- Dx,Dy nnnnXXXnssnnnYYY If bit 0 of `inst' is set, install size bits in bits 6..7 ------------
145 int m_abcd(WORD inst, WORD siz) {
146 if(inst & 1) { // Install size bits
151 inst |= a0reg | reg_9[a1reg];
158 // --- {adda} ea,AREG ------------------------------------------------------------------------------
161 int m_adda(WORD inst, WORD siz) {
162 inst |= am0 | a0reg | lwsiz_8[siz] | reg_9[a1reg];
164 ea0gen(siz); // Gen EA
170 // -------------------------------------------------------------------------------------------------
171 // If bit 0 of `inst' is 1, install size bits in bits 6..7 of instr.
172 // If bit 1 of `inst' is 1, install a1reg in bits 9..11 of instr.
173 // -------------------------------------------------------------------------------------------------
176 int m_reg(WORD inst, WORD siz) {
177 if(inst & 1) // Install size bits
179 if(inst & 2) // Install other register (9..11)
180 inst |= reg_9[a1reg];
182 inst &= ~7; // Clear off crufty bits
183 inst |= a0reg; // Install first register
190 // --- <op> #expr ----------------------------------------------------------------------------------
193 int m_imm(WORD inst, WORD siz) {
201 // --- <op>.b #expr --------------------------------------------------------------------------------
204 int m_imm8(WORD inst, WORD siz) {
213 // --- <shift> Dn,Dn -------------------------------------------------------------------------------
216 int m_shr(WORD inst, WORD siz) {
217 inst |= reg_9[a0reg] | a1reg | siz_6[siz];
224 // --- <shift> #n,Dn -------------------------------------------------------------------------------
227 int m_shi(WORD inst, WORD siz) {
228 inst |= a1reg | siz_6[siz];
230 if(a0exattr & DEFINED) {
232 return(error(range_error));
233 inst |= (a0exval & 7) << 9;
236 fixup(FU_QUICK, sloc, a0expr);
244 // --- {bset, btst, bchg, bclr} -- #immed,ea -- Dn,ea ----------------------------------------------
247 int m_bitop(WORD inst, WORD siz) {
248 // Enforce instruction sizes
249 if(am1 == DREG) { // X,Dn must be .n or .l
250 if(siz & (SIZB|SIZW))
251 return(error(siz_error));
253 if(siz & (SIZW|SIZL)) // X,ea must be .n or .b
254 return error(siz_error);
256 // Construct instr and EAs
260 ea0gen(SIZB); // Immediate bit number
262 inst |= reg_9[a0reg];
266 ea1gen(SIZB); // ea to bit-munch
271 int m_dbra(WORD inst, WORD siz) {
277 if(a1exattr & DEFINED) {
278 if((a1exattr & TDB) != cursect)
279 return(error(rel_error));
282 if(v + 0x8000 > 0x10000)
283 return(error(range_error));
286 fixup(FU_WORD|FU_PCREL|FU_ISBRA, sloc, a1expr);
294 // --- EXG -----------------------------------------------------------------------------------------
297 int m_exg(WORD inst, WORD siz) {
301 if(am0 == DREG && am1 == DREG)
303 else if(am0 == AREG && am1 == AREG)
306 if(am0 == AREG) { // Dn,An or An,Dn
307 m = a1reg; // Get AREG into a1reg
313 inst |= m | reg_9[a0reg] | a1reg;
320 // --- LINK ----------------------------------------------------------------------------------------
323 int m_link(WORD inst, WORD siz) {
333 // -------------------------------------------------------------------------------------------------
334 // Handle MOVE <C_ALL> <C_ALTDATA>
335 // MOVE <C_ALL> <M_AREG>
337 // Optimize MOVE.L #<smalldata>,D0 to a MOVEQ
338 // -------------------------------------------------------------------------------------------------
341 int m_move(WORD inst, int siz) {
342 // Try to optimize to MOVEQ
343 if(siz == SIZL && am0 == IMMED && am1 == DREG && (a0exattr & (TDB|DEFINED)) == DEFINED &&
344 a0exval + 0x80 < 0x100) {
345 m_moveq((WORD)0x7000, (WORD)0);
347 inst |= siz_12[siz] | am_6[am1] | reg_9[a1reg] | am0 | a0reg;
350 if(am0 >= ADISP) ea0gen((WORD)siz);
351 if(am1 >= ADISP) ea1gen((WORD)siz);
358 // --- move USP,An -- move An,USP ------------------------------------------------------------------
361 int m_usp(WORD inst, WORD siz) {
363 if(am0 == AM_USP) inst |= a1reg; // USP,An
364 else inst |= a0reg; // An,USP
371 // --- moveq ---------------------------------------------------------------------------------------
374 int m_moveq(WORD inst, WORD siz) {
376 if(!(a0exattr & DEFINED)) { // Arrange for future fixup
377 fixup(FU_BYTE|FU_SEXT, sloc+1, a0expr);
380 if(a0exval + 0x100 >= 0x200)
381 return(error(range_error));
383 inst |= reg_9[a1reg] | (a0exval & 0xff);
390 // --- movep Dn,disp(An) -- movep disp(An),Dn ------------------------------------------------------
393 int m_movep(WORD inst, WORD siz) {
400 inst |= reg_9[a0reg] | a1reg;
407 inst |= reg_9[a1reg] | a0reg;
419 // --- Bcc -- BSR ----------------------------------------------------------------------------------
422 int m_br(WORD inst, WORD siz) {
425 if(a0exattr & DEFINED) {
426 if((a0exattr & TDB) != cursect)
427 return(error(rel_error));
429 v = a0exval - (sloc + 2);
431 // Optimize branch instr. size
433 if(v != 0 && v + 0x80 < 0x100) { // Fits in .B
437 } else { // Fits in .W
438 if(v + 0x8000 > 0x10000)
439 return(error(range_error));
447 if(v + 0x80 >= 0x100)
448 return(error(range_error));
452 if(v + 0x8000 >= 0x10000)
453 return(error(range_error));
462 if(siz == SIZB) { // .B
463 fixup(FU_BBRA|FU_PCREL|FU_SEXT, sloc, a0expr);
468 fixup(FU_WORD|FU_PCREL|FU_LBRA|FU_ISBRA, sloc, a0expr);
476 // --- ADDQ -- SUBQ --------------------------------------------------------------------------------
479 int m_addq(WORD inst, WORD siz) {
480 inst |= siz_6[siz] | am1 | a1reg;
482 if(a0exattr & DEFINED) {
483 if(a0exval > 8 || a0exval == 0) // Range in 1..8
484 return(error(range_error));
485 inst |= (a0exval & 7) << 9;
488 fixup(FU_QUICK, sloc, a0expr);
497 // --- trap #n -------------------------------------------------------------------------------------
500 int m_trap(WORD inst, WORD siz) {
502 if(a0exattr & DEFINED) {
504 return(error(abs_error));
506 return(error(range_error));
510 return(error(undef_error));
516 // --- movem <rlist>,ea -- movem ea,<rlist> --------------------------------------------------------
519 int m_movem(WORD inst, WORD siz) {
525 if(siz & SIZB) return(error("bad size suffix"));
527 if(siz == SIZL) inst |= 0x0040;
529 if(*tok == '#') { // Handle #<expr>,ea
531 if(abs_expr(&eval) != OK) return(0);
532 if(eval >= 0x10000L) return(error(range_error));
537 if(*tok >= KW_D0 && *tok <= KW_A7) { // <rlist>,ea
538 if(reglist(&rmask) < 0) return(0);
542 if(*tok++ != ',') return(error("missing comma"));
543 if(amode(0) < 0) return(0);
546 if(!(amsktab[am0] & (C_ALTCTRL|M_APREDEC)))
547 return(error("invalid addressing mode"));
549 // If APREDEC, reverse register mask
553 for(i = 0x8000; i; i >>= 1, w >>= 1)
554 rmask = (WORD)((rmask << 1) | w & 1);
556 } else { // ea,<rlist>
557 if(amode(0) < 0) return(0);
558 inst |= 0x0400 | am0 | a0reg;
559 if(*tok++ != ',') return(error("missing comma"));
560 if(*tok == EOL) return(error("missing register list"));
562 if(*tok == '#') { // ea,#<expr>
564 if(abs_expr(&eval) != OK) return(0);
565 if(eval >= 0x10000) return(error(range_error));
568 if(reglist(&rmask) < 0) return(0);
570 if(!(amsktab[am0] & (C_CTRL|M_APOSTINC)))
571 return(error("invalid addressing mode"));
582 // --- CLR.x An ==> SUBA.x An,An -------------------------------------------------------------------
585 int m_clra(WORD inst, WORD siz) {
586 inst |= a0reg | reg_9[a0reg] | lwsiz_8[siz];