2 // RMAC - Reboot's Macro Assembler for all Atari computers
3 // MACH.C - Code Generation
4 // Copyright (C) 199x Landon Dyer, 2011-2017 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), m_bad6mode(WORD, WORD), m_bad6inst(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);
78 int m_pbcc(WORD inst, WORD siz);
79 int m_pflusha(WORD inst, WORD siz);
80 int m_pflush(WORD inst, WORD siz);
81 int m_pflushr(WORD inst, WORD siz);
82 int m_pload(WORD inst, WORD siz, WORD extension);
83 int m_pmove(WORD inst, WORD siz);
84 int m_pmovefd(WORD inst, WORD siz);
85 int m_ptest(WORD inst, WORD siz);
86 int m_ptrapcc(WORD inst, WORD siz);
87 int m_ploadr(WORD inst, WORD siz);
88 int m_ploadw(WORD inst, WORD siz);
91 int m_fabs(WORD inst, WORD siz);
92 int m_facos(WORD inst, WORD siz);
93 int m_fadd(WORD inst, WORD siz);
94 int m_fasin(WORD inst, WORD siz);
95 int m_fatan(WORD inst, WORD siz);
96 int m_fatanh(WORD inst, WORD siz);
97 int m_fcmp(WORD inst, WORD siz);
98 int m_fcos(WORD inst, WORD siz);
99 int m_fcosh(WORD inst, WORD siz);
100 int m_fdabs(WORD inst, WORD siz);
101 int m_fdadd(WORD inst, WORD siz);
102 int m_fdbcc(WORD inst, WORD siz);
103 int m_fddiv(WORD inst, WORD siz);
104 int m_fdfsqrt(WORD inst, WORD siz);
105 int m_fdiv(WORD inst, WORD siz);
106 int m_fdmove(WORD inst, WORD siz);
107 int m_fdmul(WORD inst, WORD siz);
108 int m_fdneg(WORD inst, WORD siz);
109 int m_fdsub(WORD inst, WORD siz);
110 int m_fetox(WORD inst, WORD siz);
111 int m_fetoxm1(WORD inst, WORD siz);
112 int m_fgetexp(WORD inst, WORD siz);
113 int m_fgetman(WORD inst, WORD siz);
114 int m_fint(WORD inst, WORD siz);
115 int m_fintrz(WORD inst, WORD siz);
116 int m_flog10(WORD inst, WORD siz);
117 int m_flog2(WORD inst, WORD siz);
118 int m_flogn(WORD inst, WORD siz);
119 int m_flognp1(WORD inst, WORD siz);
120 int m_fmod(WORD inst, WORD siz);
121 int m_fmove(WORD inst, WORD siz);
122 int m_fmovescr(WORD inst, WORD siz);
123 int m_fmovecr(WORD inst, WORD siz);
124 int m_fmovem(WORD inst, WORD siz);
125 int m_fmul(WORD inst, WORD siz);
126 int m_fneg(WORD inst, WORD siz);
127 int m_fnop(WORD inst, WORD siz);
128 int m_frem(WORD inst, WORD siz);
129 int m_frestore(WORD inst, WORD siz);
130 int m_fsabs(WORD inst, WORD siz);
131 int m_fsadd(WORD inst, WORD siz);
132 int m_fscc(WORD inst, WORD siz);
133 int m_fscale(WORD inst, WORD siz);
134 int m_fsdiv(WORD inst, WORD siz);
135 int m_fsfsqrt(WORD inst, WORD siz);
136 int m_fsfsub(WORD inst, WORD siz);
137 int m_fsgldiv(WORD inst, WORD siz);
138 int m_fsglmul(WORD inst, WORD siz);
139 int m_fsin(WORD inst, WORD siz);
140 int m_fsincos(WORD inst, WORD siz);
141 int m_fsinh(WORD inst, WORD siz);
142 int m_fsmove(WORD inst, WORD siz);
143 int m_fsmul(WORD inst, WORD siz);
144 int m_fsneg(WORD inst, WORD siz);
145 int m_fsqrt(WORD inst, WORD siz);
146 int m_fsub(WORD inst, WORD siz);
147 int m_ftan(WORD inst, WORD siz);
148 int m_ftanh(WORD inst, WORD siz);
149 int m_ftentox(WORD inst, WORD siz);
150 int m_ftst(WORD inst, WORD siz);
151 int m_ftwotox(WORD inst, WORD siz);
152 int m_ftrapcc(WORD inst, WORD siz);
154 // Common error messages
155 char range_error[] = "expression out of range";
156 char abs_error[] = "illegal absolute expression";
157 char seg_error[] = "bad (section) expression";
158 char rel_error[] = "illegal relative address";
159 char siz_error[] = "bad size specified";
160 char undef_error[] = "undefined expression";
161 char fwd_error[] = "forward or undefined expression";
162 char unsupport[] = "unsupported for selected CPU";
164 // Include code tables
166 { 0xFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000, 0, m_badmode }, // 0
168 { 0, 0L, 0L, 0x0000, 0, m_unimp } // Last entry
171 // Register number << 9
173 0, 1 << 9, 2 << 9, 3 << 9, 4 << 9, 5 << 9, 6 << 9, 7 << 9
176 // SIZB==>00, SIZW==>01, SIZL==>10, SIZN==>01 << 6
180 1<<6, (WORD)-1, // SIZW, n/a
181 2<<6, (WORD)-1, (WORD)-1, (WORD)-1, // SIZL, n/a, n/a, n/a
185 // Byte/word/long size for MOVE instrs
189 0x3000, (WORD)-1, // Word
190 0x2000, (WORD)-1, (WORD)-1, (WORD)-1, // Long
191 0x3000 // Word (SIZN)
194 // Word/long size (0=.w, 1=.l) in bit 8
198 0, (WORD)-1, // SIZW, n/a
199 1<<8, (WORD)-1, (WORD)-1, (WORD)-1, // SIZL, n/a, n/a, n/a
203 // Byte/Word/long size (0=.w, 1=.l) in bit 9
207 1<<9, (WORD)-1, // Word
208 1<<10, (WORD)-1, (WORD)-1, (WORD)-1, // Long
212 // Addressing mode in bits 6..11 (register/mode fields are reversed)
214 00000, 01000, 02000, 03000, 04000, 05000, 06000, 07000,
215 00100, 01100, 02100, 03100, 04100, 05100, 06100, 07100,
216 00200, 01200, 02200, 03200, 04200, 05200, 06200, 07200,
217 00300, 01300, 02300, 03300, 04300, 05300, 06300, 07300,
218 00400, 01400, 02400, 03400, 04400, 05400, 06400, 07400,
219 00500, 01500, 02500, 03500, 04500, 05500, 06500, 07500,
220 00600, 01600, 02600, 03600, 04600, 05600, 06600, 07600,
221 00700, 01700, 02700, 03700, 04700, 05700, 06700, 07700
224 // Control registers lookup table
226 // MC68010/MC68020/MC68030/MC68040/CPU32
227 0x000, // Source Function Code(SFC)
228 0x001, // Destination Function Code(DFC)
229 0x800, // User Stack Pointer(USP)
230 0x801, // Vector Base Register(VBR)
231 // MC68020 / MC68030 / MC68040
232 0x002, // Cache Control Register(CACR)
233 0x802, // Cache Address Register(CAAR) (020/030 only)
234 0x803, // Master Stack Pointer(MSP)
235 0x804, // Interrupt Stack Pointer(ISP)
236 // MC68040 / MC68LC040
237 0x003, // MMU Translation Control Register(TC)
238 0x004, // Instruction Transparent Translation Register 0 (ITT0)
239 0x005, // Instruction Transparent Translation Register 1 (ITT1)
240 0x006, // Data Transparent Translation Register 0 (DTT0)
241 0x007, // Data Transparent Translation Register 1 (DTT1)
242 0x805, // MMU Status Register(MMUSR)
243 0x806, // User Root Pointer(URP)
244 0x807, // Supervisor Root Pointer(SRP)
246 0x004, // Instruction Access Control Register 0 (IACR0)
247 0x005, // Instruction Access Control Register 1 (IACR1)
248 0x006, // Data Access Control Register 0 (DACR1)
249 0x007, // Data Access Control Register 1 (DACR1)
251 0xFFF // CPU Root Pointer (CRP) - There's no movec with CRP in it, this is just a guard entry
256 int m_unimp(WORD unused1, WORD unused2)
258 return (int)error("unimplemented mnemonic");
262 //int m_badmode(void)
263 int m_badmode(WORD unused1, WORD unused2)
265 return (int)error("inappropriate addressing mode");
269 int m_self(WORD inst, WORD usused)
277 // Do one EA in bits 0..5
279 // Bits in `inst' have the following meaning:
281 // Bit zero specifies which ea (ea0 or ea1) to generate in the lower six bits
284 // If bit one is set, the OTHER ea (the one that wasn't generated by bit zero)
285 // is generated after the instruction. Regardless of bit 0's value, ea0 is
286 // always deposited in memory before ea1.
288 // If bit two is set, standard size bits are set in the instr in bits 6 and 7.
290 // If bit four is set, bit three specifies which eaXreg to place in bits 9..11
293 int m_ea(WORD inst, WORD siz)
295 WORD flg = inst; // Save flag bits
296 inst &= ~0x3F; // Clobber flag bits in instr
298 // Install "standard" instr size bits
304 // OR-in register number
306 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
308 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
314 inst |= am1 | a1reg; // Get ea1 into instr
315 D_word(inst); // Deposit instr
317 // Generate ea0 if requested
321 ea1gen(siz); // Generate ea1
326 inst |= am0 | a0reg; // Get ea0 into instr
327 D_word(inst); // Deposit instr
328 ea0gen(siz); // Generate ea0
330 // Generate ea1 if requested
340 // Check if lea x(an),an can be optimised to addq.w #x,an--otherwise fall back
343 int m_lea(WORD inst, WORD siz)
345 if (CHECK_OPTS(OPT_LEA_ADDQ)
346 && ((am0 == ADISP) && (a0reg == a1reg) && (a0exattr & DEFINED))
347 && ((a0exval > 0) && (a0exval <= 8)))
349 inst = B16(01010000, 01001000) | (((uint16_t)a0exval & 7) << 9) | (a0reg);
351 warn("lea size(An),An converted to addq #size,An");
355 return m_ea(inst, siz);
359 int m_ea030(WORD inst, WORD siz)
362 WORD flg = inst; // Save flag bits
363 inst &= ~0x3F; // Clobber flag bits in instr
365 // Install "standard" instr size bits
371 // OR-in register number
374 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
378 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
385 inst |= am1 | a1reg; // Get ea1 into instr
386 D_word(inst); // Deposit instr
388 // Generate ea0 if requested
392 ea1gen(siz); // Generate ea1
398 // We get here if we're doing 020+ addressing and an address
399 // register is used. For example, something like "tst a0". A bit of
400 // a corner case, so kludge it
402 else if (am0 == PCDISP)
403 //Another corner case (possibly!), so kludge ahoy
404 inst |= am0; // Get ea0 into instr
405 else if (am0 == IMMED)
406 inst |= am0 | a0reg; // Get ea0 into instr
407 else if (am0 == AM_CCR)
409 else if (am0 == AIND)
412 inst |= a0reg; // Get ea0 into instr
413 D_word(inst); // Deposit instr
414 ea0gen(siz); // Generate ea0
416 // Generate ea1 if requested
426 // Dx,Dy nnnnXXXnssnnnYYY If bit 0 of `inst' is set, install size bits in bits
429 int m_abcd(WORD inst, WORD siz)
438 inst |= a0reg | reg_9[a1reg];
448 int m_adda(WORD inst, WORD siz)
450 if (a0exattr & DEFINED)
452 if (CHECK_OPTS(OPT_ADDA_ADDQ))
453 if (a0exval > 1 && a0exval <= 8)
454 // Immediate is between 1 and 8 so let's convert to addq
455 return m_addq(B16(01010000, 00000000), siz);
456 if (CHECK_OPTS(OPT_ADDA_LEA))
459 // Immediate is larger than 8 so let's convert to lea
460 am0 = ADISP; // Change addressing mode
461 a0reg = a1reg; // In ADISP a0reg is used instead of a1reg!
462 return m_lea(B16(01000001, 11011000), SIZW);
466 inst |= am0 | a0reg | lwsiz_8[siz] | reg_9[a1reg];
468 ea0gen(siz); // Generate EA
475 // If bit 0 of `inst' is 1, install size bits in bits 6..7 of instr.
476 // If bit 1 of `inst' is 1, install a1reg in bits 9..11 of instr.
478 int m_reg(WORD inst, WORD siz)
485 // Install other register (9..11)
486 inst |= reg_9[a1reg];
488 inst &= ~7; // Clear off crufty bits
489 inst |= a0reg; // Install first register
499 int m_imm(WORD inst, WORD siz)
511 int m_imm8(WORD inst, WORD siz)
524 int m_shr(WORD inst, WORD siz)
526 inst |= reg_9[a0reg] | a1reg | siz_6[siz];
536 int m_shi(WORD inst, WORD siz)
538 inst |= a1reg | siz_6[siz];
540 if (a0exattr & DEFINED)
543 return error(range_error);
545 inst |= (a0exval & 7) << 9;
550 AddFixup(FU_QUICK, sloc, a0expr);
559 // {bset, btst, bchg, bclr} -- #immed,ea -- Dn,ea
561 int m_bitop(WORD inst, WORD siz)
563 // Enforce instruction sizes
565 { // X,Dn must be .n or .l
566 if (siz & (SIZB | SIZW))
567 return error(siz_error);
569 else if (siz & (SIZW | SIZL)) // X,ea must be .n or .b
570 return error(siz_error);
572 // Construct instr and EAs
578 ea0gen(SIZB); // Immediate bit number
582 inst |= reg_9[a0reg];
593 int m_dbra(WORD inst, WORD siz)
599 if (a1exattr & DEFINED)
601 if ((a1exattr & TDB) != cursect)
602 return error(rel_error);
604 uint32_t v = a1exval - sloc;
606 if (v + 0x8000 > 0x10000)
607 return error(range_error);
613 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
624 int m_exg(WORD inst, WORD siz)
630 if (am0 == DREG && am1 == DREG)
632 else if (am0 == AREG && am1 == AREG)
638 m = a1reg; // Get AREG into a1reg
646 inst |= m | reg_9[a0reg] | a1reg;
656 int m_link(WORD inst, WORD siz)
660 // Is this an error condition???
665 inst &= ~((3 << 9) | (1 << 6) | (1 << 4));
677 WORD extra_addressing[16]=
679 0, // 0100 (bd,An,Xn)
680 0, // 0101 ([bd,An],Xn,od)
681 0x180, // 0102 ([bc,An,Xn],od) (111 110 110 111)
682 0, // 0103 (bd,PC,Xn)
683 0, // 0104 ([bd,PC],Xn,od)
684 0, // 0105 ([bc,PC,Xn],od)
699 // Handle MOVE <C_ALL> <C_ALTDATA>
700 // MOVE <C_ALL> <M_AREG>
702 // Optimize MOVE.L #<smalldata>,D0 to a MOVEQ
704 int m_move(WORD inst, WORD size)
706 // Cast the passed in value to an int
709 // Try to optimize to MOVEQ
710 // N.B.: We can get away with casting the uint64_t to a 32-bit value
711 // because it checks for a SIZL (i.e., a 32-bit value).
712 if (CHECK_OPTS(OPT_MOVEL_MOVEQ)
713 && (siz == SIZL) && (am0 == IMMED) && (am1 == DREG)
714 && ((a0exattr & (TDB | DEFINED)) == DEFINED)
715 && ((uint32_t)a0exval + 0x80 < 0x100))
717 m_moveq((WORD)0x7000, (WORD)0);
720 warn("move.l #size,dx converted to moveq");
724 if ((am0 < ABASE) && (am1 < ABASE)) // 68000 modes
726 inst |= siz_12[siz] | am_6[am1] | reg_9[a1reg] | am0 | a0reg;
734 ea1gen((WORD)siz | 0x8000); // Tell ea1gen we're move ea,ea
738 inst |= siz_12[siz] | reg_9[a1reg] | extra_addressing[am0 - ABASE];
755 // Handle MOVE <C_ALL030> <C_ALTDATA>
756 // MOVE <C_ALL030> <M_AREG>
758 int m_move30(WORD inst, WORD size)
761 // TODO: is extra_addressing necessary/correct?
762 //inst |= siz_12[siz] | reg_9[a1reg & 7] | a0reg | extra_addressing[am0 - ABASE];
763 inst |= siz_12[siz] | reg_9[a1reg & 7] | a0reg;
778 // move USP,An -- move An,USP
780 int m_usp(WORD inst, WORD siz)
785 inst |= a1reg; // USP, An
787 inst |= a0reg; // An, USP
798 int m_moveq(WORD inst, WORD siz)
802 // Arrange for future fixup
803 if (!(a0exattr & DEFINED))
805 AddFixup(FU_BYTE | FU_SEXT, sloc + 1, a0expr);
808 else if ((uint32_t)a0exval + 0x100 >= 0x200)
809 return error(range_error);
811 inst |= reg_9[a1reg] | (a0exval & 0xFF);
819 // movep Dn, disp(An) -- movep disp(An), Dn
821 int m_movep(WORD inst, WORD siz)
823 // Tell ea0gen to lay off the 0(a0) optimisations on this one
831 inst |= reg_9[a0reg] | a1reg;
841 inst |= reg_9[a1reg] | a0reg;
858 int m_br(WORD inst, WORD siz)
860 if (a0exattr & DEFINED)
862 if ((a0exattr & TDB) != cursect)
864 //printf("m_br(): a0exattr = %X, cursect = %X, a0exval = %X, sloc = %X\n", a0exattr, cursect, a0exval, sloc);
865 return error(rel_error);
868 uint32_t v = (uint32_t)a0exval - (sloc + 2);
870 // Optimize branch instr. size
873 if (CHECK_OPTS(OPT_BSR_BCC_S) && (v != 0) && ((v + 0x80) < 0x100))
880 warn("Bcc.w/BSR.w converted to .s");
887 if ((v + 0x8000) > 0x10000)
888 return error(range_error);
896 if (siz == SIZB || siz == SIZS)
898 if ((v + 0x80) >= 0x100)
899 return error(range_error);
906 if ((v + 0x8000) >= 0x10000)
907 return error(range_error);
915 else if (siz == SIZN)
918 if (siz == SIZB || siz == SIZS)
921 AddFixup(FU_BBRA | FU_PCREL | FU_SEXT, sloc, a0expr);
929 AddFixup(FU_WORD | FU_PCREL | FU_LBRA | FU_ISBRA, sloc, a0expr);
940 int m_addq(WORD inst, WORD siz)
942 inst |= siz_6[siz] | am1 | a1reg;
944 if (a0exattr & DEFINED)
946 if ((a0exval > 8) || (a0exval == 0)) // Range in 1..8
947 return error(range_error);
949 inst |= (a0exval & 7) << 9;
954 AddFixup(FU_QUICK, sloc, a0expr);
967 int m_trap(WORD inst, WORD siz)
971 if (a0exattr & DEFINED)
974 return error(abs_error);
977 return error(range_error);
983 return error(undef_error);
990 // movem <rlist>,ea -- movem ea,<rlist>
992 int m_movem(WORD inst, WORD siz)
1000 return error("bad size suffix");
1007 // Handle #<expr>, ea
1010 if (abs_expr(&eval) != OK)
1013 if (eval >= 0x10000L)
1014 return error(range_error);
1020 if ((*tok >= KW_D0) && (*tok <= KW_A7))
1023 if (reglist(&rmask) < 0)
1028 return error("missing comma");
1033 inst |= am0 | a0reg;
1035 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
1036 return error("invalid addressing mode");
1038 // If APREDEC, reverse register mask
1044 for(i=0x8000; i; i>>=1, w>>=1)
1045 rmask = (WORD)((rmask << 1) | w & 1);
1054 inst |= 0x0400 | am0 | a0reg;
1057 return error("missing comma");
1060 return error("missing register list");
1067 if (abs_expr(&eval) != OK)
1070 if (eval >= 0x10000)
1071 return error(range_error);
1075 else if (reglist(&rmask) < 0)
1078 if (!(amsktab[am0] & (C_CTRL | M_APOSTINC)))
1079 return error("invalid addressing mode");
1091 // CLR.x An ==> SUBA.x An,An
1093 int m_clra(WORD inst, WORD siz)
1095 inst |= a0reg | reg_9[a0reg] | lwsiz_8[siz];
1103 // CLR.L Dn ==> CLR.L An or MOVEQ #0,Dx
1105 int m_clrd(WORD inst, WORD siz)
1107 if (!CHECK_OPTS(OPT_CLR_DX))
1110 inst = (a0reg << 9) | B16(01110000, 00000000);
1118 ////////////////////////////////////////
1120 // 68020/30/40/60 instructions
1122 ////////////////////////////////////////
1127 int m_br30(WORD inst, WORD siz)
1129 if (a0exattr & DEFINED)
1131 if ((a0exattr & TDB) != cursect)
1132 return error(rel_error);
1134 uint32_t v = (uint32_t)a0exval - (sloc + 2);
1143 AddFixup(FU_LONG | FU_PCREL | FU_SEXT, sloc, a0expr);
1151 // bfchg, bfclr, bfexts, bfextu, bfffo, bfins, bfset
1152 // (68020, 68030, 68040)
1154 int m_bfop(WORD inst, WORD siz)
1156 if ((bfval1 > 31) || (bfval1 < 0))
1157 return error("bfxxx offset: immediate value must be between 0 and 31");
1159 // First instruction word - just the opcode and first EA
1160 // Note: both am1 is ORed because solely of bfins - maybe it's a good idea
1161 // to make a dedicated function for it?
1168 if (bfval2 > 31 || bfval2 < 0)
1169 return error("bfxxx width: immediate value must be between 0 and 31");
1171 // For Dw both immediate and register number are stuffed
1172 // into the same field O_o
1173 bfparam2 = (bfval2 << 0);
1177 bfparam1 = (bfval1 << 6);
1179 bfparam1 = bfval1 << 12;
1181 D_word((inst | am0 | a0reg | am1 | a1reg));
1182 ea0gen(siz); // Generate EA
1184 // Second instruction word - Dest register (if exists), Do, Offset, Dw, Width
1185 inst = bfparam1 | bfparam2;
1191 inst |= a0reg << 12;
1200 // bkpt (68EC000, 68010, 68020, 68030, 68040, CPU32)
1202 int m_bkpt(WORD inst, WORD siz)
1206 if (a0exattr & DEFINED)
1209 return error(abs_error);
1212 return error(range_error);
1218 return error(undef_error);
1227 int m_callm(WORD inst, WORD siz)
1234 if (a0exattr & DEFINED)
1237 return error(abs_error);
1240 return error(range_error);
1242 inst = (uint16_t)a0exval;
1246 return error(undef_error);
1256 // cas (68020, 68030, 68040)
1258 int m_cas(WORD inst, WORD siz)
1264 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1265 return error(unsupport);
1280 return error("bad size suffix");
1285 if ((*tok < KW_D0) && (*tok > KW_D7))
1286 return error("CAS accepts only data registers");
1288 inst2 = (*tok++) & 7;
1291 return error("missing comma");
1294 if ((*tok < KW_D0) && (*tok > KW_D7))
1295 return error("CAS accepts only data registers");
1297 inst2 |= ((*tok++) & 7) << 6;
1300 return error("missing comma");
1303 if ((modes = amode(1)) < 0)
1307 return error("too many ea fields");
1310 return error("extra (unexpected) text found");
1312 // Reject invalid ea modes
1313 amsk = amsktab[am0];
1315 if ((amsk & (M_AIND | M_APOSTINC | M_APREDEC | M_ADISP | M_AINDEXED | M_ABSW | M_ABSL | M_ABASE | M_MEMPOST | M_MEMPRE)) == 0)
1316 return error("unsupported addressing mode");
1318 inst |= am0 | a0reg;
1328 // cas2 (68020, 68030, 68040)
1330 int m_cas2(WORD inst, WORD siz)
1334 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1335 return error(unsupport);
1350 return error("bad size suffix");
1355 if ((*tok < KW_D0) && (*tok > KW_D7))
1356 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1358 inst2 = (*tok++) & 7;
1361 return error("missing colon");
1364 if ((*tok < KW_D0) && (*tok > KW_D7))
1365 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1367 inst3 = (*tok++) & 7;
1370 return error("missing comma");
1373 if ((*tok < KW_D0) && (*tok > KW_D7))
1374 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1376 inst2 |= ((*tok++) & 7) << 6;
1379 return error("missing colon");
1382 if ((*tok < KW_D0) && (*tok > KW_D7))
1383 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1385 inst3 |= ((*tok++) & 7) << 6;
1388 return error("missing comma");
1392 return error("missing (");
1393 if ((*tok >= KW_D0) && (*tok <= KW_D7))
1394 inst2 |= (((*tok++) & 7) << 12) | (0 << 15);
1395 else if ((*tok >= KW_A0) && (*tok <= KW_A7))
1396 inst2 |= (((*tok++) & 7) << 12) | (1 << 15);
1398 return error("CAS accepts either data or address registers for Rn1:Rn2 pair");
1401 return error("missing (");
1404 return error("missing colon");
1408 return error("missing (");
1409 if ((*tok >= KW_D0) && (*tok <= KW_D7))
1410 inst3 |= (((*tok++) & 7) << 12) | (0 << 15);
1411 else if ((*tok >= KW_A0) && (*tok <= KW_A7))
1412 inst3 |= (((*tok++) & 7) << 12) | (1 << 15);
1414 return error("CAS accepts either data or address registers for Rn1:Rn2 pair");
1417 return error("missing (");
1420 return error("extra (unexpected) text found");
1431 // cmp2 (68020, 68030, 68040, CPU32)
1433 int m_cmp2(WORD inst, WORD siz)
1435 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1436 return error(unsupport);
1438 switch (siz & 0x000F)
1452 WORD flg = inst; // Save flag bits
1453 inst &= ~0x3F; // Clobber flag bits in instr
1455 // Install "standard" instr size bits
1461 // OR-in register number
1463 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1465 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1471 inst |= am1 | a1reg; // Get ea1 into instr
1472 D_word(inst); // Deposit instr
1474 // Generate ea0 if requested
1478 ea1gen(siz); // Generate ea1
1483 inst |= am0 | a0reg; // Get ea0 into instr
1484 D_word(inst); // Deposit instr
1485 ea0gen(siz); // Generate ea0
1487 // Generate ea1 if requested
1492 // If we're called from chk2 then bit 11 of size will be set. This is just
1493 // a dumb mechanism to pass this, required by the extension word. (You might
1494 // have noticed the siz & 15 thing above!)
1495 inst = (a1reg << 12) | (siz & (1 << 11));
1507 // chk2 (68020, 68030, 68040, CPU32)
1509 int m_chk2(WORD inst, WORD siz)
1511 return m_cmp2(inst, siz | (1 << 11));
1516 // cpbcc(68020, 68030)
1518 int m_cpbr(WORD inst, WORD siz)
1520 if ((activecpu & (CPU_68020 | CPU_68030)) == 0)
1521 return error(unsupport);
1523 if (a0exattr & DEFINED)
1525 if ((a0exattr & TDB) != cursect)
1526 return error(rel_error);
1528 uint32_t v = (uint32_t)a0exval - (sloc + 2);
1530 // Optimize branch instr. size
1533 if ((v != 0) && ((v + 0x8000) < 0x10000))
1543 if ((v + 0x8000) >= 0x10000)
1544 return error(range_error);
1552 else if (siz == SIZN)
1559 AddFixup(FU_LONG | FU_PCREL | FU_SEXT, sloc, a0expr);
1567 AddFixup(FU_WORD | FU_PCREL | FU_SEXT, sloc, a0expr);
1576 // cpdbcc(68020, 68030)
1578 int m_cpdbr(WORD inst, WORD siz)
1583 WORD condition = inst & 0x1F; // Grab condition sneakily placed in the lower 5 bits of inst
1584 inst &= 0xFFE0; // And then mask them out - you ain't seen me, roit?
1586 inst |= (1 << 9); // Bolt on FPU id
1593 if (a1exattr & DEFINED)
1595 if ((a1exattr & TDB) != cursect)
1596 return error(rel_error);
1598 v = (uint32_t)a1exval - sloc;
1600 if (v + 0x8000 > 0x10000)
1601 return error(range_error);
1607 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
1616 // muls.l / divs.l / divu.l / mulu.l (68020+)
1618 int m_muls(WORD inst, WORD siz)
1620 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1621 return error(unsupport);
1623 WORD flg = inst; // Save flag bits
1624 inst &= ~0x33F; // Clobber flag and extension bits in instr
1626 // Install "standard" instr size bits
1632 // OR-in register number
1634 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1636 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1639 // Regarding extension word: bit 11 is signed/unsigned selector
1640 // bit 10 is 32/64 bit selector
1641 // Both of these are packed in bits 9 and 8 of the instruction
1642 // field in 68ktab. Extra compilcations arise from the fact we
1643 // have to distinguish between divu/s.l Dn,Dm (which is encoded
1644 // as divu/s.l Dn,Dm:Dm) and divu/s.l Dn,Dm:Dx - the first is
1645 // 32 bit while the second 64 bit
1650 inst |= am1 | a1reg; // Get ea1 into instr
1651 D_word(inst); // Deposit instr
1655 inst = a1reg + (a2reg << 12) + ((flg & 0x200) << 2);
1657 inst = a1reg + (a2reg << 12) + ((flg & 0x300) << 2);
1661 // Generate ea0 if requested
1665 ea1gen(siz); // Generate ea1
1672 inst |= am0 | a0reg; // Get ea0 into instr
1673 D_word(inst); // Deposit instr
1677 inst = a1reg + (a2reg << 12) + ((flg & 0x200) << 2);
1679 inst = a1reg + (a2reg << 12) + ((flg & 0x300) << 2);
1683 ea0gen(siz); // Generate ea0
1685 // Generate ea1 if requested
1695 // move16 (ax)+,(ay)+
1697 int m_move16a(WORD inst, WORD siz)
1699 if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1700 return error(unsupport);
1704 inst = (1 << 15) + (a1reg << 12);
1712 // move16 with absolute address
1714 int m_move16b(WORD inst, WORD siz)
1716 if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1717 return error(unsupport);
1723 if (am0 == APOSTINC)
1726 return error("Wasn't this suppose to call m_move16a???");
1729 //move16 (ax)+,(xxx).L
1734 else if (am0 == ABSL)
1738 //move16 (xxx).L,(ax)+
1744 //move16 (xxx).L,(ax)
1749 else if (am0 == AIND)
1751 //move16 (ax),(xxx).L
1764 // pack/unpack (68020/68030/68040)
1766 int m_pack(WORD inst, WORD siz)
1771 return error("bad size suffix");
1773 if (*tok >= KW_D0 && *tok <= KW_D7)
1775 // Dx,Dy,#<adjustment>
1776 inst |= (0 << 3); // R/M
1777 inst |= (*tok++ & 7);
1779 if (*tok != ',' && tok[2] != ',')
1780 return error("missing comma");
1782 if (tok[1] < KW_D0 && tok[1] > KW_D7)
1783 return error(syntax_error);
1785 inst |= ((tok[1] & 7)<<9);
1788 // Fall through for adjustment (common in both valid cases)
1790 else if (*tok == '-')
1792 // -(Ax),-(Ay),#<adjustment>
1793 inst |= (1 << 3); // R/M
1794 tok++; // eat the minus
1796 if ((*tok != '(') && (tok[2]!=')') && (tok[3]!=',') && (tok[4] != '-') && (tok[5] != '(') && (tok[7] != ')') && (tok[8] != ','))
1797 return error(syntax_error);
1799 if (tok[1] < KW_A0 && tok[1] > KW_A7)
1800 return error(syntax_error);
1802 if (tok[5] < KW_A0 && tok[6] > KW_A7)
1803 return error(syntax_error);
1805 inst |= ((tok[1] & 7) << 0);
1806 inst |= ((tok[6] & 7) << 9);
1809 // Fall through for adjustment (common in both valid cases)
1812 return error("invalid syntax");
1814 if ((*tok != CONST) && (*tok != SYMBOL) && (*tok != '-'))
1815 return error(syntax_error);
1817 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
1820 if ((a0exattr & DEFINED) == 0)
1821 return error(undef_error);
1823 if (a0exval + 0x8000 > 0x10000)
1827 return error(extra_stuff);
1829 D_word((a0exval & 0xFFFF));
1838 int m_rtm(WORD inst, WORD siz)
1846 else if (am0 == AREG)
1848 inst |= (1 << 3) + a0reg;
1851 return error("rtm only allows data or address registers.");
1862 int m_rtd(WORD inst, WORD siz)
1866 if (a0exattr & DEFINED)
1869 return error(abs_error);
1871 if ((a0exval + 0x8000) <= 0x7FFF)
1872 return error(range_error);
1878 return error(undef_error);
1887 int m_trapcc(WORD inst, WORD siz)
1895 else if (am0 == IMMED)
1899 if (a0exval < 0x10000)
1906 return error("Immediate value too big");
1916 return error("Invalid parameter for trapcc");
1923 // cinvl/p/a (68040)
1925 int m_cinv(WORD inst, WORD siz)
1930 inst |= (0 << 6) | (a1reg);
1934 inst |= (2 << 6) | (a1reg);
1937 inst |= (1 << 6) | (a1reg);
1940 inst |= (3 << 6) | (a1reg);
1949 int m_fpusavrest(WORD inst, WORD siz)
1951 inst |= am0 | a0reg;
1960 // cpSAVE/cpRESTORE (68020, 68030)
1962 int m_cprest(WORD inst, WORD siz)
1964 if (activecpu & !(CPU_68020 | CPU_68030))
1965 return error(unsupport);
1967 return m_fpusavrest(inst, siz);
1973 // FSAVE/FRESTORE (68040, 68060)
1975 int m_frestore(WORD inst, WORD siz)
1977 if ((!(activecpu & (CPU_68040 | CPU_68060))) ||
1978 (activefpu&(FPU_68881 | FPU_68882)))
1979 return error(unsupport);
1981 return m_fpusavrest(inst, siz);
1986 // movec (68010, 68020, 68030, 68040, CPU32)
1988 int m_movec(WORD inst, WORD siz)
1992 if (am0 == DREG || am0 == AREG)
2000 inst = (0 << 15) + (a0reg << 12) + CREGlut[a1reg];
2005 inst = (1 << 15) + (a0reg << 12) + CREGlut[a1reg];
2016 inst = (0 << 15) + (a1reg << 12) + CREGlut[a0reg];
2021 inst = (1 << 15) + (a1reg << 12) + CREGlut[a0reg];
2031 // moves (68010, 68020, 68030, 68040, CPU32)
2033 int m_moves(WORD inst, WORD siz)
2035 if (activecpu & !(CPU_68020 | CPU_68030 | CPU_68040))
2036 return error(unsupport);
2040 else if (siz == SIZL)
2047 inst |= am1 | a1reg;
2049 inst = (a0reg << 12) | (1 << 11) | (0 << 15);
2052 else if (am0 == AREG)
2054 inst |= am1 | a1reg;
2056 inst = (a0reg << 12) | (1 << 11) | (1 << 15);
2063 inst |= am0 | a0reg;
2065 inst = (a1reg << 12) | (0 << 11) | (0 << 15);
2070 inst |= am0 | a0reg;
2072 inst = (a1reg << 12) | (0 << 11) | (1 << 15);
2084 int m_pbcc(WORD inst, WORD siz)
2087 return error("Not implemented yet.");
2092 // pflusha (68030, 68040)
2094 int m_pflusha(WORD inst, WORD siz)
2096 if (activecpu == CPU_68030)
2099 inst = (1 << 13) | (1 << 10) | (0 << 5) | 0;
2103 else if (activecpu == CPU_68040)
2105 inst = B16(11110101, 00011000);
2110 return error(unsupport);
2117 // pflush (68030, 68040, 68060)
2119 int m_pflush(WORD inst, WORD siz)
2121 if (activecpu == CPU_68030)
2124 // PFLUSH FC, MASK, < ea >
2132 if (*tok != CONST && *tok != SYMBOL)
2133 return error("function code should be an expression");
2135 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2138 if ((a0exattr & DEFINED) == 0)
2139 return error("function code immediate should be defined");
2141 if (a0exval > 7 && a0exval < 0)
2142 return error("function code out of range (0-7)");
2144 fc = (uint16_t)a0exval;
2154 fc = (1 << 4) | (*tok++ & 7);
2165 return error(syntax_error);
2169 return error("comma exptected");
2172 return error("mask should be an immediate value");
2174 if (*tok != CONST && *tok != SYMBOL)
2175 return error("mask is supposed to be immediate");
2177 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2180 if ((a0exattr & DEFINED) == 0)
2181 return error("mask immediate value should be defined");
2183 if (a0exval > 7 && a0exval < 0)
2184 return error("function code out of range (0-7)");
2186 mask = (uint16_t)a0exval << 5;
2192 inst = (1 << 13) | fc | mask | (4 << 10);
2196 else if (*tok == ',')
2198 // PFLUSH FC, MASK, < ea >
2201 if (amode(0) == ERROR)
2205 return error(extra_stuff);
2207 if (am0 == AIND || am0 == ABSW || am0 == ABSL || am0 == ADISP || am0 == ADISP || am0 == AINDEXED || am0 == ABASE || am0 == MEMPOST || am0 == MEMPRE)
2209 inst |= am0 | a0reg;
2211 inst = (1 << 13) | fc | mask | (6 << 10);
2217 return error("unsupported addressing mode");
2221 return error(syntax_error);
2225 else if (activecpu == CPU_68040 || activecpu == CPU_68060)
2229 if (*tok != '(' && tok[2] != ')')
2230 return error(syntax_error);
2232 if (tok[1] < KW_A0 && tok[1] > KW_A7)
2233 return error("expected (An)");
2235 if ((inst & 7) == 7)
2236 // With pflushn/pflush there's no easy way to distinguish between
2237 // the two in 68040 mode. Ideally the opcode bitfields would have
2238 // been hardcoded in 68ktab but there is aliasing between 68030
2239 // and 68040 opcode. So we just set the 3 lower bits to 1 in
2240 // pflushn inside 68ktab and detect it here.
2241 inst = (inst & 0xff8) | 8;
2243 inst |= (tok[1] & 7) | (5 << 8);
2246 return error(extra_stuff);
2251 return error(unsupport);
2260 int m_pflushr(WORD inst, WORD siz)
2264 WORD flg = inst; // Save flag bits
2265 inst &= ~0x3F; // Clobber flag bits in instr
2267 // Install "standard" instr size bits
2273 // OR-in register number
2275 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
2277 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
2283 inst |= am1 | a1reg; // Get ea1 into instr
2284 D_word(inst); // Deposit instr
2286 // Generate ea0 if requested
2290 ea1gen(siz); // Generate ea1
2295 inst |= am0 | a0reg; // Get ea0 into instr
2296 D_word(inst); // Deposit instr
2297 ea0gen(siz); // Generate ea0
2299 // Generate ea1 if requested
2304 D_word(B16(10100000, 00000000));
2310 // ploadr, ploadw (68030)
2312 int m_pload(WORD inst, WORD siz, WORD extension)
2314 // TODO: 68851 support is not added yet.
2315 // None of the ST series of computers had a 68020 + 68851 socket and since
2316 // this is an Atari targetted assembler...
2325 if (a0reg == KW_SFC - KW_SFC)
2327 else if (a0reg == KW_DFC - KW_SFC)
2330 return error("illegal control register specified");
2334 inst = (1 << 3) | a0reg;
2337 if ((a0exattr & DEFINED) == 0)
2338 return error("constant value must be defined");
2340 inst = (2 << 3) | (uint16_t)a0exval;
2344 inst |= extension | (1 << 13);
2353 int m_ploadr(WORD inst, WORD siz)
2355 return m_pload(inst, siz, 1 << 9);
2359 int m_ploadw(WORD inst, WORD siz)
2361 return m_pload(inst, siz, 0 << 9);
2366 // pmove (68030/68851)
2368 int m_pmove(WORD inst, WORD siz)
2372 // TODO: 68851 support is not added yet. None of the ST series of
2373 // computers had a 68020 + 68851 socket and since this is an Atari
2374 // targetted assembler.... (same for 68EC030)
2377 inst2 = inst & (1 << 8); // Copy the flush bit over to inst2 in case we're called from m_pmovefd
2378 inst &= ~(1 << 8); // And mask it out
2385 else if (am1 == CREG)
2391 return error("pmove sez: Wut?");
2393 // The instruction is a quad-word (8 byte) operation
2394 // for the CPU root pointer and the supervisor root pointer.
2395 // It is a long - word operation for the translation control register
2396 // and the transparent translation registers(TT0 and TT1).
2397 // It is a word operation for the MMU status register.
2399 if (((reg == (KW_URP - KW_SFC)) || (reg == (KW_SRP - KW_SFC)))
2400 && ((siz != SIZD) && (siz != SIZN)))
2401 return error(siz_error);
2403 if (((reg == (KW_TC - KW_SFC)) || (reg == (KW_TT0 - KW_SFC)) || (reg == (KW_TT1 - KW_SFC)))
2404 && ((siz != SIZL) && (siz != SIZN)))
2405 return error(siz_error);
2407 if ((reg == (KW_MMUSR - KW_SFC)) && ((siz != SIZW) && (siz != SIZN)))
2408 return error(siz_error);
2412 inst |= am1 | a1reg;
2415 else if (am1 == CREG)
2417 inst |= am0 | a0reg;
2421 switch (reg + KW_SFC)
2424 inst2 |= (0 << 10) + (1 << 14); break;
2426 inst2 |= (2 << 10) + (1 << 14); break;
2428 inst2 |= (3 << 10) + (1 << 14); break;
2430 inst2 |= (2 << 10) + (0 << 13); break;
2432 inst2 |= (3 << 10) + (0 << 13); break;
2435 inst2 |= (1 << 9) + (3 << 13);
2437 inst2 |= (0 << 9) + (3 << 13);
2440 return error("unsupported register");
2448 else if (am1 == CREG)
2458 int m_pmovefd(WORD inst, WORD siz)
2462 return m_pmove(inst | (1 << 8), siz);
2469 int m_ptrapcc(WORD inst, WORD siz)
2472 // We stash the 5 condition bits inside the opcode in 68ktab (bits 0-4),
2473 // so we need to extract them first and fill in the clobbered bits.
2474 WORD opcode = inst & 0x1F;
2475 inst = (inst & 0xFFE0) | (0x18);
2484 else if (siz == SIZL)
2491 else if (siz == SIZN)
2503 // ptestr, ptestw (68030)
2505 int m_ptest(WORD inst, WORD siz)
2509 if (activecpu == CPU_68030)
2510 return error("Not implemented yet.");
2511 else if (activecpu == CPU_68040)
2512 return error("Not implemented yet.");
2517 //////////////////////////////////////////////////////////////////////////////
2519 // 68020/30/40/60 instructions
2520 // Note: the map of which instructions are allowed on which CPUs came from the
2521 // 68060 manual, section D-1 (page 392 of the PDF). The current implementation
2522 // is missing checks for the EC models which have a simplified FPU.
2524 //////////////////////////////////////////////////////////////////////////////
2527 #define FPU_NOWARN 0
2532 // Generate a FPU opcode
2534 static inline int gen_fpu(WORD inst, WORD siz, WORD opmode, WORD emul)
2536 if (am0 < AM_NONE) // Check first operand for ea or fp - is this right?
2538 inst |= (1 << 9); // Bolt on FPU id
2541 //if (am0 == DREG || am0 == AREG)
2545 inst = 1 << 14; // R/M field (we have ea so have to set this to 1)
2549 case SIZB: inst |= (6 << 10); break;
2550 case SIZW: inst |= (4 << 10); break;
2551 case SIZL: inst |= (0 << 10); break;
2553 case SIZS: inst |= (1 << 10); break;
2554 case SIZD: inst |= (5 << 10); break;
2555 case SIZX: inst |= (2 << 10); break;
2560 warn("This encoding will cause an unimplemented data type exception in the MC68040 to allow emulation in software.");
2564 return error("Something bad happened, possibly, in gen_fpu.");
2568 inst |= (a1reg << 7);
2575 inst |= (1 << 9); // Bolt on FPU id
2579 inst |= (a1reg << 7);
2584 if ((emul & FPU_FPSP) && (activefpu == (FPU_68040 | FPU_68060)))
2585 warn("Instruction is emulated in 68040/060");
2592 // fabs (6888X, 68040FPSP, 68060FPSP)
2594 int m_fabs(WORD inst, WORD siz)
2597 return gen_fpu(inst, siz, B8(00011000), FPU_NOWARN);
2602 // fsabs (68040, 68060)
2604 int m_fsabs(WORD inst, WORD siz)
2607 if (activefpu == FPU_68040)
2608 return gen_fpu(inst, siz, B8(01011000), FPU_NOWARN);
2610 return error("Unsupported in current FPU");
2615 // fdabs (68040, 68060)
2617 int m_fdabs(WORD inst, WORD siz)
2619 if (activefpu == FPU_68040)
2620 return gen_fpu(inst, siz, B8(01011100), FPU_NOWARN);
2622 return error("Unsupported in current FPU");
2627 // facos (6888X, 68040FPSP, 68060FPSP)
2629 int m_facos(WORD inst, WORD siz)
2632 return gen_fpu(inst, siz, B8(00011100), FPU_FPSP);
2637 // fadd (6888X, 68040, 68060)
2639 int m_fadd(WORD inst, WORD siz)
2642 return gen_fpu(inst, siz, B8(00100010), FPU_NOWARN);
2647 // fsadd (68040, 68060)
2649 int m_fsadd(WORD inst, WORD siz)
2651 if (activefpu & (FPU_68040 | FPU_68060))
2652 return gen_fpu(inst, siz, B8(01100010), FPU_NOWARN);
2654 return error("Unsupported in current FPU");
2661 int m_fdadd(WORD inst, WORD siz)
2663 if (activefpu & (FPU_68040 | FPU_68060))
2664 return gen_fpu(inst, siz, B8(01100110), FPU_NOWARN);
2666 return error("Unsupported in current FPU");
2671 // fasin (6888X, 68040FPSP, 68060FPSP)
2673 int m_fasin(WORD inst, WORD siz)
2676 return gen_fpu(inst, siz, B8(00001100), FPU_FPSP);
2681 // fatan (6888X, 68040FPSP, 68060FPSP)
2683 int m_fatan(WORD inst, WORD siz)
2686 return gen_fpu(inst, siz, B8(00001010), FPU_FPSP);
2691 // fatanh (6888X, 68040FPSP, 68060FPSP)
2693 int m_fatanh(WORD inst, WORD siz)
2696 return gen_fpu(inst, siz, B8(00001101), FPU_FPSP);
2701 // fcmp (6888X, 68040, 68060)
2703 int m_fcmp(WORD inst, WORD siz)
2706 return gen_fpu(inst, siz, B8(00111000), FPU_FPSP);
2711 // fcos (6888X, 68040FPSP, 68060FPSP)
2713 int m_fcos(WORD inst, WORD siz)
2716 return gen_fpu(inst, siz, B8(00011101), FPU_FPSP);
2721 // fcosh (6888X, 68040FPSP, 68060FPSP)
2723 int m_fcosh(WORD inst, WORD siz)
2726 return gen_fpu(inst, siz, B8(00011001), FPU_FPSP);
2731 // fdbcc (6888X, 68040, 68060FPSP)
2733 int m_fdbcc(WORD inst, WORD siz)
2736 WORD opcode = inst & 0x3F; // Grab conditional bitfield
2746 if (a1exattr & DEFINED)
2748 if ((a1exattr & TDB) != cursect)
2749 return error(rel_error);
2751 uint32_t v = (uint32_t)a1exval - sloc;
2753 if ((v + 0x8000) > 0x10000)
2754 return error(range_error);
2760 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
2764 if (activefpu == FPU_68060)
2765 warn("Instruction is emulated in 68060");
2772 // fdiv (6888X, 68040, 68060)
2774 int m_fdiv(WORD inst, WORD siz)
2777 return gen_fpu(inst, siz, B8(00100000), FPU_NOWARN);
2782 // fsdiv (68040, 68060)
2784 int m_fsdiv(WORD inst, WORD siz)
2786 if (activefpu & (FPU_68040 | FPU_68060))
2787 return gen_fpu(inst, siz, B8(01100000), FPU_NOWARN);
2789 return error("Unsupported in current FPU");
2794 // fddiv (68040, 68060)
2796 int m_fddiv(WORD inst, WORD siz)
2798 if (activefpu & (FPU_68040 | FPU_68060))
2799 return gen_fpu(inst, siz, B8(01100100), FPU_NOWARN);
2801 return error("Unsupported in current FPU");
2806 // fetox (6888X, 68040FPSP, 68060FPSP)
2808 int m_fetox(WORD inst, WORD siz)
2811 return gen_fpu(inst, siz, B8(00010000), FPU_FPSP);
2816 // fetoxm1 (6888X, 68040FPSP, 68060FPSP)
2818 int m_fetoxm1(WORD inst, WORD siz)
2821 return gen_fpu(inst, siz, B8(00001000), FPU_FPSP);
2826 // fgetexp (6888X, 68040FPSP, 68060FPSP)
2828 int m_fgetexp(WORD inst, WORD siz)
2831 return gen_fpu(inst, siz, B8(00011110), FPU_FPSP);
2836 // fgetman (6888X, 68040FPSP, 68060FPSP)
2838 int m_fgetman(WORD inst, WORD siz)
2841 return gen_fpu(inst, siz, B8(00011111), FPU_FPSP);
2846 // fint (6888X, 68040FPSP, 68060)
2848 int m_fint(WORD inst, WORD siz)
2851 // special case - fint fpx = fint fpx,fpx
2854 if (activefpu == FPU_68040)
2855 warn("Instruction is emulated in 68040");
2857 return gen_fpu(inst, siz, B8(00000001), FPU_NOWARN);
2862 // fintrz (6888X, 68040FPSP, 68060)
2864 int m_fintrz(WORD inst, WORD siz)
2867 // special case - fintrz fpx = fintrz fpx,fpx
2870 if (activefpu == FPU_68040)
2871 warn("Instruction is emulated in 68040");
2873 return gen_fpu(inst, siz, B8(00000011), FPU_NOWARN);
2878 // flog10 (6888X, 68040FPSP, 68060FPSP)
2880 int m_flog10(WORD inst, WORD siz)
2883 return gen_fpu(inst, siz, B8(00010101), FPU_FPSP);
2888 // flog2 (6888X, 68040FPSP, 68060FPSP)
2890 int m_flog2(WORD inst, WORD siz)
2893 return gen_fpu(inst, siz, B8(00010110), FPU_FPSP);
2898 // flogn (6888X, 68040FPSP, 68060FPSP)
2900 int m_flogn(WORD inst, WORD siz)
2903 return gen_fpu(inst, siz, B8(00010100), FPU_FPSP);
2908 // flognp1 (68040FPSP, 68060FPSP)
2910 int m_flognp1(WORD inst, WORD siz)
2912 if (activefpu & (FPU_68040 | FPU_68060))
2913 return gen_fpu(inst, siz, B8(00000110), FPU_FPSP);
2915 return error("Unsupported in current FPU");
2920 // fmod (6888X, 68040FPSP, 68060FPSP)
2922 int m_fmod(WORD inst, WORD siz)
2925 return gen_fpu(inst, siz, B8(00100001), FPU_FPSP);
2930 // fmove (6888X, 68040, 68060)
2932 int m_fmove(WORD inst, WORD siz)
2937 if ((am0 == FREG) && (am1 < AM_USP))
2941 inst |= am1 | a1reg;
2950 case SIZB: inst |= (6 << 10); break;
2951 case SIZW: inst |= (4 << 10); break;
2952 case SIZL: inst |= (0 << 10); break;
2954 case SIZS: inst |= (1 << 10); break;
2955 case SIZD: inst |= (5 << 10); break;
2956 case SIZX: inst |= (2 << 10); break;
2957 case SIZP: inst |= (3 << 10);
2958 // In P size we have 2 cases: {#k} where k is immediate
2959 // and {Dn} where Dn=Data register
2964 inst |= bfval1 << 4;
2969 if (bfval1 > 63 && bfval1 < -64)
2970 return error("K-factor must be between -64 and 63");
2972 inst |= bfval1 & 127;
2977 return error("Something bad happened, possibly.");
2981 // Destination specifier
2982 inst |= (a0reg << 7);
2990 else if ((am0 < AM_USP) && (am1 == FREG))
2995 inst |= am0 | a0reg;
3004 case SIZB: inst |= (6 << 10); break;
3005 case SIZW: inst |= (4 << 10); break;
3006 case SIZL: inst |= (0 << 10); break;
3008 case SIZS: inst |= (1 << 10); break;
3009 case SIZD: inst |= (5 << 10); break;
3010 case SIZX: inst |= (2 << 10); break;
3011 case SIZP: inst |= (3 << 10); break;
3013 return error("Something bad happened, possibly.");
3017 // Destination specifier
3018 inst |= (a1reg << 7);
3026 else if ((am0 == FREG) && (am1 == FREG))
3028 // register-to-register
3029 // Essentially ea to register with R/0=0
3038 if (siz != SIZX && siz != SIZN)
3039 return error("Invalid size");
3042 inst |= (a0reg << 10);
3044 // Destination register
3045 inst |= (a1reg << 7);
3055 // fmove (6888X, 68040, 68060)
3057 int m_fmovescr(WORD inst, WORD siz)
3061 // Move Floating-Point System Control Register (FPCR)
3065 if ((am0 == FPSCR) && (am1 < AM_USP))
3067 inst |= am1 | a1reg;
3069 inst = (1 << 13) + (1 << 15);
3075 else if ((am1 == FPSCR) && (am0 < AM_USP))
3077 inst |= am0 | a0reg;
3079 inst = (0 << 13) + (1 << 15);
3086 return error("m_fmovescr says: wut?");
3090 // fsmove/fdmove (68040, 68060)
3092 int m_fsmove(WORD inst, WORD siz)
3094 if (!(activefpu & (FPU_68040 | FPU_68060)))
3095 return error("Unsupported in current FPU");
3097 return error("Not implemented yet.");
3100 if (activefpu == FPU_68040)
3101 return gen_fpu(inst, siz, B8(01100100), FPU_P_EMUL);
3103 return error("Unsupported in current FPU");
3108 int m_fdmove(WORD inst, WORD siz)
3110 if (!(activefpu & (FPU_68040 | FPU_68060)))
3111 return error("Unsupported in current FPU");
3113 return error("Not implemented yet.");
3116 if (activefpu == FPU_68040)
3117 return gen_fpu(inst, siz, B8(01100100), FPU_P_EMUL);
3119 return error("Unsupported in current FPU");
3125 // fmovecr (6888X, 68040FPSP, 68060FPSP)
3127 int m_fmovecr(WORD inst, WORD siz)
3137 if (activefpu == FPU_68040)
3138 warn("Instruction is emulated in 68040/060");
3145 // fmovem (6888X, 68040, 68060FPSP)
3147 int m_fmovem(WORD inst, WORD siz)
3154 if (siz == SIZX || siz == SIZN)
3156 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
3158 // fmovem.x <rlist>,ea
3159 if (fpu_reglist_left(®mask) < 0)
3163 return error("missing comma");
3168 inst |= am0 | a0reg;
3170 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3171 return error("invalid addressing mode");
3174 inst = (1 << 15) | (1 << 14) | (1 << 13) | (0 << 11) | regmask;
3179 else if ((*tok >= KW_D0) && (*tok <= KW_D7))
3182 datareg = (*tok++ & 7) << 10;
3185 return error("missing comma");
3190 inst |= am0 | a0reg;
3192 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3193 return error("invalid addressing mode");
3195 // Quote from the 060 manual:
3196 // "[..] when the processor attempts an FMOVEM.X instruction using a dynamic register list."
3197 if (activefpu == FPU_68060)
3198 warn("Instruction is emulated in 68060");
3201 inst = (1 << 15) | (1 << 14) | (1 << 13) | (1 << 11) | (datareg << 4);
3212 inst |= am0 | a0reg;
3215 return error("missing comma");
3217 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
3219 // fmovem.x ea,<rlist>
3220 if (fpu_reglist_right(®mask) < 0)
3224 inst = (1 << 15) | (1 << 14) | (0 << 13) | (2 << 11) | regmask;
3232 datareg = (*tok++ & 7) << 10;
3234 // Quote from the 060 manual:
3235 // "[..] when the processor attempts an FMOVEM.X instruction using a dynamic register list."
3236 if (activefpu == FPU_68060)
3237 warn("Instruction is emulated in 68060");
3240 inst = (1 << 15) | (1 << 14) | (0 << 13) | (3 << 11) | (datareg << 4);
3247 else if (siz == SIZL)
3249 if ((*tok == KW_FPCR) || (*tok == KW_FPSR) || (*tok == KW_FPIAR))
3251 // fmovem.l <rlist>,ea
3252 regmask = (1 << 15) | (1 << 13);
3253 int no_control_regs = 0;
3256 if (*tok == KW_FPCR)
3258 regmask |= (1 << 12);
3264 if (*tok == KW_FPSR)
3266 regmask |= (1 << 11);
3272 if (*tok == KW_FPIAR)
3274 regmask |= (1 << 10);
3280 if ((*tok == '/') || (*tok == '-'))
3287 return error("missing comma");
3292 // Quote from the 060 manual:
3293 // "[..] when the processor attempts to execute an FMOVEM.L instruction with
3294 // an immediate addressing mode to more than one floating - point
3295 // control register (FPCR, FPSR, FPIAR)[..]"
3296 if (activefpu == FPU_68060)
3297 if (no_control_regs > 1 && am0 == IMMED)
3298 warn("Instruction is emulated in 68060");
3300 inst |= am0 | a0reg;
3307 // fmovem.l ea,<rlist>
3311 inst |= am0 | a0reg;
3314 return error("missing comma");
3316 regmask = (1 << 15) | (0 << 13);
3319 if (*tok == KW_FPCR)
3321 regmask |= (1 << 12);
3326 if (*tok == KW_FPSR)
3328 regmask |= (1 << 11);
3333 if (*tok == KW_FPIAR)
3335 regmask |= (1 << 10);
3340 if ((*tok == '/') || (*tok == '-'))
3347 return error("extra (unexpected) text found");
3349 inst |= am0 | a0reg;
3356 return error("bad size suffix");
3363 // fmul (6888X, 68040, 68060)
3365 int m_fmul(WORD inst, WORD siz)
3368 return gen_fpu(inst, siz, B8(00100011), FPU_NOWARN);
3373 // fsmul (68040, 68060)
3375 int m_fsmul(WORD inst, WORD siz)
3377 if (activefpu & (FPU_68040 | FPU_68060))
3378 return gen_fpu(inst, siz, B8(01100011), FPU_NOWARN);
3380 return error("Unsupported in current FPU");
3387 int m_fdmul(WORD inst, WORD siz)
3389 if (activefpu & (FPU_68040 | FPU_68060))
3390 return gen_fpu(inst, siz, B8(01100111), FPU_NOWARN);
3392 return error("Unsupported in current FPU");
3397 // fneg (6888X, 68040, 68060)
3399 int m_fneg(WORD inst, WORD siz)
3406 return gen_fpu(inst, siz, B8(00011010), FPU_NOWARN);
3409 return gen_fpu(inst, siz, B8(00011010), FPU_NOWARN);
3414 // fsneg (68040, 68060)
3416 int m_fsneg(WORD inst, WORD siz)
3418 if (activefpu & (FPU_68040 | FPU_68060))
3423 return gen_fpu(inst, siz, B8(01011010), FPU_NOWARN);
3426 return gen_fpu(inst, siz, B8(01011010), FPU_NOWARN);
3429 return error("Unsupported in current FPU");
3434 // fdneg (68040, 68060)
3436 int m_fdneg(WORD inst, WORD siz)
3438 if (activefpu & (FPU_68040 | FPU_68060))
3443 return gen_fpu(inst, siz, B8(01011110), FPU_NOWARN);
3446 return gen_fpu(inst, siz, B8(01011110), FPU_NOWARN);
3449 return error("Unsupported in current FPU");
3454 // fnop (6888X, 68040, 68060)
3456 int m_fnop(WORD inst, WORD siz)
3459 return gen_fpu(inst, siz, B8(00000000), FPU_NOWARN);
3464 // frem (6888X, 68040FPSP, 68060FPSP)
3466 int m_frem(WORD inst, WORD siz)
3469 return gen_fpu(inst, siz, B8(00100101), FPU_FPSP);
3474 // fscale (6888X, 68040FPSP, 68060FPSP)
3476 int m_fscale(WORD inst, WORD siz)
3479 return gen_fpu(inst, siz, B8(00100110), FPU_FPSP);
3484 // FScc (6888X, 68040, 68060), cpScc (68851, 68030), PScc (68851)
3485 // TODO: Add check for PScc to ensure 68020+68851 active
3486 // TODO: Add check for cpScc to ensure 68020+68851, 68030
3488 int m_fscc(WORD inst, WORD siz)
3492 // We stash the 5 condition bits inside the opcode in 68ktab (bits 4-0),
3493 // so we need to extract them first and fill in the clobbered bits.
3494 WORD opcode = inst & 0x1F;
3496 inst |= am0 | a0reg;
3500 if (activefpu == FPU_68060)
3501 warn("Instruction is emulated in 68060");
3507 // fsgldiv (6888X, 68040FPSP, 68060FPSP)
3509 int m_fsgldiv(WORD inst, WORD siz)
3512 return gen_fpu(inst, siz, B8(00100100), FPU_FPSP);
3517 // fsglmul (6888X, 68040, 68060FPSP)
3519 int m_fsglmul(WORD inst, WORD siz)
3522 return gen_fpu(inst, siz, B8(00100111), FPU_FPSP);
3527 // fsin (6888X, 68040FPSP, 68060FPSP)
3529 int m_fsin(WORD inst, WORD siz)
3532 return gen_fpu(inst, siz, B8(00001110), FPU_FPSP);
3537 // fsincos (6888X, 68040FPSP, 68060FPSP)
3539 int m_fsincos(WORD inst, WORD siz)
3543 // Swap a1reg, a2reg as a2reg should be stored in the bitfield gen_fpu
3550 if (gen_fpu(inst, siz, B8(00110000), FPU_FPSP) == OK)
3561 // fsinh (6888X, 68040FPSP, 68060FPSP)
3563 int m_fsinh(WORD inst, WORD siz)
3566 return gen_fpu(inst, siz, B8(00000010), FPU_FPSP);
3571 // fsqrt (6888X, 68040, 68060)
3573 int m_fsqrt(WORD inst, WORD siz)
3576 return gen_fpu(inst, siz, B8(00000100), FPU_NOWARN);
3581 // fsfsqrt (68040, 68060)
3583 int m_fsfsqrt(WORD inst, WORD siz)
3585 if (activefpu & (FPU_68040 | FPU_68060))
3586 return gen_fpu(inst, siz, B8(01000001), FPU_NOWARN);
3588 return error("Unsupported in current FPU");
3593 // fdfsqrt (68040, 68060)
3595 int m_fdfsqrt(WORD inst, WORD siz)
3597 if (activefpu & (FPU_68040 | FPU_68060))
3598 return gen_fpu(inst, siz, B8(01000101), FPU_NOWARN);
3600 return error("Unsupported in current FPU");
3605 // fsub (6888X, 68040, 68060)
3607 int m_fsub(WORD inst, WORD siz)
3610 return gen_fpu(inst, siz, B8(00101000), FPU_NOWARN);
3615 // fsfsub (68040, 68060)
3617 int m_fsfsub(WORD inst, WORD siz)
3619 if (activefpu & (FPU_68040 | FPU_68060))
3620 return gen_fpu(inst, siz, B8(01101000), FPU_NOWARN);
3622 return error("Unsupported in current FPU");
3627 // fdfsub (68040, 68060)
3629 int m_fdsub(WORD inst, WORD siz)
3631 if (activefpu & (FPU_68040 | FPU_68060))
3632 return gen_fpu(inst, siz, B8(01101100), FPU_NOWARN);
3634 return error("Unsupported in current FPU");
3639 // ftan (6888X, 68040FPSP, 68060FPSP)
3641 int m_ftan(WORD inst, WORD siz)
3644 return gen_fpu(inst, siz, B8(00001111), FPU_FPSP);
3649 // ftanh (6888X, 68040FPSP, 68060FPSP)
3651 int m_ftanh(WORD inst, WORD siz)
3654 return gen_fpu(inst, siz, B8(00001001), FPU_FPSP);
3659 // ftentox (6888X, 68040FPSP, 68060FPSP)
3661 int m_ftentox(WORD inst, WORD siz)
3664 return gen_fpu(inst, siz, B8(00010010), FPU_FPSP);
3669 // FTRAPcc (6888X, 68040, 68060FPSP)
3671 int m_ftrapcc(WORD inst, WORD siz)
3675 // We stash the 5 condition bits inside the opcode in 68ktab (bits 3-7),
3676 // so we need to extract them first and fill in the clobbered bits.
3677 WORD opcode = (inst >> 3) & 0x1F;
3678 inst = (inst & 0xFF07) | (0xF << 3);
3687 else if (siz == SIZL)
3694 else if (siz == SIZN)
3702 if (activefpu == FPU_68060)
3703 warn("Instruction is emulated in 68060");
3710 // ftst (6888X, 68040, 68060)
3712 int m_ftst(WORD inst, WORD siz)
3715 return gen_fpu(inst, siz, B8(00111010), FPU_NOWARN);
3720 // ftwotox (6888X, 68040FPSP, 68060FPSP)
3722 int m_ftwotox(WORD inst, WORD siz)
3725 return gen_fpu(inst, siz, B8(00010001), FPU_FPSP);