2 // RMAC - Reboot's Macro Assembler for all Atari computers
3 // MACH.C - Code Generation
4 // Copyright (C) 199x Landon Dyer, 2011-2018 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
24 int movep = 0; // Global flag to indicate we're generating a movep instruction
26 // Function prototypes
27 int m_unimp(WORD, WORD), m_badmode(WORD, WORD);
28 int m_self(WORD, WORD);
29 int m_abcd(WORD, WORD);
30 int m_reg(WORD, WORD);
31 int m_imm(WORD, WORD);
32 int m_imm8(WORD, WORD);
33 int m_shi(WORD, WORD);
34 int m_shr(WORD, WORD);
35 int m_bitop(WORD, WORD);
36 int m_exg(WORD, WORD);
38 int m_lea(WORD, WORD);
40 int m_dbra(WORD, WORD);
41 int m_link(WORD, WORD);
42 int m_adda(WORD, WORD);
43 int m_addq(WORD, WORD);
44 int m_move(WORD, WORD);
45 int m_moveq(WORD, WORD);
46 int m_usp(WORD, WORD);
47 int m_movep(WORD, WORD);
48 int m_trap(WORD, WORD);
49 int m_movem(WORD, WORD);
50 int m_clra(WORD, WORD);
51 int m_clrd(WORD, WORD);
53 int m_move30(WORD, WORD); // 68020/30/40/60
54 int m_br30(WORD inst, WORD siz);
55 int m_ea030(WORD inst, WORD siz);
56 int m_bfop(WORD inst, WORD siz);
57 int m_callm(WORD inst, WORD siz);
58 int m_cas(WORD inst, WORD siz);
59 int m_cas2(WORD inst, WORD siz);
60 int m_chk2(WORD inst, WORD siz);
61 int m_cmp2(WORD inst, WORD siz);
62 int m_bkpt(WORD inst, WORD siz);
63 int m_cpbr(WORD inst, WORD siz);
64 int m_cpdbr(WORD inst, WORD siz);
65 int m_muls(WORD inst, WORD siz);
66 int m_move16a(WORD inst, WORD siz);
67 int m_move16b(WORD inst, WORD siz);
68 int m_pack(WORD inst, WORD siz);
69 int m_rtm(WORD inst, WORD siz);
70 int m_rtd(WORD inst, WORD siz);
71 int m_trapcc(WORD inst, WORD siz);
72 int m_cinv(WORD inst, WORD siz);
73 int m_cprest(WORD inst, WORD siz);
74 int m_movec(WORD inst, WORD siz);
75 int m_moves(WORD inst, WORD siz);
76 int m_lpstop(WORD inst, WORD siz);
77 int m_plpa(WORD inst, WORD siz);
80 int m_pbcc(WORD inst, WORD siz);
81 int m_pflusha(WORD inst, WORD siz);
82 int m_pflush(WORD inst, WORD siz);
83 int m_pflushr(WORD inst, WORD siz);
84 int m_pflushan(WORD inst, WORD siz);
85 int m_pload(WORD inst, WORD siz, WORD extension);
86 int m_pmove(WORD inst, WORD siz);
87 int m_pmovefd(WORD inst, WORD siz);
88 int m_ptest(WORD inst, WORD siz);
89 int m_ptrapcc(WORD inst, WORD siz);
90 int m_ploadr(WORD inst, WORD siz);
91 int m_ploadw(WORD inst, WORD siz);
94 int m_fabs(WORD inst, WORD siz);
95 int m_facos(WORD inst, WORD siz);
96 int m_fadd(WORD inst, WORD siz);
97 int m_fasin(WORD inst, WORD siz);
98 int m_fatan(WORD inst, WORD siz);
99 int m_fatanh(WORD inst, WORD siz);
100 int m_fcmp(WORD inst, WORD siz);
101 int m_fcos(WORD inst, WORD siz);
102 int m_fcosh(WORD inst, WORD siz);
103 int m_fdabs(WORD inst, WORD siz);
104 int m_fdadd(WORD inst, WORD siz);
105 int m_fdbcc(WORD inst, WORD siz);
106 int m_fddiv(WORD inst, WORD siz);
107 int m_fdfsqrt(WORD inst, WORD siz);
108 int m_fdiv(WORD inst, WORD siz);
109 int m_fdmove(WORD inst, WORD siz);
110 int m_fdmul(WORD inst, WORD siz);
111 int m_fdneg(WORD inst, WORD siz);
112 int m_fdsub(WORD inst, WORD siz);
113 int m_fetox(WORD inst, WORD siz);
114 int m_fetoxm1(WORD inst, WORD siz);
115 int m_fgetexp(WORD inst, WORD siz);
116 int m_fgetman(WORD inst, WORD siz);
117 int m_fint(WORD inst, WORD siz);
118 int m_fintrz(WORD inst, WORD siz);
119 int m_flog10(WORD inst, WORD siz);
120 int m_flog2(WORD inst, WORD siz);
121 int m_flogn(WORD inst, WORD siz);
122 int m_flognp1(WORD inst, WORD siz);
123 int m_fmod(WORD inst, WORD siz);
124 int m_fmove(WORD inst, WORD siz);
125 int m_fmovescr(WORD inst, WORD siz);
126 int m_fmovecr(WORD inst, WORD siz);
127 int m_fmovem(WORD inst, WORD siz);
128 int m_fmul(WORD inst, WORD siz);
129 int m_fneg(WORD inst, WORD siz);
130 int m_fnop(WORD inst, WORD siz);
131 int m_frem(WORD inst, WORD siz);
132 int m_frestore(WORD inst, WORD siz);
133 int m_fsabs(WORD inst, WORD siz);
134 int m_fsadd(WORD inst, WORD siz);
135 int m_fscc(WORD inst, WORD siz);
136 int m_fscale(WORD inst, WORD siz);
137 int m_fsdiv(WORD inst, WORD siz);
138 int m_fsfsqrt(WORD inst, WORD siz);
139 int m_fsfsub(WORD inst, WORD siz);
140 int m_fsgldiv(WORD inst, WORD siz);
141 int m_fsglmul(WORD inst, WORD siz);
142 int m_fsin(WORD inst, WORD siz);
143 int m_fsincos(WORD inst, WORD siz);
144 int m_fsinh(WORD inst, WORD siz);
145 int m_fsmove(WORD inst, WORD siz);
146 int m_fsmul(WORD inst, WORD siz);
147 int m_fsneg(WORD inst, WORD siz);
148 int m_fsqrt(WORD inst, WORD siz);
149 int m_fsub(WORD inst, WORD siz);
150 int m_ftan(WORD inst, WORD siz);
151 int m_ftanh(WORD inst, WORD siz);
152 int m_ftentox(WORD inst, WORD siz);
153 int m_ftst(WORD inst, WORD siz);
154 int m_ftwotox(WORD inst, WORD siz);
155 int m_ftrapcc(WORD inst, WORD siz);
157 // Common error messages
158 char range_error[] = "expression out of range";
159 char abs_error[] = "illegal absolute expression";
160 char seg_error[] = "bad (section) expression";
161 char rel_error[] = "illegal relative address";
162 char siz_error[] = "bad size specified";
163 char undef_error[] = "undefined expression";
164 char fwd_error[] = "forward or undefined expression";
165 char unsupport[] = "unsupported for selected CPU";
167 // Include code tables
169 { 0xFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000, 0, m_badmode }, // 0
171 { 0, 0L, 0L, 0x0000, 0, m_unimp } // Last entry
174 // Register number << 9
176 0, 1 << 9, 2 << 9, 3 << 9, 4 << 9, 5 << 9, 6 << 9, 7 << 9
179 // SIZB==>00, SIZW==>01, SIZL==>10, SIZN==>01 << 6
183 1<<6, (WORD)-1, // SIZW, n/a
184 2<<6, (WORD)-1, (WORD)-1, (WORD)-1, // SIZL, n/a, n/a, n/a
188 // Byte/word/long size for MOVE instrs
192 0x3000, (WORD)-1, // Word
193 0x2000, (WORD)-1, (WORD)-1, (WORD)-1, // Long
194 0x3000 // Word (SIZN)
197 // Word/long size (0=.w, 1=.l) in bit 8
201 0, (WORD)-1, // SIZW, n/a
202 1<<8, (WORD)-1, (WORD)-1, (WORD)-1, // SIZL, n/a, n/a, n/a
206 // Byte/Word/long size (0=.w, 1=.l) in bit 9
210 1<<9, (WORD)-1, // Word
211 1<<10, (WORD)-1, (WORD)-1, (WORD)-1, // Long
215 // Addressing mode in bits 6..11 (register/mode fields are reversed)
217 00000, 01000, 02000, 03000, 04000, 05000, 06000, 07000,
218 00100, 01100, 02100, 03100, 04100, 05100, 06100, 07100,
219 00200, 01200, 02200, 03200, 04200, 05200, 06200, 07200,
220 00300, 01300, 02300, 03300, 04300, 05300, 06300, 07300,
221 00400, 01400, 02400, 03400, 04400, 05400, 06400, 07400,
222 00500, 01500, 02500, 03500, 04500, 05500, 06500, 07500,
223 00600, 01600, 02600, 03600, 04600, 05600, 06600, 07600,
224 00700, 01700, 02700, 03700, 04700, 05700, 06700, 07700
227 // Control registers lookup table
229 // MC68010/MC68020/MC68030/MC68040/CPU32
230 0x000, // Source Function Code(SFC)
231 0x001, // Destination Function Code(DFC)
232 0x800, // User Stack Pointer(USP)
233 0x801, // Vector Base Register(VBR)
234 // MC68020 / MC68030 / MC68040
235 0x002, // Cache Control Register(CACR)
236 0x802, // Cache Address Register(CAAR) (020/030 only)
237 0x803, // Master Stack Pointer(MSP)
238 0x804, // Interrupt Stack Pointer(ISP)
239 // MC68040 / MC68LC040
240 0x003, // MMU Translation Control Register(TC)
241 0x004, // Instruction Transparent Translation Register 0 (ITT0)
242 0x005, // Instruction Transparent Translation Register 1 (ITT1)
243 0x006, // Data Transparent Translation Register 0 (DTT0)
244 0x007, // Data Transparent Translation Register 1 (DTT1)
245 0x805, // MMU Status Register(MMUSR)
246 0x806, // User Root Pointer(URP)
247 0x807, // Supervisor Root Pointer(SRP)
249 0x004, // Instruction Access Control Register 0 (IACR0)
250 0x005, // Instruction Access Control Register 1 (IACR1)
251 0x006, // Data Access Control Register 0 (DACR1)
252 0x007, // Data Access Control Register 1 (DACR1)
254 0xFFF // CPU Root Pointer (CRP) - There's no movec with CRP in it, this is just a guard entry
259 int m_unimp(WORD unused1, WORD unused2)
261 return (int)error("unimplemented mnemonic");
265 //int m_badmode(void)
266 int m_badmode(WORD unused1, WORD unused2)
268 return (int)error("inappropriate addressing mode");
272 int m_self(WORD inst, WORD usused)
280 // Do one EA in bits 0..5
282 // Bits in `inst' have the following meaning:
284 // Bit zero specifies which ea (ea0 or ea1) to generate in the lower six bits
287 // If bit one is set, the OTHER ea (the one that wasn't generated by bit zero)
288 // is generated after the instruction. Regardless of bit 0's value, ea0 is
289 // always deposited in memory before ea1.
291 // If bit two is set, standard size bits are set in the instr in bits 6 and 7.
293 // If bit four is set, bit three specifies which eaXreg to place in bits 9..11
296 int m_ea(WORD inst, WORD siz)
298 WORD flg = inst; // Save flag bits
299 inst &= ~0x3F; // Clobber flag bits in instr
301 // Install "standard" instr size bits
307 // OR-in register number
309 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
311 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
317 inst |= am1 | a1reg; // Get ea1 into instr
318 D_word(inst); // Deposit instr
320 // Generate ea0 if requested
324 ea1gen(siz); // Generate ea1
329 inst |= am0 | a0reg; // Get ea0 into instr
330 D_word(inst); // Deposit instr
331 ea0gen(siz); // Generate ea0
333 // Generate ea1 if requested
343 // Check if lea x(an),an can be optimised to addq.w #x,an--otherwise fall back
346 int m_lea(WORD inst, WORD siz)
348 if (CHECK_OPTS(OPT_LEA_ADDQ)
349 && ((am0 == ADISP) && (a0reg == a1reg) && (a0exattr & DEFINED))
350 && ((a0exval > 0) && (a0exval <= 8)))
352 inst = B16(01010000, 01001000) | (((uint16_t)a0exval & 7) << 9) | (a0reg);
354 warn("lea size(An),An converted to addq #size,An");
358 return m_ea(inst, siz);
362 int m_ea030(WORD inst, WORD siz)
365 WORD flg = inst; // Save flag bits
366 inst &= ~0x3F; // Clobber flag bits in instr
368 // Install "standard" instr size bits
374 // OR-in register number
377 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
381 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
388 inst |= am1 | a1reg; // Get ea1 into instr
389 D_word(inst); // Deposit instr
391 // Generate ea0 if requested
395 ea1gen(siz); // Generate ea1
401 // We get here if we're doing 020+ addressing and an address
402 // register is used. For example, something like "tst a0". A bit of
403 // a corner case, so kludge it
405 else if (am0 == PCDISP)
406 // Another corner case (possibly!), so kludge ahoy
407 inst |= am0; // Get ea0 into instr
408 else if (am0 == IMMED && am1 == MEMPOST)
410 // Added for addi/andi/cmpi/eori/ori/subi #xx,(bd,An,Dm)
411 inst |= a1reg | AINDEXED;
413 else if (am0 == IMMED)
414 inst |= am0 | a0reg; // Get ea0 into instr
415 else if (am0 == AM_CCR)
417 else if (am0 == AIND)
420 inst |= a0reg; // Get ea0 into instr
421 D_word(inst); // Deposit instr
422 ea0gen(siz); // Generate ea0
424 // Generate ea1 if requested
434 // Dx,Dy nnnnXXXnssnnnYYY If bit 0 of `inst' is set, install size bits in bits
437 int m_abcd(WORD inst, WORD siz)
446 inst |= a0reg | reg_9[a1reg];
456 int m_adda(WORD inst, WORD siz)
458 if (a0exattr & DEFINED)
460 if (CHECK_OPTS(OPT_ADDA_ADDQ))
461 if (a0exval > 1 && a0exval <= 8)
462 // Immediate is between 1 and 8 so let's convert to addq
463 return m_addq(B16(01010000, 00000000), siz);
464 if (CHECK_OPTS(OPT_ADDA_LEA))
467 // Immediate is larger than 8 so let's convert to lea
468 am0 = ADISP; // Change addressing mode
469 a0reg = a1reg; // In ADISP a0reg is used instead of a1reg!
470 return m_lea(B16(01000001, 11011000), SIZW);
474 inst |= am0 | a0reg | lwsiz_8[siz] | reg_9[a1reg];
476 ea0gen(siz); // Generate EA
483 // If bit 0 of `inst' is 1, install size bits in bits 6..7 of instr.
484 // If bit 1 of `inst' is 1, install a1reg in bits 9..11 of instr.
486 int m_reg(WORD inst, WORD siz)
493 // Install other register (9..11)
494 inst |= reg_9[a1reg];
496 inst &= ~7; // Clear off crufty bits
497 inst |= a0reg; // Install first register
507 int m_imm(WORD inst, WORD siz)
519 int m_imm8(WORD inst, WORD siz)
532 int m_shr(WORD inst, WORD siz)
534 inst |= reg_9[a0reg] | a1reg | siz_6[siz];
544 int m_shi(WORD inst, WORD siz)
546 inst |= a1reg | siz_6[siz];
548 if (a0exattr & DEFINED)
551 return error(range_error);
553 inst |= (a0exval & 7) << 9;
558 AddFixup(FU_QUICK, sloc, a0expr);
567 // {bset, btst, bchg, bclr} -- #immed,ea -- Dn,ea
569 int m_bitop(WORD inst, WORD siz)
571 // Enforce instruction sizes
573 { // X,Dn must be .n or .l
574 if (siz & (SIZB | SIZW))
575 return error(siz_error);
577 else if (siz & (SIZW | SIZL)) // X,ea must be .n or .b
578 return error(siz_error);
580 // Construct instr and EAs
586 ea0gen(SIZB); // Immediate bit number
590 inst |= reg_9[a0reg];
601 int m_dbra(WORD inst, WORD siz)
607 if (a1exattr & DEFINED)
609 if ((a1exattr & TDB) != cursect)
610 return error(rel_error);
612 uint32_t v = (uint32_t)a1exval - sloc;
614 if (v + 0x8000 > 0x10000)
615 return error(range_error);
621 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
632 int m_exg(WORD inst, WORD siz)
638 if (am0 == DREG && am1 == DREG)
640 else if (am0 == AREG && am1 == AREG)
646 m = a1reg; // Get AREG into a1reg
654 inst |= m | reg_9[a0reg] | a1reg;
664 int m_link(WORD inst, WORD siz)
668 // Is this an error condition???
673 inst &= ~((3 << 9) | (1 << 6) | (1 << 4));
685 WORD extra_addressing[16]=
687 0x30, // 0100 (bd,An,Xn)
688 0x30, // 0101 ([bd,An],Xn,od)
689 0x30, // 0102 ([bc,An,Xn],od)
690 0x30, // 0103 (bd,PC,Xn)
691 0x30, // 0104 ([bd,PC],Xn,od)
692 0x30, // 0105 ([bc,PC,Xn],od)
707 // Handle MOVE <C_ALL> <C_ALTDATA>
708 // MOVE <C_ALL> <M_AREG>
710 // Optimize MOVE.L #<smalldata>,D0 to a MOVEQ
712 int m_move(WORD inst, WORD size)
714 // Cast the passed in value to an int
717 // Try to optimize to MOVEQ
718 // N.B.: We can get away with casting the uint64_t to a 32-bit value
719 // because it checks for a SIZL (i.e., a 32-bit value).
720 if (CHECK_OPTS(OPT_MOVEL_MOVEQ)
721 && (siz == SIZL) && (am0 == IMMED) && (am1 == DREG)
722 && ((a0exattr & (TDB | DEFINED)) == DEFINED)
723 && ((uint32_t)a0exval + 0x80 < 0x100))
725 m_moveq((WORD)0x7000, (WORD)0);
728 warn("move.l #size,dx converted to moveq");
732 if ((am0 < ABASE) && (am1 < ABASE)) // 68000 modes
734 inst |= siz_12[siz] | am_6[am1] | reg_9[a1reg] | am0 | a0reg;
742 ea1gen((WORD)siz | 0x8000); // Tell ea1gen we're move ea,ea
746 inst |= siz_12[siz] | reg_9[a1reg] | extra_addressing[am0 - ABASE];
763 // Handle MOVE <C_ALL030> <C_ALTDATA>
764 // MOVE <C_ALL030> <M_AREG>
766 int m_move30(WORD inst, WORD size)
769 inst |= siz_12[siz] | reg_9[a1reg & 7] | a0reg | extra_addressing[am0 - ABASE];
784 // move USP,An -- move An,USP
786 int m_usp(WORD inst, WORD siz)
791 inst |= a1reg; // USP, An
793 inst |= a0reg; // An, USP
804 int m_moveq(WORD inst, WORD siz)
808 // Arrange for future fixup
809 if (!(a0exattr & DEFINED))
811 AddFixup(FU_BYTE | FU_SEXT, sloc + 1, a0expr);
814 else if ((uint32_t)a0exval + 0x100 >= 0x200)
815 return error(range_error);
817 inst |= reg_9[a1reg] | (a0exval & 0xFF);
825 // movep Dn, disp(An) -- movep disp(An), Dn
827 int m_movep(WORD inst, WORD siz)
829 // Tell ea0gen to lay off the 0(a0) optimisations on this one
837 inst |= reg_9[a0reg] | a1reg;
847 inst |= reg_9[a1reg] | a0reg;
864 int m_br(WORD inst, WORD siz)
866 if (a0exattr & DEFINED)
868 if ((a0exattr & TDB) != cursect)
870 //printf("m_br(): a0exattr = %X, cursect = %X, a0exval = %X, sloc = %X\n", a0exattr, cursect, a0exval, sloc);
871 return error(rel_error);
874 uint32_t v = (uint32_t)a0exval - (sloc + 2);
876 // Optimize branch instr. size
879 if (CHECK_OPTS(OPT_BSR_BCC_S) && (v != 0) && ((v + 0x80) < 0x100))
886 warn("Bcc.w/BSR.w converted to .s");
893 if ((v + 0x8000) > 0x10000)
894 return error(range_error);
902 if (siz == SIZB || siz == SIZS)
904 if ((v + 0x80) >= 0x100)
905 return error(range_error);
912 if ((v + 0x8000) >= 0x10000)
913 return error(range_error);
921 else if (siz == SIZN)
924 if (siz == SIZB || siz == SIZS)
927 AddFixup(FU_BBRA | FU_PCREL | FU_SEXT, sloc, a0expr);
935 AddFixup(FU_WORD | FU_PCREL | FU_LBRA | FU_ISBRA, sloc, a0expr);
946 int m_addq(WORD inst, WORD siz)
948 inst |= siz_6[siz] | am1 | a1reg;
950 if (a0exattr & DEFINED)
952 if ((a0exval > 8) || (a0exval == 0)) // Range in 1..8
953 return error(range_error);
955 inst |= (a0exval & 7) << 9;
960 AddFixup(FU_QUICK, sloc, a0expr);
973 int m_trap(WORD inst, WORD siz)
977 if (a0exattr & DEFINED)
980 return error(abs_error);
983 return error(range_error);
989 return error(undef_error);
996 // movem <rlist>,ea -- movem ea,<rlist>
998 int m_movem(WORD inst, WORD siz)
1006 return error("bad size suffix");
1013 // Handle #<expr>, ea
1016 if (abs_expr(&eval) != OK)
1019 if (eval >= 0x10000L)
1020 return error(range_error);
1026 if ((*tok >= KW_D0) && (*tok <= KW_A7))
1029 if (reglist(&rmask) < 0)
1034 return error("missing comma");
1039 inst |= am0 | a0reg;
1041 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
1042 return error("invalid addressing mode");
1044 // If APREDEC, reverse register mask
1050 for(i=0x8000; i; i>>=1, w>>=1)
1051 rmask = (WORD)((rmask << 1) | (w & 1));
1060 inst |= 0x0400 | am0 | a0reg;
1063 return error("missing comma");
1066 return error("missing register list");
1073 if (abs_expr(&eval) != OK)
1076 if (eval >= 0x10000)
1077 return error(range_error);
1081 else if (reglist(&rmask) < 0)
1084 if (!(amsktab[am0] & (C_CTRL | M_APOSTINC)))
1085 return error("invalid addressing mode");
1097 // CLR.x An ==> SUBA.x An,An
1099 int m_clra(WORD inst, WORD siz)
1101 inst |= a0reg | reg_9[a0reg] | lwsiz_8[siz];
1109 // CLR.L Dn ==> CLR.L An or MOVEQ #0,Dx
1111 int m_clrd(WORD inst, WORD siz)
1113 if (!CHECK_OPTS(OPT_CLR_DX))
1116 inst = (a0reg << 9) | B16(01110000, 00000000);
1124 ////////////////////////////////////////
1126 // 68020/30/40/60 instructions
1128 ////////////////////////////////////////
1133 int m_br30(WORD inst, WORD siz)
1135 if (a0exattr & DEFINED)
1137 if ((a0exattr & TDB) != cursect)
1138 return error(rel_error);
1140 uint32_t v = (uint32_t)a0exval - (sloc + 2);
1149 AddFixup(FU_LONG | FU_PCREL | FU_SEXT, sloc, a0expr);
1157 // bfchg, bfclr, bfexts, bfextu, bfffo, bfins, bfset
1158 // (68020, 68030, 68040)
1160 int m_bfop(WORD inst, WORD siz)
1162 if ((bfval1 > 31) || (bfval1 < 0))
1163 return error("bfxxx offset: immediate value must be between 0 and 31");
1165 // First instruction word - just the opcode and first EA
1166 // Note: both am1 is ORed because solely of bfins - maybe it's a good idea
1167 // to make a dedicated function for it?
1174 if (bfval2 > 31 || bfval2 < 0)
1175 return error("bfxxx width: immediate value must be between 0 and 31");
1177 // For Dw both immediate and register number are stuffed
1178 // into the same field O_o
1179 bfparam2 = (bfval2 << 0);
1183 bfparam1 = (bfval1 << 6);
1185 bfparam1 = bfval1 << 12;
1187 //D_word((inst | am0 | a0reg | am1 | a1reg));
1188 if (inst == B16(11101111, 11000000))
1190 // bfins special case
1191 D_word((inst | am1 | a1reg));
1195 D_word((inst | am0 | a0reg));
1198 ea0gen(siz); // Generate EA
1200 // Second instruction word - Dest register (if exists), Do, Offset, Dw, Width
1201 if (inst == B16(11101111, 11000000))
1203 // bfins special case
1204 inst = bfparam1 | bfparam2;
1207 inst |= a0reg << 12;
1213 inst = bfparam1 | bfparam2;
1219 inst |= a1reg << 12;
1229 // bkpt (68EC000, 68010, 68020, 68030, 68040, CPU32)
1231 int m_bkpt(WORD inst, WORD siz)
1235 if (a0exattr & DEFINED)
1238 return error(abs_error);
1241 return error(range_error);
1247 return error(undef_error);
1256 int m_callm(WORD inst, WORD siz)
1263 if (a0exattr & DEFINED)
1266 return error(abs_error);
1269 return error(range_error);
1271 inst = (uint16_t)a0exval;
1275 return error(undef_error);
1285 // cas (68020, 68030, 68040)
1287 int m_cas(WORD inst, WORD siz)
1293 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1294 return error(unsupport);
1309 return error("bad size suffix");
1314 if ((*tok < KW_D0) && (*tok > KW_D7))
1315 return error("CAS accepts only data registers");
1317 inst2 = (*tok++) & 7;
1320 return error("missing comma");
1323 if ((*tok < KW_D0) && (*tok > KW_D7))
1324 return error("CAS accepts only data registers");
1326 inst2 |= ((*tok++) & 7) << 6;
1329 return error("missing comma");
1332 if ((modes = amode(1)) < 0)
1336 return error("too many ea fields");
1339 return error("extra (unexpected) text found");
1341 // Reject invalid ea modes
1342 amsk = amsktab[am0];
1344 if ((amsk & (M_AIND | M_APOSTINC | M_APREDEC | M_ADISP | M_AINDEXED | M_ABSW | M_ABSL | M_ABASE | M_MEMPOST | M_MEMPRE)) == 0)
1345 return error("unsupported addressing mode");
1347 inst |= am0 | a0reg;
1357 // cas2 (68020, 68030, 68040)
1359 int m_cas2(WORD inst, WORD siz)
1363 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1364 return error(unsupport);
1379 return error("bad size suffix");
1384 if ((*tok < KW_D0) && (*tok > KW_D7))
1385 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1387 inst2 = (*tok++) & 7;
1390 return error("missing colon");
1393 if ((*tok < KW_D0) && (*tok > KW_D7))
1394 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1396 inst3 = (*tok++) & 7;
1399 return error("missing comma");
1402 if ((*tok < KW_D0) && (*tok > KW_D7))
1403 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1405 inst2 |= ((*tok++) & 7) << 6;
1408 return error("missing colon");
1411 if ((*tok < KW_D0) && (*tok > KW_D7))
1412 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1414 inst3 |= ((*tok++) & 7) << 6;
1417 return error("missing comma");
1421 return error("missing (");
1422 if ((*tok >= KW_D0) && (*tok <= KW_D7))
1423 inst2 |= (((*tok++) & 7) << 12) | (0 << 15);
1424 else if ((*tok >= KW_A0) && (*tok <= KW_A7))
1425 inst2 |= (((*tok++) & 7) << 12) | (1 << 15);
1427 return error("CAS accepts either data or address registers for Rn1:Rn2 pair");
1430 return error("missing (");
1433 return error("missing colon");
1437 return error("missing (");
1438 if ((*tok >= KW_D0) && (*tok <= KW_D7))
1439 inst3 |= (((*tok++) & 7) << 12) | (0 << 15);
1440 else if ((*tok >= KW_A0) && (*tok <= KW_A7))
1441 inst3 |= (((*tok++) & 7) << 12) | (1 << 15);
1443 return error("CAS accepts either data or address registers for Rn1:Rn2 pair");
1446 return error("missing (");
1449 return error("extra (unexpected) text found");
1460 // cmp2 (68020, 68030, 68040, CPU32)
1462 int m_cmp2(WORD inst, WORD siz)
1464 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1465 return error(unsupport);
1467 switch (siz & 0x000F)
1481 WORD flg = inst; // Save flag bits
1482 inst &= ~0x3F; // Clobber flag bits in instr
1484 // Install "standard" instr size bits
1490 // OR-in register number
1492 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1494 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1500 inst |= am1 | a1reg; // Get ea1 into instr
1501 D_word(inst); // Deposit instr
1503 // Generate ea0 if requested
1507 ea1gen(siz); // Generate ea1
1512 inst |= am0 | a0reg; // Get ea0 into instr
1513 D_word(inst); // Deposit instr
1514 ea0gen(siz); // Generate ea0
1516 // Generate ea1 if requested
1521 // If we're called from chk2 then bit 11 of size will be set. This is just
1522 // a dumb mechanism to pass this, required by the extension word. (You might
1523 // have noticed the siz & 15 thing above!)
1524 inst = (a1reg << 12) | (siz & (1 << 11));
1536 // chk2 (68020, 68030, 68040, CPU32)
1538 int m_chk2(WORD inst, WORD siz)
1540 return m_cmp2(inst, siz | (1 << 11));
1545 // cpbcc(68020, 68030, 68040 (FBcc), 68060 (FBcc))
1546 // TODO: Better checks for different instructions?
1548 int m_cpbr(WORD inst, WORD siz)
1550 if ((activecpu & (CPU_68020 | CPU_68030)) && (!activefpu == 0))
1551 return error(unsupport);
1553 if (a0exattr & DEFINED)
1555 if ((a0exattr & TDB) != cursect)
1556 return error(rel_error);
1558 uint32_t v = (uint32_t)a0exval - (sloc + 2);
1560 // Optimize branch instr. size
1563 if ((v != 0) && ((v + 0x8000) < 0x10000))
1573 if ((v + 0x8000) >= 0x10000)
1574 return error(range_error);
1582 else if (siz == SIZN)
1589 AddFixup(FU_LONG | FU_PCREL | FU_SEXT, sloc, a0expr);
1597 AddFixup(FU_WORD | FU_PCREL | FU_SEXT, sloc, a0expr);
1606 // cpdbcc(68020, 68030)
1608 int m_cpdbr(WORD inst, WORD siz)
1613 WORD condition = inst & 0x1F; // Grab condition sneakily placed in the lower 5 bits of inst
1614 inst &= 0xFFE0; // And then mask them out - you ain't seen me, roit?
1616 inst |= (1 << 9); // Bolt on FPU id
1623 if (a1exattr & DEFINED)
1625 if ((a1exattr & TDB) != cursect)
1626 return error(rel_error);
1628 v = (uint32_t)a1exval - sloc;
1630 if (v + 0x8000 > 0x10000)
1631 return error(range_error);
1637 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
1647 // muls.l / divs.l / divu.l / mulu.l (68020+)
1649 int m_muls(WORD inst, WORD siz)
1651 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1652 return error(unsupport);
1654 WORD flg = inst; // Save flag bits
1655 inst &= ~0x33F; // Clobber flag and extension bits in instr
1657 // Install "standard" instr size bits
1663 // OR-in register number
1665 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1667 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1670 // Regarding extension word: bit 11 is signed/unsigned selector
1671 // bit 10 is 32/64 bit selector
1672 // Both of these are packed in bits 9 and 8 of the instruction
1673 // field in 68ktab. Extra compilcations arise from the fact we
1674 // have to distinguish between divu/s.l Dn,Dm (which is encoded
1675 // as divu/s.l Dn,Dm:Dm) and divu/s.l Dn,Dm:Dx - the first is
1676 // 32 bit while the second 64 bit
1681 inst |= am1 | a1reg; // Get ea1 into instr
1682 D_word(inst); // Deposit instr
1686 inst = a1reg + (a2reg << 12) + ((flg & 0x200) << 2);
1688 inst = a1reg + (a2reg << 12) + ((flg & 0x300) << 2);
1692 // Generate ea0 if requested
1696 ea1gen(siz); // Generate ea1
1703 inst |= am0 | a0reg; // Get ea0 into instr
1704 D_word(inst); // Deposit instr
1708 inst = a1reg + (a2reg << 12) + ((flg & 0x200) << 2);
1710 inst = a1reg + (a2reg << 12) + ((flg & 0x300) << 2);
1714 ea0gen(siz); // Generate ea0
1716 // Generate ea1 if requested
1726 // move16 (ax)+,(ay)+
1728 int m_move16a(WORD inst, WORD siz)
1730 if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1731 return error(unsupport);
1735 inst = (1 << 15) + (a1reg << 12);
1743 // move16 with absolute address
1745 int m_move16b(WORD inst, WORD siz)
1747 if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1748 return error(unsupport);
1754 if (am0 == APOSTINC)
1757 return error("Wasn't this suppose to call m_move16a???");
1760 // move16 (ax)+,(xxx).L
1765 else if (am0 == ABSL)
1769 // move16 (xxx).L,(ax)+
1775 // move16 (xxx).L,(ax)
1780 else if (am0 == AIND)
1782 // move16 (ax),(xxx).L
1795 // pack/unpack (68020/68030/68040)
1797 int m_pack(WORD inst, WORD siz)
1802 return error("bad size suffix");
1804 if (*tok >= KW_D0 && *tok <= KW_D7)
1806 // Dx,Dy,#<adjustment>
1807 inst |= (0 << 3); // R/M
1808 inst |= (*tok++ & 7);
1810 if (*tok != ',' && tok[2] != ',')
1811 return error("missing comma");
1813 if (tok[1] < KW_D0 && tok[1] > KW_D7)
1814 return error(syntax_error);
1816 inst |= ((tok[1] & 7)<<9);
1819 // Fall through for adjustment (common in both valid cases)
1821 else if (*tok == '-')
1823 // -(Ax),-(Ay),#<adjustment>
1824 inst |= (1 << 3); // R/M
1825 tok++; // eat the minus
1827 if ((*tok != '(') && (tok[2]!=')') && (tok[3]!=',') && (tok[4] != '-') && (tok[5] != '(') && (tok[7] != ')') && (tok[8] != ','))
1828 return error(syntax_error);
1830 if (tok[1] < KW_A0 && tok[1] > KW_A7)
1831 return error(syntax_error);
1833 if (tok[5] < KW_A0 && tok[6] > KW_A7)
1834 return error(syntax_error);
1836 inst |= ((tok[1] & 7) << 0);
1837 inst |= ((tok[6] & 7) << 9);
1840 // Fall through for adjustment (common in both valid cases)
1843 return error("invalid syntax");
1845 if ((*tok != CONST) && (*tok != SYMBOL) && (*tok != '-'))
1846 return error(syntax_error);
1848 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
1851 if ((a0exattr & DEFINED) == 0)
1852 return error(undef_error);
1854 if (a0exval + 0x8000 > 0x10000)
1858 return error(extra_stuff);
1860 D_word((a0exval & 0xFFFF));
1869 int m_rtm(WORD inst, WORD siz)
1877 else if (am0 == AREG)
1879 inst |= (1 << 3) + a0reg;
1882 return error("rtm only allows data or address registers.");
1893 int m_rtd(WORD inst, WORD siz)
1897 if (a0exattr & DEFINED)
1900 return error(abs_error);
1902 if ((a0exval + 0x8000) <= 0x7FFF)
1903 return error(range_error);
1909 return error(undef_error);
1918 int m_trapcc(WORD inst, WORD siz)
1926 else if (am0 == IMMED)
1930 if (a0exval < 0x10000)
1937 return error("Immediate value too big");
1947 return error("Invalid parameter for trapcc");
1954 // cinvl/p/a (68040/68060)
1956 int m_cinv(WORD inst, WORD siz)
1961 inst |= (0 << 6) | (a1reg);
1965 inst |= (2 << 6) | (a1reg);
1968 inst |= (1 << 6) | (a1reg);
1971 inst |= (3 << 6) | (a1reg);
1980 int m_fpusavrest(WORD inst, WORD siz)
1982 inst |= am0 | a0reg;
1991 // cpSAVE/cpRESTORE (68020, 68030)
1993 int m_cprest(WORD inst, WORD siz)
1995 if (activecpu & !(CPU_68020 | CPU_68030))
1996 return error(unsupport);
1998 return m_fpusavrest(inst, siz);
2004 // FSAVE/FRESTORE (68040, 68060)
2006 int m_frestore(WORD inst, WORD siz)
2008 if ((!(activecpu & (CPU_68040 | CPU_68060))) ||
2009 (activefpu&(FPU_68881 | FPU_68882)))
2010 return error(unsupport);
2012 return m_fpusavrest(inst, siz);
2017 // movec (68010, 68020, 68030, 68040, 68060, CPU32)
2019 int m_movec(WORD inst, WORD siz)
2023 if (am0 == DREG || am0 == AREG)
2031 inst = (0 << 15) + (a0reg << 12) + CREGlut[a1reg];
2036 inst = (1 << 15) + (a0reg << 12) + CREGlut[a1reg];
2047 inst = (0 << 15) + (a1reg << 12) + CREGlut[a0reg];
2052 inst = (1 << 15) + (a1reg << 12) + CREGlut[a0reg];
2062 // moves (68010, 68020, 68030, 68040, CPU32)
2064 int m_moves(WORD inst, WORD siz)
2066 if (activecpu & !(CPU_68020 | CPU_68030 | CPU_68040))
2067 return error(unsupport);
2071 else if (siz == SIZL)
2078 inst |= am1 | a1reg;
2080 inst = (a0reg << 12) | (1 << 11) | (0 << 15);
2083 else if (am0 == AREG)
2085 inst |= am1 | a1reg;
2087 inst = (a0reg << 12) | (1 << 11) | (1 << 15);
2094 inst |= am0 | a0reg;
2096 inst = (a1reg << 12) | (0 << 11) | (0 << 15);
2101 inst |= am0 | a0reg;
2103 inst = (a1reg << 12) | (0 << 11) | (1 << 15);
2115 int m_pbcc(WORD inst, WORD siz)
2118 return error("Not implemented yet.");
2123 // pflusha (68030, 68040)
2125 int m_pflusha(WORD inst, WORD siz)
2127 if (activecpu == CPU_68030)
2130 inst = (1 << 13) | (1 << 10) | (0 << 5) | 0;
2134 else if (activecpu == CPU_68040)
2136 inst = B16(11110101, 00011000);
2141 return error(unsupport);
2148 // pflush (68030, 68040, 68060)
2150 int m_pflush(WORD inst, WORD siz)
2152 if (activecpu == CPU_68030)
2155 // PFLUSH FC, MASK, < ea >
2163 if (*tok != CONST && *tok != SYMBOL)
2164 return error("function code should be an expression");
2166 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2169 if ((a0exattr & DEFINED) == 0)
2170 return error("function code immediate should be defined");
2173 return error("function code out of range (0-7)");
2175 fc = (uint16_t)a0exval;
2185 fc = (1 << 4) | (*tok++ & 7);
2196 return error(syntax_error);
2200 return error("comma exptected");
2203 return error("mask should be an immediate value");
2205 if (*tok != CONST && *tok != SYMBOL)
2206 return error("mask is supposed to be immediate");
2208 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2211 if ((a0exattr & DEFINED) == 0)
2212 return error("mask immediate value should be defined");
2215 return error("function code out of range (0-7)");
2217 mask = (uint16_t)a0exval << 5;
2223 inst = (1 << 13) | fc | mask | (4 << 10);
2227 else if (*tok == ',')
2229 // PFLUSH FC, MASK, < ea >
2232 if (amode(0) == ERROR)
2236 return error(extra_stuff);
2238 if (am0 == AIND || am0 == ABSW || am0 == ABSL || am0 == ADISP || am0 == ADISP || am0 == AINDEXED || am0 == ABASE || am0 == MEMPOST || am0 == MEMPRE)
2240 inst |= am0 | a0reg;
2242 inst = (1 << 13) | fc | mask | (6 << 10);
2248 return error("unsupported addressing mode");
2252 return error(syntax_error);
2256 else if (activecpu == CPU_68040 || activecpu == CPU_68060)
2260 if (*tok != '(' && tok[2] != ')')
2261 return error(syntax_error);
2263 if (tok[1] < KW_A0 && tok[1] > KW_A7)
2264 return error("expected (An)");
2266 if ((inst & 7) == 7)
2267 // With pflushn/pflush there's no easy way to distinguish between
2268 // the two in 68040 mode. Ideally the opcode bitfields would have
2269 // been hardcoded in 68ktab but there is aliasing between 68030
2270 // and 68040 opcode. So we just set the 3 lower bits to 1 in
2271 // pflushn inside 68ktab and detect it here.
2272 inst = (inst & 0xff8) | 8;
2274 inst |= (tok[1] & 7) | (5 << 8);
2277 return error(extra_stuff);
2282 return error(unsupport);
2289 // pflushan (68040, 68060)
2291 int m_pflushan(WORD inst, WORD siz)
2293 if (activecpu == CPU_68040 || activecpu == CPU_68060)
2303 int m_pflushr(WORD inst, WORD siz)
2307 WORD flg = inst; // Save flag bits
2308 inst &= ~0x3F; // Clobber flag bits in instr
2310 // Install "standard" instr size bits
2316 // OR-in register number
2318 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
2320 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
2326 inst |= am1 | a1reg; // Get ea1 into instr
2327 D_word(inst); // Deposit instr
2329 // Generate ea0 if requested
2333 ea1gen(siz); // Generate ea1
2338 inst |= am0 | a0reg; // Get ea0 into instr
2339 D_word(inst); // Deposit instr
2340 ea0gen(siz); // Generate ea0
2342 // Generate ea1 if requested
2347 D_word(B16(10100000, 00000000));
2353 // ploadr, ploadw (68030)
2355 int m_pload(WORD inst, WORD siz, WORD extension)
2357 // TODO: 68851 support is not added yet.
2358 // None of the ST series of computers had a 68020 + 68851 socket and since
2359 // this is an Atari targetted assembler...
2368 if (a0reg == KW_SFC - KW_SFC)
2370 else if (a0reg == KW_DFC - KW_SFC)
2373 return error("illegal control register specified");
2377 inst = (1 << 3) | a0reg;
2380 if ((a0exattr & DEFINED) == 0)
2381 return error("constant value must be defined");
2383 inst = (2 << 3) | (uint16_t)a0exval;
2387 inst |= extension | (1 << 13);
2396 int m_ploadr(WORD inst, WORD siz)
2398 return m_pload(inst, siz, 1 << 9);
2402 int m_ploadw(WORD inst, WORD siz)
2404 return m_pload(inst, siz, 0 << 9);
2409 // pmove (68030/68851)
2411 int m_pmove(WORD inst, WORD siz)
2415 // TODO: 68851 support is not added yet. None of the ST series of
2416 // computers had a 68020 + 68851 socket and since this is an Atari
2417 // targetted assembler.... (same for 68EC030)
2420 inst2 = inst & (1 << 8); // Copy the flush bit over to inst2 in case we're called from m_pmovefd
2421 inst &= ~(1 << 8); // And mask it out
2428 else if (am1 == CREG)
2434 return error("pmove sez: Wut?");
2436 // The instruction is a quad-word (8 byte) operation
2437 // for the CPU root pointer and the supervisor root pointer.
2438 // It is a long-word operation for the translation control register
2439 // and the transparent translation registers(TT0 and TT1).
2440 // It is a word operation for the MMU status register.
2442 if (((reg == (KW_URP - KW_SFC)) || (reg == (KW_SRP - KW_SFC)))
2443 && ((siz != SIZD) && (siz != SIZN)))
2444 return error(siz_error);
2446 if (((reg == (KW_TC - KW_SFC)) || (reg == (KW_TT0 - KW_SFC)) || (reg == (KW_TT1 - KW_SFC)))
2447 && ((siz != SIZL) && (siz != SIZN)))
2448 return error(siz_error);
2450 if ((reg == (KW_MMUSR - KW_SFC)) && ((siz != SIZW) && (siz != SIZN)))
2451 return error(siz_error);
2455 inst |= am1 | a1reg;
2458 else if (am1 == CREG)
2460 inst |= am0 | a0reg;
2464 switch (reg + KW_SFC)
2467 inst2 |= (0 << 10) + (1 << 14); break;
2469 inst2 |= (2 << 10) + (1 << 14); break;
2471 inst2 |= (3 << 10) + (1 << 14); break;
2473 inst2 |= (2 << 10) + (0 << 13); break;
2475 inst2 |= (3 << 10) + (0 << 13); break;
2478 inst2 |= (1 << 9) + (3 << 13);
2480 inst2 |= (0 << 9) + (3 << 13);
2483 return error("unsupported register");
2491 else if (am1 == CREG)
2501 int m_pmovefd(WORD inst, WORD siz)
2505 return m_pmove(inst | (1 << 8), siz);
2512 int m_ptrapcc(WORD inst, WORD siz)
2515 // We stash the 5 condition bits inside the opcode in 68ktab (bits 0-4),
2516 // so we need to extract them first and fill in the clobbered bits.
2517 WORD opcode = inst & 0x1F;
2518 inst = (inst & 0xFFE0) | (0x18);
2527 else if (siz == SIZL)
2534 else if (siz == SIZN)
2546 // ptestr, ptestw (68030)
2548 int m_ptest(WORD inst, WORD siz)
2552 if (activecpu == CPU_68030)
2553 return error("Not implemented yet.");
2554 else if (activecpu == CPU_68040)
2555 return error("Not implemented yet.");
2560 //////////////////////////////////////////////////////////////////////////////
2562 // 68020/30/40/60 instructions
2563 // Note: the map of which instructions are allowed on which CPUs came from the
2564 // 68060 manual, section D-1 (page 392 of the PDF). The current implementation
2565 // is missing checks for the EC models which have a simplified FPU.
2567 //////////////////////////////////////////////////////////////////////////////
2570 #define FPU_NOWARN 0
2575 // Generate a FPU opcode
2577 static inline int gen_fpu(WORD inst, WORD siz, WORD opmode, WORD emul)
2579 if (am0 < AM_NONE) // Check first operand for ea or fp - is this right?
2581 inst |= (1 << 9); // Bolt on FPU id
2584 //if (am0 == DREG || am0 == AREG)
2588 inst = 1 << 14; // R/M field (we have ea so have to set this to 1)
2592 case SIZB: inst |= (6 << 10); break;
2593 case SIZW: inst |= (4 << 10); break;
2594 case SIZL: inst |= (0 << 10); break;
2596 case SIZS: inst |= (1 << 10); break;
2597 case SIZD: inst |= (5 << 10); break;
2598 case SIZX: inst |= (2 << 10); break;
2603 warn("This encoding will cause an unimplemented data type exception in the MC68040 to allow emulation in software.");
2607 return error("Something bad happened, possibly, in gen_fpu.");
2611 inst |= (a1reg << 7);
2618 inst |= (1 << 9); // Bolt on FPU id
2622 inst |= (a1reg << 7);
2627 if ((emul & FPU_FPSP) && (activefpu == (FPU_68040 | FPU_68060)))
2628 warn("Instruction is emulated in 68040/060");
2635 // fabs (6888X, 68040FPSP, 68060FPSP)
2637 int m_fabs(WORD inst, WORD siz)
2640 return gen_fpu(inst, siz, B8(00011000), FPU_NOWARN);
2645 // fsabs (68040, 68060)
2647 int m_fsabs(WORD inst, WORD siz)
2650 if (activefpu == FPU_68040)
2651 return gen_fpu(inst, siz, B8(01011000), FPU_NOWARN);
2653 return error("Unsupported in current FPU");
2658 // fdabs (68040, 68060)
2660 int m_fdabs(WORD inst, WORD siz)
2662 if (activefpu == FPU_68040)
2663 return gen_fpu(inst, siz, B8(01011100), FPU_NOWARN);
2665 return error("Unsupported in current FPU");
2670 // facos (6888X, 68040FPSP, 68060FPSP)
2672 int m_facos(WORD inst, WORD siz)
2675 return gen_fpu(inst, siz, B8(00011100), FPU_FPSP);
2680 // fadd (6888X, 68040, 68060)
2682 int m_fadd(WORD inst, WORD siz)
2685 return gen_fpu(inst, siz, B8(00100010), FPU_NOWARN);
2690 // fsadd (68040, 68060)
2692 int m_fsadd(WORD inst, WORD siz)
2694 if (activefpu & (FPU_68040 | FPU_68060))
2695 return gen_fpu(inst, siz, B8(01100010), FPU_NOWARN);
2697 return error("Unsupported in current FPU");
2704 int m_fdadd(WORD inst, WORD siz)
2706 if (activefpu & (FPU_68040 | FPU_68060))
2707 return gen_fpu(inst, siz, B8(01100110), FPU_NOWARN);
2709 return error("Unsupported in current FPU");
2714 // fasin (6888X, 68040FPSP, 68060FPSP)
2716 int m_fasin(WORD inst, WORD siz)
2719 return gen_fpu(inst, siz, B8(00001100), FPU_FPSP);
2724 // fatan (6888X, 68040FPSP, 68060FPSP)
2726 int m_fatan(WORD inst, WORD siz)
2729 return gen_fpu(inst, siz, B8(00001010), FPU_FPSP);
2734 // fatanh (6888X, 68040FPSP, 68060FPSP)
2736 int m_fatanh(WORD inst, WORD siz)
2739 return gen_fpu(inst, siz, B8(00001101), FPU_FPSP);
2744 // fcmp (6888X, 68040, 68060)
2746 int m_fcmp(WORD inst, WORD siz)
2749 return gen_fpu(inst, siz, B8(00111000), FPU_FPSP);
2754 // fcos (6888X, 68040FPSP, 68060FPSP)
2756 int m_fcos(WORD inst, WORD siz)
2759 return gen_fpu(inst, siz, B8(00011101), FPU_FPSP);
2764 // fcosh (6888X, 68040FPSP, 68060FPSP)
2766 int m_fcosh(WORD inst, WORD siz)
2769 return gen_fpu(inst, siz, B8(00011001), FPU_FPSP);
2774 // fdbcc (6888X, 68040, 68060FPSP)
2776 int m_fdbcc(WORD inst, WORD siz)
2779 WORD opcode = inst & 0x3F; // Grab conditional bitfield
2789 if (a1exattr & DEFINED)
2791 if ((a1exattr & TDB) != cursect)
2792 return error(rel_error);
2794 uint32_t v = (uint32_t)a1exval - sloc;
2796 if ((v + 0x8000) > 0x10000)
2797 return error(range_error);
2803 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
2807 if (activefpu == FPU_68060)
2808 warn("Instruction is emulated in 68060");
2815 // fdiv (6888X, 68040, 68060)
2817 int m_fdiv(WORD inst, WORD siz)
2820 return gen_fpu(inst, siz, B8(00100000), FPU_NOWARN);
2825 // fsdiv (68040, 68060)
2827 int m_fsdiv(WORD inst, WORD siz)
2829 if (activefpu & (FPU_68040 | FPU_68060))
2830 return gen_fpu(inst, siz, B8(01100000), FPU_NOWARN);
2832 return error("Unsupported in current FPU");
2837 // fddiv (68040, 68060)
2839 int m_fddiv(WORD inst, WORD siz)
2841 if (activefpu & (FPU_68040 | FPU_68060))
2842 return gen_fpu(inst, siz, B8(01100100), FPU_NOWARN);
2844 return error("Unsupported in current FPU");
2849 // fetox (6888X, 68040FPSP, 68060FPSP)
2851 int m_fetox(WORD inst, WORD siz)
2854 return gen_fpu(inst, siz, B8(00010000), FPU_FPSP);
2859 // fetoxm1 (6888X, 68040FPSP, 68060FPSP)
2861 int m_fetoxm1(WORD inst, WORD siz)
2864 return gen_fpu(inst, siz, B8(00001000), FPU_FPSP);
2869 // fgetexp (6888X, 68040FPSP, 68060FPSP)
2871 int m_fgetexp(WORD inst, WORD siz)
2874 return gen_fpu(inst, siz, B8(00011110), FPU_FPSP);
2879 // fgetman (6888X, 68040FPSP, 68060FPSP)
2881 int m_fgetman(WORD inst, WORD siz)
2884 return gen_fpu(inst, siz, B8(00011111), FPU_FPSP);
2889 // fint (6888X, 68040FPSP, 68060)
2891 int m_fint(WORD inst, WORD siz)
2894 // special case - fint fpx = fint fpx,fpx
2897 if (activefpu == FPU_68040)
2898 warn("Instruction is emulated in 68040");
2900 return gen_fpu(inst, siz, B8(00000001), FPU_NOWARN);
2905 // fintrz (6888X, 68040FPSP, 68060)
2907 int m_fintrz(WORD inst, WORD siz)
2910 // special case - fintrz fpx = fintrz fpx,fpx
2913 if (activefpu == FPU_68040)
2914 warn("Instruction is emulated in 68040");
2916 return gen_fpu(inst, siz, B8(00000011), FPU_NOWARN);
2921 // flog10 (6888X, 68040FPSP, 68060FPSP)
2923 int m_flog10(WORD inst, WORD siz)
2926 return gen_fpu(inst, siz, B8(00010101), FPU_FPSP);
2931 // flog2 (6888X, 68040FPSP, 68060FPSP)
2933 int m_flog2(WORD inst, WORD siz)
2936 return gen_fpu(inst, siz, B8(00010110), FPU_FPSP);
2941 // flogn (6888X, 68040FPSP, 68060FPSP)
2943 int m_flogn(WORD inst, WORD siz)
2946 return gen_fpu(inst, siz, B8(00010100), FPU_FPSP);
2951 // flognp1 (68040FPSP, 68060FPSP)
2953 int m_flognp1(WORD inst, WORD siz)
2955 if (activefpu & (FPU_68040 | FPU_68060))
2956 return gen_fpu(inst, siz, B8(00000110), FPU_FPSP);
2958 return error("Unsupported in current FPU");
2963 // fmod (6888X, 68040FPSP, 68060FPSP)
2965 int m_fmod(WORD inst, WORD siz)
2968 return gen_fpu(inst, siz, B8(00100001), FPU_FPSP);
2973 // fmove (6888X, 68040, 68060)
2975 int m_fmove(WORD inst, WORD siz)
2980 if ((am0 == FREG) && (am1 < AM_USP))
2984 inst |= am1 | a1reg;
2993 case SIZB: inst |= (6 << 10); break;
2994 case SIZW: inst |= (4 << 10); break;
2995 case SIZL: inst |= (0 << 10); break;
2997 case SIZS: inst |= (1 << 10); break;
2998 case SIZD: inst |= (5 << 10); break;
2999 case SIZX: inst |= (2 << 10); break;
3000 case SIZP: inst |= (3 << 10);
3001 // In P size we have 2 cases: {#k} where k is immediate
3002 // and {Dn} where Dn=Data register
3007 inst |= bfval1 << 4;
3012 if (bfval1 > 63 && bfval1 < -64)
3013 return error("K-factor must be between -64 and 63");
3015 inst |= bfval1 & 127;
3020 return error("Something bad happened, possibly.");
3024 // Destination specifier
3025 inst |= (a0reg << 7);
3033 else if ((am0 < AM_USP) && (am1 == FREG))
3038 inst |= am0 | a0reg;
3047 case SIZB: inst |= (6 << 10); break;
3048 case SIZW: inst |= (4 << 10); break;
3049 case SIZL: inst |= (0 << 10); break;
3051 case SIZS: inst |= (1 << 10); break;
3052 case SIZD: inst |= (5 << 10); break;
3053 case SIZX: inst |= (2 << 10); break;
3054 case SIZP: inst |= (3 << 10); break;
3056 return error("Something bad happened, possibly.");
3060 // Destination specifier
3061 inst |= (a1reg << 7);
3069 else if ((am0 == FREG) && (am1 == FREG))
3071 // register-to-register
3072 // Essentially ea to register with R/0=0
3081 if (siz != SIZX && siz != SIZN)
3082 return error("Invalid size");
3085 inst |= (a0reg << 10);
3087 // Destination register
3088 inst |= (a1reg << 7);
3098 // fmove (6888X, 68040, 68060)
3100 int m_fmovescr(WORD inst, WORD siz)
3104 // Move Floating-Point System Control Register (FPCR)
3108 if ((am0 == FPSCR) && (am1 < AM_USP))
3110 inst |= am1 | a1reg;
3112 inst = (1 << 13) + (1 << 15);
3118 else if ((am1 == FPSCR) && (am0 < AM_USP))
3120 inst |= am0 | a0reg;
3122 inst = (0 << 13) + (1 << 15);
3129 return error("m_fmovescr says: wut?");
3133 // fsmove/fdmove (68040, 68060)
3135 int m_fsmove(WORD inst, WORD siz)
3137 if (!(activefpu & (FPU_68040 | FPU_68060)))
3138 return error("Unsupported in current FPU");
3140 return error("Not implemented yet.");
3143 if (activefpu == FPU_68040)
3144 return gen_fpu(inst, siz, B8(01100100), FPU_P_EMUL);
3146 return error("Unsupported in current FPU");
3151 int m_fdmove(WORD inst, WORD siz)
3153 if (!(activefpu & (FPU_68040 | FPU_68060)))
3154 return error("Unsupported in current FPU");
3156 return error("Not implemented yet.");
3159 if (activefpu == FPU_68040)
3160 return gen_fpu(inst, siz, B8(01100100), FPU_P_EMUL);
3162 return error("Unsupported in current FPU");
3168 // fmovecr (6888X, 68040FPSP, 68060FPSP)
3170 int m_fmovecr(WORD inst, WORD siz)
3180 if (activefpu == FPU_68040)
3181 warn("Instruction is emulated in 68040/060");
3188 // fmovem (6888X, 68040, 68060FPSP)
3190 int m_fmovem(WORD inst, WORD siz)
3197 if (siz == SIZX || siz == SIZN)
3199 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
3201 // fmovem.x <rlist>,ea
3202 if (fpu_reglist_left(®mask) < 0)
3206 return error("missing comma");
3211 inst |= am0 | a0reg;
3213 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3214 return error("invalid addressing mode");
3217 inst = (1 << 15) | (1 << 14) | (1 << 13) | (0 << 11) | regmask;
3222 else if ((*tok >= KW_D0) && (*tok <= KW_D7))
3225 datareg = (*tok++ & 7) << 10;
3228 return error("missing comma");
3233 inst |= am0 | a0reg;
3235 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3236 return error("invalid addressing mode");
3238 // Quote from the 060 manual:
3239 // "[..] when the processor attempts an FMOVEM.X instruction using a dynamic register list."
3240 if (activefpu == FPU_68060)
3241 warn("Instruction is emulated in 68060");
3244 inst = (1 << 15) | (1 << 14) | (1 << 13) | (1 << 11) | (datareg << 4);
3255 inst |= am0 | a0reg;
3258 return error("missing comma");
3260 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
3262 // fmovem.x ea,<rlist>
3263 if (fpu_reglist_right(®mask) < 0)
3267 inst = (1 << 15) | (1 << 14) | (0 << 13) | (2 << 11) | regmask;
3275 datareg = (*tok++ & 7) << 10;
3277 // Quote from the 060 manual:
3278 // "[..] when the processor attempts an FMOVEM.X instruction using a dynamic register list."
3279 if (activefpu == FPU_68060)
3280 warn("Instruction is emulated in 68060");
3283 inst = (1 << 15) | (1 << 14) | (0 << 13) | (3 << 11) | (datareg << 4);
3290 else if (siz == SIZL)
3292 if ((*tok == KW_FPCR) || (*tok == KW_FPSR) || (*tok == KW_FPIAR))
3294 // fmovem.l <rlist>,ea
3295 regmask = (1 << 15) | (1 << 13);
3296 int no_control_regs = 0;
3299 if (*tok == KW_FPCR)
3301 regmask |= (1 << 12);
3307 if (*tok == KW_FPSR)
3309 regmask |= (1 << 11);
3315 if (*tok == KW_FPIAR)
3317 regmask |= (1 << 10);
3323 if ((*tok == '/') || (*tok == '-'))
3330 return error("missing comma");
3335 // Quote from the 060 manual:
3336 // "[..] when the processor attempts to execute an FMOVEM.L instruction with
3337 // an immediate addressing mode to more than one floating - point
3338 // control register (FPCR, FPSR, FPIAR)[..]"
3339 if (activefpu == FPU_68060)
3340 if (no_control_regs > 1 && am0 == IMMED)
3341 warn("Instruction is emulated in 68060");
3343 inst |= am0 | a0reg;
3350 // fmovem.l ea,<rlist>
3354 inst |= am0 | a0reg;
3357 return error("missing comma");
3359 regmask = (1 << 15) | (0 << 13);
3362 if (*tok == KW_FPCR)
3364 regmask |= (1 << 12);
3369 if (*tok == KW_FPSR)
3371 regmask |= (1 << 11);
3376 if (*tok == KW_FPIAR)
3378 regmask |= (1 << 10);
3383 if ((*tok == '/') || (*tok == '-'))
3390 return error("extra (unexpected) text found");
3392 inst |= am0 | a0reg;
3399 return error("bad size suffix");
3406 // fmul (6888X, 68040, 68060)
3408 int m_fmul(WORD inst, WORD siz)
3411 return gen_fpu(inst, siz, B8(00100011), FPU_NOWARN);
3416 // fsmul (68040, 68060)
3418 int m_fsmul(WORD inst, WORD siz)
3420 if (activefpu & (FPU_68040 | FPU_68060))
3421 return gen_fpu(inst, siz, B8(01100011), FPU_NOWARN);
3423 return error("Unsupported in current FPU");
3430 int m_fdmul(WORD inst, WORD siz)
3432 if (activefpu & (FPU_68040 | FPU_68060))
3433 return gen_fpu(inst, siz, B8(01100111), FPU_NOWARN);
3435 return error("Unsupported in current FPU");
3440 // fneg (6888X, 68040, 68060)
3442 int m_fneg(WORD inst, WORD siz)
3449 return gen_fpu(inst, siz, B8(00011010), FPU_NOWARN);
3452 return gen_fpu(inst, siz, B8(00011010), FPU_NOWARN);
3457 // fsneg (68040, 68060)
3459 int m_fsneg(WORD inst, WORD siz)
3461 if (activefpu & (FPU_68040 | FPU_68060))
3466 return gen_fpu(inst, siz, B8(01011010), FPU_NOWARN);
3469 return gen_fpu(inst, siz, B8(01011010), FPU_NOWARN);
3472 return error("Unsupported in current FPU");
3477 // fdneg (68040, 68060)
3479 int m_fdneg(WORD inst, WORD siz)
3481 if (activefpu & (FPU_68040 | FPU_68060))
3486 return gen_fpu(inst, siz, B8(01011110), FPU_NOWARN);
3489 return gen_fpu(inst, siz, B8(01011110), FPU_NOWARN);
3492 return error("Unsupported in current FPU");
3497 // fnop (6888X, 68040, 68060)
3499 int m_fnop(WORD inst, WORD siz)
3502 return gen_fpu(inst, siz, B8(00000000), FPU_NOWARN);
3507 // frem (6888X, 68040FPSP, 68060FPSP)
3509 int m_frem(WORD inst, WORD siz)
3512 return gen_fpu(inst, siz, B8(00100101), FPU_FPSP);
3517 // fscale (6888X, 68040FPSP, 68060FPSP)
3519 int m_fscale(WORD inst, WORD siz)
3522 return gen_fpu(inst, siz, B8(00100110), FPU_FPSP);
3527 // FScc (6888X, 68040, 68060), cpScc (68851, 68030), PScc (68851)
3528 // TODO: Add check for PScc to ensure 68020+68851 active
3529 // TODO: Add check for cpScc to ensure 68020+68851, 68030
3531 int m_fscc(WORD inst, WORD siz)
3535 // We stash the 5 condition bits inside the opcode in 68ktab (bits 4-0),
3536 // so we need to extract them first and fill in the clobbered bits.
3537 WORD opcode = inst & 0x1F;
3539 inst |= am0 | a0reg;
3543 if (activefpu == FPU_68060)
3544 warn("Instruction is emulated in 68060");
3550 // fsgldiv (6888X, 68040FPSP, 68060FPSP)
3552 int m_fsgldiv(WORD inst, WORD siz)
3555 return gen_fpu(inst, siz, B8(00100100), FPU_FPSP);
3560 // fsglmul (6888X, 68040, 68060FPSP)
3562 int m_fsglmul(WORD inst, WORD siz)
3565 return gen_fpu(inst, siz, B8(00100111), FPU_FPSP);
3570 // fsin (6888X, 68040FPSP, 68060FPSP)
3572 int m_fsin(WORD inst, WORD siz)
3575 return gen_fpu(inst, siz, B8(00001110), FPU_FPSP);
3580 // fsincos (6888X, 68040FPSP, 68060FPSP)
3582 int m_fsincos(WORD inst, WORD siz)
3586 // Swap a1reg, a2reg as a2reg should be stored in the bitfield gen_fpu
3593 if (gen_fpu(inst, siz, B8(00110000), FPU_FPSP) == OK)
3604 // fsinh (6888X, 68040FPSP, 68060FPSP)
3606 int m_fsinh(WORD inst, WORD siz)
3609 return gen_fpu(inst, siz, B8(00000010), FPU_FPSP);
3614 // fsqrt (6888X, 68040, 68060)
3616 int m_fsqrt(WORD inst, WORD siz)
3619 return gen_fpu(inst, siz, B8(00000100), FPU_NOWARN);
3624 // fsfsqrt (68040, 68060)
3626 int m_fsfsqrt(WORD inst, WORD siz)
3628 if (activefpu & (FPU_68040 | FPU_68060))
3629 return gen_fpu(inst, siz, B8(01000001), FPU_NOWARN);
3631 return error("Unsupported in current FPU");
3636 // fdfsqrt (68040, 68060)
3638 int m_fdfsqrt(WORD inst, WORD siz)
3640 if (activefpu & (FPU_68040 | FPU_68060))
3641 return gen_fpu(inst, siz, B8(01000101), FPU_NOWARN);
3643 return error("Unsupported in current FPU");
3648 // fsub (6888X, 68040, 68060)
3650 int m_fsub(WORD inst, WORD siz)
3653 return gen_fpu(inst, siz, B8(00101000), FPU_NOWARN);
3658 // fsfsub (68040, 68060)
3660 int m_fsfsub(WORD inst, WORD siz)
3662 if (activefpu & (FPU_68040 | FPU_68060))
3663 return gen_fpu(inst, siz, B8(01101000), FPU_NOWARN);
3665 return error("Unsupported in current FPU");
3670 // fdfsub (68040, 68060)
3672 int m_fdsub(WORD inst, WORD siz)
3674 if (activefpu & (FPU_68040 | FPU_68060))
3675 return gen_fpu(inst, siz, B8(01101100), FPU_NOWARN);
3677 return error("Unsupported in current FPU");
3682 // ftan (6888X, 68040FPSP, 68060FPSP)
3684 int m_ftan(WORD inst, WORD siz)
3687 return gen_fpu(inst, siz, B8(00001111), FPU_FPSP);
3692 // ftanh (6888X, 68040FPSP, 68060FPSP)
3694 int m_ftanh(WORD inst, WORD siz)
3697 return gen_fpu(inst, siz, B8(00001001), FPU_FPSP);
3702 // ftentox (6888X, 68040FPSP, 68060FPSP)
3704 int m_ftentox(WORD inst, WORD siz)
3707 return gen_fpu(inst, siz, B8(00010010), FPU_FPSP);
3712 // FTRAPcc (6888X, 68040, 68060FPSP)
3714 int m_ftrapcc(WORD inst, WORD siz)
3718 // We stash the 5 condition bits inside the opcode in 68ktab (bits 3-7),
3719 // so we need to extract them first and fill in the clobbered bits.
3720 WORD opcode = (inst >> 3) & 0x1F;
3721 inst = (inst & 0xFF07) | (0xF << 3);
3730 else if (siz == SIZL)
3737 else if (siz == SIZN)
3745 if (activefpu == FPU_68060)
3746 warn("Instruction is emulated in 68060");
3753 // ftst (6888X, 68040, 68060)
3755 int m_ftst(WORD inst, WORD siz)
3758 return gen_fpu(inst, siz, B8(00111010), FPU_NOWARN);
3763 // ftwotox (6888X, 68040FPSP, 68060FPSP)
3765 int m_ftwotox(WORD inst, WORD siz)
3768 return gen_fpu(inst, siz, B8(00010001), FPU_FPSP);
3772 /////////////////////////////////
3774 // 68060 specific instructions //
3776 /////////////////////////////////
3782 int m_lpstop(WORD inst, WORD siz)
3785 D_word(B16(00000001, 11000000));
3787 if (a0exattr & DEFINED)
3793 AddFixup(FU_WORD, sloc, a0expr);
3804 int m_plpa(WORD inst, WORD siz)
3807 inst |= a0reg; // Install register