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 && am1 == MEMPOST)
407 // Added for addi/andi/cmpi/eori/ori/subi #xx,(bd,An,Dm)
408 inst |= a1reg | AINDEXED;
410 else if (am0 == IMMED)
411 inst |= am0 | a0reg; // Get ea0 into instr
412 else if (am0 == AM_CCR)
414 else if (am0 == AIND)
417 inst |= a0reg; // Get ea0 into instr
418 D_word(inst); // Deposit instr
419 ea0gen(siz); // Generate ea0
421 // Generate ea1 if requested
431 // Dx,Dy nnnnXXXnssnnnYYY If bit 0 of `inst' is set, install size bits in bits
434 int m_abcd(WORD inst, WORD siz)
443 inst |= a0reg | reg_9[a1reg];
453 int m_adda(WORD inst, WORD siz)
455 if (a0exattr & DEFINED)
457 if (CHECK_OPTS(OPT_ADDA_ADDQ))
458 if (a0exval > 1 && a0exval <= 8)
459 // Immediate is between 1 and 8 so let's convert to addq
460 return m_addq(B16(01010000, 00000000), siz);
461 if (CHECK_OPTS(OPT_ADDA_LEA))
464 // Immediate is larger than 8 so let's convert to lea
465 am0 = ADISP; // Change addressing mode
466 a0reg = a1reg; // In ADISP a0reg is used instead of a1reg!
467 return m_lea(B16(01000001, 11011000), SIZW);
471 inst |= am0 | a0reg | lwsiz_8[siz] | reg_9[a1reg];
473 ea0gen(siz); // Generate EA
480 // If bit 0 of `inst' is 1, install size bits in bits 6..7 of instr.
481 // If bit 1 of `inst' is 1, install a1reg in bits 9..11 of instr.
483 int m_reg(WORD inst, WORD siz)
490 // Install other register (9..11)
491 inst |= reg_9[a1reg];
493 inst &= ~7; // Clear off crufty bits
494 inst |= a0reg; // Install first register
504 int m_imm(WORD inst, WORD siz)
516 int m_imm8(WORD inst, WORD siz)
529 int m_shr(WORD inst, WORD siz)
531 inst |= reg_9[a0reg] | a1reg | siz_6[siz];
541 int m_shi(WORD inst, WORD siz)
543 inst |= a1reg | siz_6[siz];
545 if (a0exattr & DEFINED)
548 return error(range_error);
550 inst |= (a0exval & 7) << 9;
555 AddFixup(FU_QUICK, sloc, a0expr);
564 // {bset, btst, bchg, bclr} -- #immed,ea -- Dn,ea
566 int m_bitop(WORD inst, WORD siz)
568 // Enforce instruction sizes
570 { // X,Dn must be .n or .l
571 if (siz & (SIZB | SIZW))
572 return error(siz_error);
574 else if (siz & (SIZW | SIZL)) // X,ea must be .n or .b
575 return error(siz_error);
577 // Construct instr and EAs
583 ea0gen(SIZB); // Immediate bit number
587 inst |= reg_9[a0reg];
598 int m_dbra(WORD inst, WORD siz)
604 if (a1exattr & DEFINED)
606 if ((a1exattr & TDB) != cursect)
607 return error(rel_error);
609 uint32_t v = a1exval - sloc;
611 if (v + 0x8000 > 0x10000)
612 return error(range_error);
618 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
629 int m_exg(WORD inst, WORD siz)
635 if (am0 == DREG && am1 == DREG)
637 else if (am0 == AREG && am1 == AREG)
643 m = a1reg; // Get AREG into a1reg
651 inst |= m | reg_9[a0reg] | a1reg;
661 int m_link(WORD inst, WORD siz)
665 // Is this an error condition???
670 inst &= ~((3 << 9) | (1 << 6) | (1 << 4));
682 WORD extra_addressing[16]=
684 0x30, // 0100 (bd,An,Xn)
685 0x30, // 0101 ([bd,An],Xn,od)
686 0x30, // 0102 ([bc,An,Xn],od)
687 0x30, // 0103 (bd,PC,Xn)
688 0x30, // 0104 ([bd,PC],Xn,od)
689 0x30, // 0105 ([bc,PC,Xn],od)
704 // Handle MOVE <C_ALL> <C_ALTDATA>
705 // MOVE <C_ALL> <M_AREG>
707 // Optimize MOVE.L #<smalldata>,D0 to a MOVEQ
709 int m_move(WORD inst, WORD size)
711 // Cast the passed in value to an int
714 // Try to optimize to MOVEQ
715 // N.B.: We can get away with casting the uint64_t to a 32-bit value
716 // because it checks for a SIZL (i.e., a 32-bit value).
717 if (CHECK_OPTS(OPT_MOVEL_MOVEQ)
718 && (siz == SIZL) && (am0 == IMMED) && (am1 == DREG)
719 && ((a0exattr & (TDB | DEFINED)) == DEFINED)
720 && ((uint32_t)a0exval + 0x80 < 0x100))
722 m_moveq((WORD)0x7000, (WORD)0);
725 warn("move.l #size,dx converted to moveq");
729 if ((am0 < ABASE) && (am1 < ABASE)) // 68000 modes
731 inst |= siz_12[siz] | am_6[am1] | reg_9[a1reg] | am0 | a0reg;
739 ea1gen((WORD)siz | 0x8000); // Tell ea1gen we're move ea,ea
743 inst |= siz_12[siz] | reg_9[a1reg] | extra_addressing[am0 - ABASE];
760 // Handle MOVE <C_ALL030> <C_ALTDATA>
761 // MOVE <C_ALL030> <M_AREG>
763 int m_move30(WORD inst, WORD size)
766 inst |= siz_12[siz] | reg_9[a1reg & 7] | a0reg | extra_addressing[am0 - ABASE];
781 // move USP,An -- move An,USP
783 int m_usp(WORD inst, WORD siz)
788 inst |= a1reg; // USP, An
790 inst |= a0reg; // An, USP
801 int m_moveq(WORD inst, WORD siz)
805 // Arrange for future fixup
806 if (!(a0exattr & DEFINED))
808 AddFixup(FU_BYTE | FU_SEXT, sloc + 1, a0expr);
811 else if ((uint32_t)a0exval + 0x100 >= 0x200)
812 return error(range_error);
814 inst |= reg_9[a1reg] | (a0exval & 0xFF);
822 // movep Dn, disp(An) -- movep disp(An), Dn
824 int m_movep(WORD inst, WORD siz)
826 // Tell ea0gen to lay off the 0(a0) optimisations on this one
834 inst |= reg_9[a0reg] | a1reg;
844 inst |= reg_9[a1reg] | a0reg;
861 int m_br(WORD inst, WORD siz)
863 if (a0exattr & DEFINED)
865 if ((a0exattr & TDB) != cursect)
867 //printf("m_br(): a0exattr = %X, cursect = %X, a0exval = %X, sloc = %X\n", a0exattr, cursect, a0exval, sloc);
868 return error(rel_error);
871 uint32_t v = (uint32_t)a0exval - (sloc + 2);
873 // Optimize branch instr. size
876 if (CHECK_OPTS(OPT_BSR_BCC_S) && (v != 0) && ((v + 0x80) < 0x100))
883 warn("Bcc.w/BSR.w converted to .s");
890 if ((v + 0x8000) > 0x10000)
891 return error(range_error);
899 if (siz == SIZB || siz == SIZS)
901 if ((v + 0x80) >= 0x100)
902 return error(range_error);
909 if ((v + 0x8000) >= 0x10000)
910 return error(range_error);
918 else if (siz == SIZN)
921 if (siz == SIZB || siz == SIZS)
924 AddFixup(FU_BBRA | FU_PCREL | FU_SEXT, sloc, a0expr);
932 AddFixup(FU_WORD | FU_PCREL | FU_LBRA | FU_ISBRA, sloc, a0expr);
943 int m_addq(WORD inst, WORD siz)
945 inst |= siz_6[siz] | am1 | a1reg;
947 if (a0exattr & DEFINED)
949 if ((a0exval > 8) || (a0exval == 0)) // Range in 1..8
950 return error(range_error);
952 inst |= (a0exval & 7) << 9;
957 AddFixup(FU_QUICK, sloc, a0expr);
970 int m_trap(WORD inst, WORD siz)
974 if (a0exattr & DEFINED)
977 return error(abs_error);
980 return error(range_error);
986 return error(undef_error);
993 // movem <rlist>,ea -- movem ea,<rlist>
995 int m_movem(WORD inst, WORD siz)
1003 return error("bad size suffix");
1010 // Handle #<expr>, ea
1013 if (abs_expr(&eval) != OK)
1016 if (eval >= 0x10000L)
1017 return error(range_error);
1023 if ((*tok >= KW_D0) && (*tok <= KW_A7))
1026 if (reglist(&rmask) < 0)
1031 return error("missing comma");
1036 inst |= am0 | a0reg;
1038 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
1039 return error("invalid addressing mode");
1041 // If APREDEC, reverse register mask
1047 for(i=0x8000; i; i>>=1, w>>=1)
1048 rmask = (WORD)((rmask << 1) | w & 1);
1057 inst |= 0x0400 | am0 | a0reg;
1060 return error("missing comma");
1063 return error("missing register list");
1070 if (abs_expr(&eval) != OK)
1073 if (eval >= 0x10000)
1074 return error(range_error);
1078 else if (reglist(&rmask) < 0)
1081 if (!(amsktab[am0] & (C_CTRL | M_APOSTINC)))
1082 return error("invalid addressing mode");
1094 // CLR.x An ==> SUBA.x An,An
1096 int m_clra(WORD inst, WORD siz)
1098 inst |= a0reg | reg_9[a0reg] | lwsiz_8[siz];
1106 // CLR.L Dn ==> CLR.L An or MOVEQ #0,Dx
1108 int m_clrd(WORD inst, WORD siz)
1110 if (!CHECK_OPTS(OPT_CLR_DX))
1113 inst = (a0reg << 9) | B16(01110000, 00000000);
1121 ////////////////////////////////////////
1123 // 68020/30/40/60 instructions
1125 ////////////////////////////////////////
1130 int m_br30(WORD inst, WORD siz)
1132 if (a0exattr & DEFINED)
1134 if ((a0exattr & TDB) != cursect)
1135 return error(rel_error);
1137 uint32_t v = (uint32_t)a0exval - (sloc + 2);
1146 AddFixup(FU_LONG | FU_PCREL | FU_SEXT, sloc, a0expr);
1154 // bfchg, bfclr, bfexts, bfextu, bfffo, bfins, bfset
1155 // (68020, 68030, 68040)
1157 int m_bfop(WORD inst, WORD siz)
1159 if ((bfval1 > 31) || (bfval1 < 0))
1160 return error("bfxxx offset: immediate value must be between 0 and 31");
1162 // First instruction word - just the opcode and first EA
1163 // Note: both am1 is ORed because solely of bfins - maybe it's a good idea
1164 // to make a dedicated function for it?
1171 if (bfval2 > 31 || bfval2 < 0)
1172 return error("bfxxx width: immediate value must be between 0 and 31");
1174 // For Dw both immediate and register number are stuffed
1175 // into the same field O_o
1176 bfparam2 = (bfval2 << 0);
1180 bfparam1 = (bfval1 << 6);
1182 bfparam1 = bfval1 << 12;
1184 D_word((inst | am0 | a0reg | am1 | a1reg));
1185 ea0gen(siz); // Generate EA
1187 // Second instruction word - Dest register (if exists), Do, Offset, Dw, Width
1188 inst = bfparam1 | bfparam2;
1194 inst |= a0reg << 12;
1203 // bkpt (68EC000, 68010, 68020, 68030, 68040, CPU32)
1205 int m_bkpt(WORD inst, WORD siz)
1209 if (a0exattr & DEFINED)
1212 return error(abs_error);
1215 return error(range_error);
1221 return error(undef_error);
1230 int m_callm(WORD inst, WORD siz)
1237 if (a0exattr & DEFINED)
1240 return error(abs_error);
1243 return error(range_error);
1245 inst = (uint16_t)a0exval;
1249 return error(undef_error);
1259 // cas (68020, 68030, 68040)
1261 int m_cas(WORD inst, WORD siz)
1267 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1268 return error(unsupport);
1283 return error("bad size suffix");
1288 if ((*tok < KW_D0) && (*tok > KW_D7))
1289 return error("CAS accepts only data registers");
1291 inst2 = (*tok++) & 7;
1294 return error("missing comma");
1297 if ((*tok < KW_D0) && (*tok > KW_D7))
1298 return error("CAS accepts only data registers");
1300 inst2 |= ((*tok++) & 7) << 6;
1303 return error("missing comma");
1306 if ((modes = amode(1)) < 0)
1310 return error("too many ea fields");
1313 return error("extra (unexpected) text found");
1315 // Reject invalid ea modes
1316 amsk = amsktab[am0];
1318 if ((amsk & (M_AIND | M_APOSTINC | M_APREDEC | M_ADISP | M_AINDEXED | M_ABSW | M_ABSL | M_ABASE | M_MEMPOST | M_MEMPRE)) == 0)
1319 return error("unsupported addressing mode");
1321 inst |= am0 | a0reg;
1331 // cas2 (68020, 68030, 68040)
1333 int m_cas2(WORD inst, WORD siz)
1337 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1338 return error(unsupport);
1353 return error("bad size suffix");
1358 if ((*tok < KW_D0) && (*tok > KW_D7))
1359 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1361 inst2 = (*tok++) & 7;
1364 return error("missing colon");
1367 if ((*tok < KW_D0) && (*tok > KW_D7))
1368 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1370 inst3 = (*tok++) & 7;
1373 return error("missing comma");
1376 if ((*tok < KW_D0) && (*tok > KW_D7))
1377 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1379 inst2 |= ((*tok++) & 7) << 6;
1382 return error("missing colon");
1385 if ((*tok < KW_D0) && (*tok > KW_D7))
1386 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1388 inst3 |= ((*tok++) & 7) << 6;
1391 return error("missing comma");
1395 return error("missing (");
1396 if ((*tok >= KW_D0) && (*tok <= KW_D7))
1397 inst2 |= (((*tok++) & 7) << 12) | (0 << 15);
1398 else if ((*tok >= KW_A0) && (*tok <= KW_A7))
1399 inst2 |= (((*tok++) & 7) << 12) | (1 << 15);
1401 return error("CAS accepts either data or address registers for Rn1:Rn2 pair");
1404 return error("missing (");
1407 return error("missing colon");
1411 return error("missing (");
1412 if ((*tok >= KW_D0) && (*tok <= KW_D7))
1413 inst3 |= (((*tok++) & 7) << 12) | (0 << 15);
1414 else if ((*tok >= KW_A0) && (*tok <= KW_A7))
1415 inst3 |= (((*tok++) & 7) << 12) | (1 << 15);
1417 return error("CAS accepts either data or address registers for Rn1:Rn2 pair");
1420 return error("missing (");
1423 return error("extra (unexpected) text found");
1434 // cmp2 (68020, 68030, 68040, CPU32)
1436 int m_cmp2(WORD inst, WORD siz)
1438 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1439 return error(unsupport);
1441 switch (siz & 0x000F)
1455 WORD flg = inst; // Save flag bits
1456 inst &= ~0x3F; // Clobber flag bits in instr
1458 // Install "standard" instr size bits
1464 // OR-in register number
1466 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1468 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1474 inst |= am1 | a1reg; // Get ea1 into instr
1475 D_word(inst); // Deposit instr
1477 // Generate ea0 if requested
1481 ea1gen(siz); // Generate ea1
1486 inst |= am0 | a0reg; // Get ea0 into instr
1487 D_word(inst); // Deposit instr
1488 ea0gen(siz); // Generate ea0
1490 // Generate ea1 if requested
1495 // If we're called from chk2 then bit 11 of size will be set. This is just
1496 // a dumb mechanism to pass this, required by the extension word. (You might
1497 // have noticed the siz & 15 thing above!)
1498 inst = (a1reg << 12) | (siz & (1 << 11));
1510 // chk2 (68020, 68030, 68040, CPU32)
1512 int m_chk2(WORD inst, WORD siz)
1514 return m_cmp2(inst, siz | (1 << 11));
1519 // cpbcc(68020, 68030)
1521 int m_cpbr(WORD inst, WORD siz)
1523 if ((activecpu & (CPU_68020 | CPU_68030)) == 0)
1524 return error(unsupport);
1526 if (a0exattr & DEFINED)
1528 if ((a0exattr & TDB) != cursect)
1529 return error(rel_error);
1531 uint32_t v = (uint32_t)a0exval - (sloc + 2);
1533 // Optimize branch instr. size
1536 if ((v != 0) && ((v + 0x8000) < 0x10000))
1546 if ((v + 0x8000) >= 0x10000)
1547 return error(range_error);
1555 else if (siz == SIZN)
1562 AddFixup(FU_LONG | FU_PCREL | FU_SEXT, sloc, a0expr);
1570 AddFixup(FU_WORD | FU_PCREL | FU_SEXT, sloc, a0expr);
1579 // cpdbcc(68020, 68030)
1581 int m_cpdbr(WORD inst, WORD siz)
1586 WORD condition = inst & 0x1F; // Grab condition sneakily placed in the lower 5 bits of inst
1587 inst &= 0xFFE0; // And then mask them out - you ain't seen me, roit?
1589 inst |= (1 << 9); // Bolt on FPU id
1596 if (a1exattr & DEFINED)
1598 if ((a1exattr & TDB) != cursect)
1599 return error(rel_error);
1601 v = (uint32_t)a1exval - sloc;
1603 if (v + 0x8000 > 0x10000)
1604 return error(range_error);
1610 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
1619 // muls.l / divs.l / divu.l / mulu.l (68020+)
1621 int m_muls(WORD inst, WORD siz)
1623 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1624 return error(unsupport);
1626 WORD flg = inst; // Save flag bits
1627 inst &= ~0x33F; // Clobber flag and extension bits in instr
1629 // Install "standard" instr size bits
1635 // OR-in register number
1637 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1639 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1642 // Regarding extension word: bit 11 is signed/unsigned selector
1643 // bit 10 is 32/64 bit selector
1644 // Both of these are packed in bits 9 and 8 of the instruction
1645 // field in 68ktab. Extra compilcations arise from the fact we
1646 // have to distinguish between divu/s.l Dn,Dm (which is encoded
1647 // as divu/s.l Dn,Dm:Dm) and divu/s.l Dn,Dm:Dx - the first is
1648 // 32 bit while the second 64 bit
1653 inst |= am1 | a1reg; // Get ea1 into instr
1654 D_word(inst); // Deposit instr
1658 inst = a1reg + (a2reg << 12) + ((flg & 0x200) << 2);
1660 inst = a1reg + (a2reg << 12) + ((flg & 0x300) << 2);
1664 // Generate ea0 if requested
1668 ea1gen(siz); // Generate ea1
1675 inst |= am0 | a0reg; // Get ea0 into instr
1676 D_word(inst); // Deposit instr
1680 inst = a1reg + (a2reg << 12) + ((flg & 0x200) << 2);
1682 inst = a1reg + (a2reg << 12) + ((flg & 0x300) << 2);
1686 ea0gen(siz); // Generate ea0
1688 // Generate ea1 if requested
1698 // move16 (ax)+,(ay)+
1700 int m_move16a(WORD inst, WORD siz)
1702 if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1703 return error(unsupport);
1707 inst = (1 << 15) + (a1reg << 12);
1715 // move16 with absolute address
1717 int m_move16b(WORD inst, WORD siz)
1719 if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1720 return error(unsupport);
1726 if (am0 == APOSTINC)
1729 return error("Wasn't this suppose to call m_move16a???");
1732 //move16 (ax)+,(xxx).L
1737 else if (am0 == ABSL)
1741 //move16 (xxx).L,(ax)+
1747 //move16 (xxx).L,(ax)
1752 else if (am0 == AIND)
1754 //move16 (ax),(xxx).L
1767 // pack/unpack (68020/68030/68040)
1769 int m_pack(WORD inst, WORD siz)
1774 return error("bad size suffix");
1776 if (*tok >= KW_D0 && *tok <= KW_D7)
1778 // Dx,Dy,#<adjustment>
1779 inst |= (0 << 3); // R/M
1780 inst |= (*tok++ & 7);
1782 if (*tok != ',' && tok[2] != ',')
1783 return error("missing comma");
1785 if (tok[1] < KW_D0 && tok[1] > KW_D7)
1786 return error(syntax_error);
1788 inst |= ((tok[1] & 7)<<9);
1791 // Fall through for adjustment (common in both valid cases)
1793 else if (*tok == '-')
1795 // -(Ax),-(Ay),#<adjustment>
1796 inst |= (1 << 3); // R/M
1797 tok++; // eat the minus
1799 if ((*tok != '(') && (tok[2]!=')') && (tok[3]!=',') && (tok[4] != '-') && (tok[5] != '(') && (tok[7] != ')') && (tok[8] != ','))
1800 return error(syntax_error);
1802 if (tok[1] < KW_A0 && tok[1] > KW_A7)
1803 return error(syntax_error);
1805 if (tok[5] < KW_A0 && tok[6] > KW_A7)
1806 return error(syntax_error);
1808 inst |= ((tok[1] & 7) << 0);
1809 inst |= ((tok[6] & 7) << 9);
1812 // Fall through for adjustment (common in both valid cases)
1815 return error("invalid syntax");
1817 if ((*tok != CONST) && (*tok != SYMBOL) && (*tok != '-'))
1818 return error(syntax_error);
1820 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
1823 if ((a0exattr & DEFINED) == 0)
1824 return error(undef_error);
1826 if (a0exval + 0x8000 > 0x10000)
1830 return error(extra_stuff);
1832 D_word((a0exval & 0xFFFF));
1841 int m_rtm(WORD inst, WORD siz)
1849 else if (am0 == AREG)
1851 inst |= (1 << 3) + a0reg;
1854 return error("rtm only allows data or address registers.");
1865 int m_rtd(WORD inst, WORD siz)
1869 if (a0exattr & DEFINED)
1872 return error(abs_error);
1874 if ((a0exval + 0x8000) <= 0x7FFF)
1875 return error(range_error);
1881 return error(undef_error);
1890 int m_trapcc(WORD inst, WORD siz)
1898 else if (am0 == IMMED)
1902 if (a0exval < 0x10000)
1909 return error("Immediate value too big");
1919 return error("Invalid parameter for trapcc");
1926 // cinvl/p/a (68040)
1928 int m_cinv(WORD inst, WORD siz)
1933 inst |= (0 << 6) | (a1reg);
1937 inst |= (2 << 6) | (a1reg);
1940 inst |= (1 << 6) | (a1reg);
1943 inst |= (3 << 6) | (a1reg);
1952 int m_fpusavrest(WORD inst, WORD siz)
1954 inst |= am0 | a0reg;
1963 // cpSAVE/cpRESTORE (68020, 68030)
1965 int m_cprest(WORD inst, WORD siz)
1967 if (activecpu & !(CPU_68020 | CPU_68030))
1968 return error(unsupport);
1970 return m_fpusavrest(inst, siz);
1976 // FSAVE/FRESTORE (68040, 68060)
1978 int m_frestore(WORD inst, WORD siz)
1980 if ((!(activecpu & (CPU_68040 | CPU_68060))) ||
1981 (activefpu&(FPU_68881 | FPU_68882)))
1982 return error(unsupport);
1984 return m_fpusavrest(inst, siz);
1989 // movec (68010, 68020, 68030, 68040, CPU32)
1991 int m_movec(WORD inst, WORD siz)
1995 if (am0 == DREG || am0 == AREG)
2003 inst = (0 << 15) + (a0reg << 12) + CREGlut[a1reg];
2008 inst = (1 << 15) + (a0reg << 12) + CREGlut[a1reg];
2019 inst = (0 << 15) + (a1reg << 12) + CREGlut[a0reg];
2024 inst = (1 << 15) + (a1reg << 12) + CREGlut[a0reg];
2034 // moves (68010, 68020, 68030, 68040, CPU32)
2036 int m_moves(WORD inst, WORD siz)
2038 if (activecpu & !(CPU_68020 | CPU_68030 | CPU_68040))
2039 return error(unsupport);
2043 else if (siz == SIZL)
2050 inst |= am1 | a1reg;
2052 inst = (a0reg << 12) | (1 << 11) | (0 << 15);
2055 else if (am0 == AREG)
2057 inst |= am1 | a1reg;
2059 inst = (a0reg << 12) | (1 << 11) | (1 << 15);
2066 inst |= am0 | a0reg;
2068 inst = (a1reg << 12) | (0 << 11) | (0 << 15);
2073 inst |= am0 | a0reg;
2075 inst = (a1reg << 12) | (0 << 11) | (1 << 15);
2087 int m_pbcc(WORD inst, WORD siz)
2090 return error("Not implemented yet.");
2095 // pflusha (68030, 68040)
2097 int m_pflusha(WORD inst, WORD siz)
2099 if (activecpu == CPU_68030)
2102 inst = (1 << 13) | (1 << 10) | (0 << 5) | 0;
2106 else if (activecpu == CPU_68040)
2108 inst = B16(11110101, 00011000);
2113 return error(unsupport);
2120 // pflush (68030, 68040, 68060)
2122 int m_pflush(WORD inst, WORD siz)
2124 if (activecpu == CPU_68030)
2127 // PFLUSH FC, MASK, < ea >
2135 if (*tok != CONST && *tok != SYMBOL)
2136 return error("function code should be an expression");
2138 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2141 if ((a0exattr & DEFINED) == 0)
2142 return error("function code immediate should be defined");
2144 if (a0exval > 7 && a0exval < 0)
2145 return error("function code out of range (0-7)");
2147 fc = (uint16_t)a0exval;
2157 fc = (1 << 4) | (*tok++ & 7);
2168 return error(syntax_error);
2172 return error("comma exptected");
2175 return error("mask should be an immediate value");
2177 if (*tok != CONST && *tok != SYMBOL)
2178 return error("mask is supposed to be immediate");
2180 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2183 if ((a0exattr & DEFINED) == 0)
2184 return error("mask immediate value should be defined");
2186 if (a0exval > 7 && a0exval < 0)
2187 return error("function code out of range (0-7)");
2189 mask = (uint16_t)a0exval << 5;
2195 inst = (1 << 13) | fc | mask | (4 << 10);
2199 else if (*tok == ',')
2201 // PFLUSH FC, MASK, < ea >
2204 if (amode(0) == ERROR)
2208 return error(extra_stuff);
2210 if (am0 == AIND || am0 == ABSW || am0 == ABSL || am0 == ADISP || am0 == ADISP || am0 == AINDEXED || am0 == ABASE || am0 == MEMPOST || am0 == MEMPRE)
2212 inst |= am0 | a0reg;
2214 inst = (1 << 13) | fc | mask | (6 << 10);
2220 return error("unsupported addressing mode");
2224 return error(syntax_error);
2228 else if (activecpu == CPU_68040 || activecpu == CPU_68060)
2232 if (*tok != '(' && tok[2] != ')')
2233 return error(syntax_error);
2235 if (tok[1] < KW_A0 && tok[1] > KW_A7)
2236 return error("expected (An)");
2238 if ((inst & 7) == 7)
2239 // With pflushn/pflush there's no easy way to distinguish between
2240 // the two in 68040 mode. Ideally the opcode bitfields would have
2241 // been hardcoded in 68ktab but there is aliasing between 68030
2242 // and 68040 opcode. So we just set the 3 lower bits to 1 in
2243 // pflushn inside 68ktab and detect it here.
2244 inst = (inst & 0xff8) | 8;
2246 inst |= (tok[1] & 7) | (5 << 8);
2249 return error(extra_stuff);
2254 return error(unsupport);
2263 int m_pflushr(WORD inst, WORD siz)
2267 WORD flg = inst; // Save flag bits
2268 inst &= ~0x3F; // Clobber flag bits in instr
2270 // Install "standard" instr size bits
2276 // OR-in register number
2278 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
2280 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
2286 inst |= am1 | a1reg; // Get ea1 into instr
2287 D_word(inst); // Deposit instr
2289 // Generate ea0 if requested
2293 ea1gen(siz); // Generate ea1
2298 inst |= am0 | a0reg; // Get ea0 into instr
2299 D_word(inst); // Deposit instr
2300 ea0gen(siz); // Generate ea0
2302 // Generate ea1 if requested
2307 D_word(B16(10100000, 00000000));
2313 // ploadr, ploadw (68030)
2315 int m_pload(WORD inst, WORD siz, WORD extension)
2317 // TODO: 68851 support is not added yet.
2318 // None of the ST series of computers had a 68020 + 68851 socket and since
2319 // this is an Atari targetted assembler...
2328 if (a0reg == KW_SFC - KW_SFC)
2330 else if (a0reg == KW_DFC - KW_SFC)
2333 return error("illegal control register specified");
2337 inst = (1 << 3) | a0reg;
2340 if ((a0exattr & DEFINED) == 0)
2341 return error("constant value must be defined");
2343 inst = (2 << 3) | (uint16_t)a0exval;
2347 inst |= extension | (1 << 13);
2356 int m_ploadr(WORD inst, WORD siz)
2358 return m_pload(inst, siz, 1 << 9);
2362 int m_ploadw(WORD inst, WORD siz)
2364 return m_pload(inst, siz, 0 << 9);
2369 // pmove (68030/68851)
2371 int m_pmove(WORD inst, WORD siz)
2375 // TODO: 68851 support is not added yet. None of the ST series of
2376 // computers had a 68020 + 68851 socket and since this is an Atari
2377 // targetted assembler.... (same for 68EC030)
2380 inst2 = inst & (1 << 8); // Copy the flush bit over to inst2 in case we're called from m_pmovefd
2381 inst &= ~(1 << 8); // And mask it out
2388 else if (am1 == CREG)
2394 return error("pmove sez: Wut?");
2396 // The instruction is a quad-word (8 byte) operation
2397 // for the CPU root pointer and the supervisor root pointer.
2398 // It is a long - word operation for the translation control register
2399 // and the transparent translation registers(TT0 and TT1).
2400 // It is a word operation for the MMU status register.
2402 if (((reg == (KW_URP - KW_SFC)) || (reg == (KW_SRP - KW_SFC)))
2403 && ((siz != SIZD) && (siz != SIZN)))
2404 return error(siz_error);
2406 if (((reg == (KW_TC - KW_SFC)) || (reg == (KW_TT0 - KW_SFC)) || (reg == (KW_TT1 - KW_SFC)))
2407 && ((siz != SIZL) && (siz != SIZN)))
2408 return error(siz_error);
2410 if ((reg == (KW_MMUSR - KW_SFC)) && ((siz != SIZW) && (siz != SIZN)))
2411 return error(siz_error);
2415 inst |= am1 | a1reg;
2418 else if (am1 == CREG)
2420 inst |= am0 | a0reg;
2424 switch (reg + KW_SFC)
2427 inst2 |= (0 << 10) + (1 << 14); break;
2429 inst2 |= (2 << 10) + (1 << 14); break;
2431 inst2 |= (3 << 10) + (1 << 14); break;
2433 inst2 |= (2 << 10) + (0 << 13); break;
2435 inst2 |= (3 << 10) + (0 << 13); break;
2438 inst2 |= (1 << 9) + (3 << 13);
2440 inst2 |= (0 << 9) + (3 << 13);
2443 return error("unsupported register");
2451 else if (am1 == CREG)
2461 int m_pmovefd(WORD inst, WORD siz)
2465 return m_pmove(inst | (1 << 8), siz);
2472 int m_ptrapcc(WORD inst, WORD siz)
2475 // We stash the 5 condition bits inside the opcode in 68ktab (bits 0-4),
2476 // so we need to extract them first and fill in the clobbered bits.
2477 WORD opcode = inst & 0x1F;
2478 inst = (inst & 0xFFE0) | (0x18);
2487 else if (siz == SIZL)
2494 else if (siz == SIZN)
2506 // ptestr, ptestw (68030)
2508 int m_ptest(WORD inst, WORD siz)
2512 if (activecpu == CPU_68030)
2513 return error("Not implemented yet.");
2514 else if (activecpu == CPU_68040)
2515 return error("Not implemented yet.");
2520 //////////////////////////////////////////////////////////////////////////////
2522 // 68020/30/40/60 instructions
2523 // Note: the map of which instructions are allowed on which CPUs came from the
2524 // 68060 manual, section D-1 (page 392 of the PDF). The current implementation
2525 // is missing checks for the EC models which have a simplified FPU.
2527 //////////////////////////////////////////////////////////////////////////////
2530 #define FPU_NOWARN 0
2535 // Generate a FPU opcode
2537 static inline int gen_fpu(WORD inst, WORD siz, WORD opmode, WORD emul)
2539 if (am0 < AM_NONE) // Check first operand for ea or fp - is this right?
2541 inst |= (1 << 9); // Bolt on FPU id
2544 //if (am0 == DREG || am0 == AREG)
2548 inst = 1 << 14; // R/M field (we have ea so have to set this to 1)
2552 case SIZB: inst |= (6 << 10); break;
2553 case SIZW: inst |= (4 << 10); break;
2554 case SIZL: inst |= (0 << 10); break;
2556 case SIZS: inst |= (1 << 10); break;
2557 case SIZD: inst |= (5 << 10); break;
2558 case SIZX: inst |= (2 << 10); break;
2563 warn("This encoding will cause an unimplemented data type exception in the MC68040 to allow emulation in software.");
2567 return error("Something bad happened, possibly, in gen_fpu.");
2571 inst |= (a1reg << 7);
2578 inst |= (1 << 9); // Bolt on FPU id
2582 inst |= (a1reg << 7);
2587 if ((emul & FPU_FPSP) && (activefpu == (FPU_68040 | FPU_68060)))
2588 warn("Instruction is emulated in 68040/060");
2595 // fabs (6888X, 68040FPSP, 68060FPSP)
2597 int m_fabs(WORD inst, WORD siz)
2600 return gen_fpu(inst, siz, B8(00011000), FPU_NOWARN);
2605 // fsabs (68040, 68060)
2607 int m_fsabs(WORD inst, WORD siz)
2610 if (activefpu == FPU_68040)
2611 return gen_fpu(inst, siz, B8(01011000), FPU_NOWARN);
2613 return error("Unsupported in current FPU");
2618 // fdabs (68040, 68060)
2620 int m_fdabs(WORD inst, WORD siz)
2622 if (activefpu == FPU_68040)
2623 return gen_fpu(inst, siz, B8(01011100), FPU_NOWARN);
2625 return error("Unsupported in current FPU");
2630 // facos (6888X, 68040FPSP, 68060FPSP)
2632 int m_facos(WORD inst, WORD siz)
2635 return gen_fpu(inst, siz, B8(00011100), FPU_FPSP);
2640 // fadd (6888X, 68040, 68060)
2642 int m_fadd(WORD inst, WORD siz)
2645 return gen_fpu(inst, siz, B8(00100010), FPU_NOWARN);
2650 // fsadd (68040, 68060)
2652 int m_fsadd(WORD inst, WORD siz)
2654 if (activefpu & (FPU_68040 | FPU_68060))
2655 return gen_fpu(inst, siz, B8(01100010), FPU_NOWARN);
2657 return error("Unsupported in current FPU");
2664 int m_fdadd(WORD inst, WORD siz)
2666 if (activefpu & (FPU_68040 | FPU_68060))
2667 return gen_fpu(inst, siz, B8(01100110), FPU_NOWARN);
2669 return error("Unsupported in current FPU");
2674 // fasin (6888X, 68040FPSP, 68060FPSP)
2676 int m_fasin(WORD inst, WORD siz)
2679 return gen_fpu(inst, siz, B8(00001100), FPU_FPSP);
2684 // fatan (6888X, 68040FPSP, 68060FPSP)
2686 int m_fatan(WORD inst, WORD siz)
2689 return gen_fpu(inst, siz, B8(00001010), FPU_FPSP);
2694 // fatanh (6888X, 68040FPSP, 68060FPSP)
2696 int m_fatanh(WORD inst, WORD siz)
2699 return gen_fpu(inst, siz, B8(00001101), FPU_FPSP);
2704 // fcmp (6888X, 68040, 68060)
2706 int m_fcmp(WORD inst, WORD siz)
2709 return gen_fpu(inst, siz, B8(00111000), FPU_FPSP);
2714 // fcos (6888X, 68040FPSP, 68060FPSP)
2716 int m_fcos(WORD inst, WORD siz)
2719 return gen_fpu(inst, siz, B8(00011101), FPU_FPSP);
2724 // fcosh (6888X, 68040FPSP, 68060FPSP)
2726 int m_fcosh(WORD inst, WORD siz)
2729 return gen_fpu(inst, siz, B8(00011001), FPU_FPSP);
2734 // fdbcc (6888X, 68040, 68060FPSP)
2736 int m_fdbcc(WORD inst, WORD siz)
2739 WORD opcode = inst & 0x3F; // Grab conditional bitfield
2749 if (a1exattr & DEFINED)
2751 if ((a1exattr & TDB) != cursect)
2752 return error(rel_error);
2754 uint32_t v = (uint32_t)a1exval - sloc;
2756 if ((v + 0x8000) > 0x10000)
2757 return error(range_error);
2763 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
2767 if (activefpu == FPU_68060)
2768 warn("Instruction is emulated in 68060");
2775 // fdiv (6888X, 68040, 68060)
2777 int m_fdiv(WORD inst, WORD siz)
2780 return gen_fpu(inst, siz, B8(00100000), FPU_NOWARN);
2785 // fsdiv (68040, 68060)
2787 int m_fsdiv(WORD inst, WORD siz)
2789 if (activefpu & (FPU_68040 | FPU_68060))
2790 return gen_fpu(inst, siz, B8(01100000), FPU_NOWARN);
2792 return error("Unsupported in current FPU");
2797 // fddiv (68040, 68060)
2799 int m_fddiv(WORD inst, WORD siz)
2801 if (activefpu & (FPU_68040 | FPU_68060))
2802 return gen_fpu(inst, siz, B8(01100100), FPU_NOWARN);
2804 return error("Unsupported in current FPU");
2809 // fetox (6888X, 68040FPSP, 68060FPSP)
2811 int m_fetox(WORD inst, WORD siz)
2814 return gen_fpu(inst, siz, B8(00010000), FPU_FPSP);
2819 // fetoxm1 (6888X, 68040FPSP, 68060FPSP)
2821 int m_fetoxm1(WORD inst, WORD siz)
2824 return gen_fpu(inst, siz, B8(00001000), FPU_FPSP);
2829 // fgetexp (6888X, 68040FPSP, 68060FPSP)
2831 int m_fgetexp(WORD inst, WORD siz)
2834 return gen_fpu(inst, siz, B8(00011110), FPU_FPSP);
2839 // fgetman (6888X, 68040FPSP, 68060FPSP)
2841 int m_fgetman(WORD inst, WORD siz)
2844 return gen_fpu(inst, siz, B8(00011111), FPU_FPSP);
2849 // fint (6888X, 68040FPSP, 68060)
2851 int m_fint(WORD inst, WORD siz)
2854 // special case - fint fpx = fint fpx,fpx
2857 if (activefpu == FPU_68040)
2858 warn("Instruction is emulated in 68040");
2860 return gen_fpu(inst, siz, B8(00000001), FPU_NOWARN);
2865 // fintrz (6888X, 68040FPSP, 68060)
2867 int m_fintrz(WORD inst, WORD siz)
2870 // special case - fintrz fpx = fintrz fpx,fpx
2873 if (activefpu == FPU_68040)
2874 warn("Instruction is emulated in 68040");
2876 return gen_fpu(inst, siz, B8(00000011), FPU_NOWARN);
2881 // flog10 (6888X, 68040FPSP, 68060FPSP)
2883 int m_flog10(WORD inst, WORD siz)
2886 return gen_fpu(inst, siz, B8(00010101), FPU_FPSP);
2891 // flog2 (6888X, 68040FPSP, 68060FPSP)
2893 int m_flog2(WORD inst, WORD siz)
2896 return gen_fpu(inst, siz, B8(00010110), FPU_FPSP);
2901 // flogn (6888X, 68040FPSP, 68060FPSP)
2903 int m_flogn(WORD inst, WORD siz)
2906 return gen_fpu(inst, siz, B8(00010100), FPU_FPSP);
2911 // flognp1 (68040FPSP, 68060FPSP)
2913 int m_flognp1(WORD inst, WORD siz)
2915 if (activefpu & (FPU_68040 | FPU_68060))
2916 return gen_fpu(inst, siz, B8(00000110), FPU_FPSP);
2918 return error("Unsupported in current FPU");
2923 // fmod (6888X, 68040FPSP, 68060FPSP)
2925 int m_fmod(WORD inst, WORD siz)
2928 return gen_fpu(inst, siz, B8(00100001), FPU_FPSP);
2933 // fmove (6888X, 68040, 68060)
2935 int m_fmove(WORD inst, WORD siz)
2940 if ((am0 == FREG) && (am1 < AM_USP))
2944 inst |= am1 | a1reg;
2953 case SIZB: inst |= (6 << 10); break;
2954 case SIZW: inst |= (4 << 10); break;
2955 case SIZL: inst |= (0 << 10); break;
2957 case SIZS: inst |= (1 << 10); break;
2958 case SIZD: inst |= (5 << 10); break;
2959 case SIZX: inst |= (2 << 10); break;
2960 case SIZP: inst |= (3 << 10);
2961 // In P size we have 2 cases: {#k} where k is immediate
2962 // and {Dn} where Dn=Data register
2967 inst |= bfval1 << 4;
2972 if (bfval1 > 63 && bfval1 < -64)
2973 return error("K-factor must be between -64 and 63");
2975 inst |= bfval1 & 127;
2980 return error("Something bad happened, possibly.");
2984 // Destination specifier
2985 inst |= (a0reg << 7);
2993 else if ((am0 < AM_USP) && (am1 == FREG))
2998 inst |= am0 | a0reg;
3007 case SIZB: inst |= (6 << 10); break;
3008 case SIZW: inst |= (4 << 10); break;
3009 case SIZL: inst |= (0 << 10); break;
3011 case SIZS: inst |= (1 << 10); break;
3012 case SIZD: inst |= (5 << 10); break;
3013 case SIZX: inst |= (2 << 10); break;
3014 case SIZP: inst |= (3 << 10); break;
3016 return error("Something bad happened, possibly.");
3020 // Destination specifier
3021 inst |= (a1reg << 7);
3029 else if ((am0 == FREG) && (am1 == FREG))
3031 // register-to-register
3032 // Essentially ea to register with R/0=0
3041 if (siz != SIZX && siz != SIZN)
3042 return error("Invalid size");
3045 inst |= (a0reg << 10);
3047 // Destination register
3048 inst |= (a1reg << 7);
3058 // fmove (6888X, 68040, 68060)
3060 int m_fmovescr(WORD inst, WORD siz)
3064 // Move Floating-Point System Control Register (FPCR)
3068 if ((am0 == FPSCR) && (am1 < AM_USP))
3070 inst |= am1 | a1reg;
3072 inst = (1 << 13) + (1 << 15);
3078 else if ((am1 == FPSCR) && (am0 < AM_USP))
3080 inst |= am0 | a0reg;
3082 inst = (0 << 13) + (1 << 15);
3089 return error("m_fmovescr says: wut?");
3093 // fsmove/fdmove (68040, 68060)
3095 int m_fsmove(WORD inst, WORD siz)
3097 if (!(activefpu & (FPU_68040 | FPU_68060)))
3098 return error("Unsupported in current FPU");
3100 return error("Not implemented yet.");
3103 if (activefpu == FPU_68040)
3104 return gen_fpu(inst, siz, B8(01100100), FPU_P_EMUL);
3106 return error("Unsupported in current FPU");
3111 int m_fdmove(WORD inst, WORD siz)
3113 if (!(activefpu & (FPU_68040 | FPU_68060)))
3114 return error("Unsupported in current FPU");
3116 return error("Not implemented yet.");
3119 if (activefpu == FPU_68040)
3120 return gen_fpu(inst, siz, B8(01100100), FPU_P_EMUL);
3122 return error("Unsupported in current FPU");
3128 // fmovecr (6888X, 68040FPSP, 68060FPSP)
3130 int m_fmovecr(WORD inst, WORD siz)
3140 if (activefpu == FPU_68040)
3141 warn("Instruction is emulated in 68040/060");
3148 // fmovem (6888X, 68040, 68060FPSP)
3150 int m_fmovem(WORD inst, WORD siz)
3157 if (siz == SIZX || siz == SIZN)
3159 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
3161 // fmovem.x <rlist>,ea
3162 if (fpu_reglist_left(®mask) < 0)
3166 return error("missing comma");
3171 inst |= am0 | a0reg;
3173 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3174 return error("invalid addressing mode");
3177 inst = (1 << 15) | (1 << 14) | (1 << 13) | (0 << 11) | regmask;
3182 else if ((*tok >= KW_D0) && (*tok <= KW_D7))
3185 datareg = (*tok++ & 7) << 10;
3188 return error("missing comma");
3193 inst |= am0 | a0reg;
3195 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3196 return error("invalid addressing mode");
3198 // Quote from the 060 manual:
3199 // "[..] when the processor attempts an FMOVEM.X instruction using a dynamic register list."
3200 if (activefpu == FPU_68060)
3201 warn("Instruction is emulated in 68060");
3204 inst = (1 << 15) | (1 << 14) | (1 << 13) | (1 << 11) | (datareg << 4);
3215 inst |= am0 | a0reg;
3218 return error("missing comma");
3220 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
3222 // fmovem.x ea,<rlist>
3223 if (fpu_reglist_right(®mask) < 0)
3227 inst = (1 << 15) | (1 << 14) | (0 << 13) | (2 << 11) | regmask;
3235 datareg = (*tok++ & 7) << 10;
3237 // Quote from the 060 manual:
3238 // "[..] when the processor attempts an FMOVEM.X instruction using a dynamic register list."
3239 if (activefpu == FPU_68060)
3240 warn("Instruction is emulated in 68060");
3243 inst = (1 << 15) | (1 << 14) | (0 << 13) | (3 << 11) | (datareg << 4);
3250 else if (siz == SIZL)
3252 if ((*tok == KW_FPCR) || (*tok == KW_FPSR) || (*tok == KW_FPIAR))
3254 // fmovem.l <rlist>,ea
3255 regmask = (1 << 15) | (1 << 13);
3256 int no_control_regs = 0;
3259 if (*tok == KW_FPCR)
3261 regmask |= (1 << 12);
3267 if (*tok == KW_FPSR)
3269 regmask |= (1 << 11);
3275 if (*tok == KW_FPIAR)
3277 regmask |= (1 << 10);
3283 if ((*tok == '/') || (*tok == '-'))
3290 return error("missing comma");
3295 // Quote from the 060 manual:
3296 // "[..] when the processor attempts to execute an FMOVEM.L instruction with
3297 // an immediate addressing mode to more than one floating - point
3298 // control register (FPCR, FPSR, FPIAR)[..]"
3299 if (activefpu == FPU_68060)
3300 if (no_control_regs > 1 && am0 == IMMED)
3301 warn("Instruction is emulated in 68060");
3303 inst |= am0 | a0reg;
3310 // fmovem.l ea,<rlist>
3314 inst |= am0 | a0reg;
3317 return error("missing comma");
3319 regmask = (1 << 15) | (0 << 13);
3322 if (*tok == KW_FPCR)
3324 regmask |= (1 << 12);
3329 if (*tok == KW_FPSR)
3331 regmask |= (1 << 11);
3336 if (*tok == KW_FPIAR)
3338 regmask |= (1 << 10);
3343 if ((*tok == '/') || (*tok == '-'))
3350 return error("extra (unexpected) text found");
3352 inst |= am0 | a0reg;
3359 return error("bad size suffix");
3366 // fmul (6888X, 68040, 68060)
3368 int m_fmul(WORD inst, WORD siz)
3371 return gen_fpu(inst, siz, B8(00100011), FPU_NOWARN);
3376 // fsmul (68040, 68060)
3378 int m_fsmul(WORD inst, WORD siz)
3380 if (activefpu & (FPU_68040 | FPU_68060))
3381 return gen_fpu(inst, siz, B8(01100011), FPU_NOWARN);
3383 return error("Unsupported in current FPU");
3390 int m_fdmul(WORD inst, WORD siz)
3392 if (activefpu & (FPU_68040 | FPU_68060))
3393 return gen_fpu(inst, siz, B8(01100111), FPU_NOWARN);
3395 return error("Unsupported in current FPU");
3400 // fneg (6888X, 68040, 68060)
3402 int m_fneg(WORD inst, WORD siz)
3409 return gen_fpu(inst, siz, B8(00011010), FPU_NOWARN);
3412 return gen_fpu(inst, siz, B8(00011010), FPU_NOWARN);
3417 // fsneg (68040, 68060)
3419 int m_fsneg(WORD inst, WORD siz)
3421 if (activefpu & (FPU_68040 | FPU_68060))
3426 return gen_fpu(inst, siz, B8(01011010), FPU_NOWARN);
3429 return gen_fpu(inst, siz, B8(01011010), FPU_NOWARN);
3432 return error("Unsupported in current FPU");
3437 // fdneg (68040, 68060)
3439 int m_fdneg(WORD inst, WORD siz)
3441 if (activefpu & (FPU_68040 | FPU_68060))
3446 return gen_fpu(inst, siz, B8(01011110), FPU_NOWARN);
3449 return gen_fpu(inst, siz, B8(01011110), FPU_NOWARN);
3452 return error("Unsupported in current FPU");
3457 // fnop (6888X, 68040, 68060)
3459 int m_fnop(WORD inst, WORD siz)
3462 return gen_fpu(inst, siz, B8(00000000), FPU_NOWARN);
3467 // frem (6888X, 68040FPSP, 68060FPSP)
3469 int m_frem(WORD inst, WORD siz)
3472 return gen_fpu(inst, siz, B8(00100101), FPU_FPSP);
3477 // fscale (6888X, 68040FPSP, 68060FPSP)
3479 int m_fscale(WORD inst, WORD siz)
3482 return gen_fpu(inst, siz, B8(00100110), FPU_FPSP);
3487 // FScc (6888X, 68040, 68060), cpScc (68851, 68030), PScc (68851)
3488 // TODO: Add check for PScc to ensure 68020+68851 active
3489 // TODO: Add check for cpScc to ensure 68020+68851, 68030
3491 int m_fscc(WORD inst, WORD siz)
3495 // We stash the 5 condition bits inside the opcode in 68ktab (bits 4-0),
3496 // so we need to extract them first and fill in the clobbered bits.
3497 WORD opcode = inst & 0x1F;
3499 inst |= am0 | a0reg;
3503 if (activefpu == FPU_68060)
3504 warn("Instruction is emulated in 68060");
3510 // fsgldiv (6888X, 68040FPSP, 68060FPSP)
3512 int m_fsgldiv(WORD inst, WORD siz)
3515 return gen_fpu(inst, siz, B8(00100100), FPU_FPSP);
3520 // fsglmul (6888X, 68040, 68060FPSP)
3522 int m_fsglmul(WORD inst, WORD siz)
3525 return gen_fpu(inst, siz, B8(00100111), FPU_FPSP);
3530 // fsin (6888X, 68040FPSP, 68060FPSP)
3532 int m_fsin(WORD inst, WORD siz)
3535 return gen_fpu(inst, siz, B8(00001110), FPU_FPSP);
3540 // fsincos (6888X, 68040FPSP, 68060FPSP)
3542 int m_fsincos(WORD inst, WORD siz)
3546 // Swap a1reg, a2reg as a2reg should be stored in the bitfield gen_fpu
3553 if (gen_fpu(inst, siz, B8(00110000), FPU_FPSP) == OK)
3564 // fsinh (6888X, 68040FPSP, 68060FPSP)
3566 int m_fsinh(WORD inst, WORD siz)
3569 return gen_fpu(inst, siz, B8(00000010), FPU_FPSP);
3574 // fsqrt (6888X, 68040, 68060)
3576 int m_fsqrt(WORD inst, WORD siz)
3579 return gen_fpu(inst, siz, B8(00000100), FPU_NOWARN);
3584 // fsfsqrt (68040, 68060)
3586 int m_fsfsqrt(WORD inst, WORD siz)
3588 if (activefpu & (FPU_68040 | FPU_68060))
3589 return gen_fpu(inst, siz, B8(01000001), FPU_NOWARN);
3591 return error("Unsupported in current FPU");
3596 // fdfsqrt (68040, 68060)
3598 int m_fdfsqrt(WORD inst, WORD siz)
3600 if (activefpu & (FPU_68040 | FPU_68060))
3601 return gen_fpu(inst, siz, B8(01000101), FPU_NOWARN);
3603 return error("Unsupported in current FPU");
3608 // fsub (6888X, 68040, 68060)
3610 int m_fsub(WORD inst, WORD siz)
3613 return gen_fpu(inst, siz, B8(00101000), FPU_NOWARN);
3618 // fsfsub (68040, 68060)
3620 int m_fsfsub(WORD inst, WORD siz)
3622 if (activefpu & (FPU_68040 | FPU_68060))
3623 return gen_fpu(inst, siz, B8(01101000), FPU_NOWARN);
3625 return error("Unsupported in current FPU");
3630 // fdfsub (68040, 68060)
3632 int m_fdsub(WORD inst, WORD siz)
3634 if (activefpu & (FPU_68040 | FPU_68060))
3635 return gen_fpu(inst, siz, B8(01101100), FPU_NOWARN);
3637 return error("Unsupported in current FPU");
3642 // ftan (6888X, 68040FPSP, 68060FPSP)
3644 int m_ftan(WORD inst, WORD siz)
3647 return gen_fpu(inst, siz, B8(00001111), FPU_FPSP);
3652 // ftanh (6888X, 68040FPSP, 68060FPSP)
3654 int m_ftanh(WORD inst, WORD siz)
3657 return gen_fpu(inst, siz, B8(00001001), FPU_FPSP);
3662 // ftentox (6888X, 68040FPSP, 68060FPSP)
3664 int m_ftentox(WORD inst, WORD siz)
3667 return gen_fpu(inst, siz, B8(00010010), FPU_FPSP);
3672 // FTRAPcc (6888X, 68040, 68060FPSP)
3674 int m_ftrapcc(WORD inst, WORD siz)
3678 // We stash the 5 condition bits inside the opcode in 68ktab (bits 3-7),
3679 // so we need to extract them first and fill in the clobbered bits.
3680 WORD opcode = (inst >> 3) & 0x1F;
3681 inst = (inst & 0xFF07) | (0xF << 3);
3690 else if (siz == SIZL)
3697 else if (siz == SIZN)
3705 if (activefpu == FPU_68060)
3706 warn("Instruction is emulated in 68060");
3713 // ftst (6888X, 68040, 68060)
3715 int m_ftst(WORD inst, WORD siz)
3718 return gen_fpu(inst, siz, B8(00111010), FPU_NOWARN);
3723 // ftwotox (6888X, 68040FPSP, 68060FPSP)
3725 int m_ftwotox(WORD inst, WORD siz)
3728 return gen_fpu(inst, siz, B8(00010001), FPU_FPSP);