2 // RMAC - Reboot's Macro Assembler for all Atari computers
3 // MACH.C - Code Generation
4 // Copyright (C) 199x Landon Dyer, 2011-2020 Reboot and Friends
5 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
6 // Source utilised with the kind permission of Landon Dyer
24 int movep = 0; // Global flag to indicate we're generating a movep instruction
26 // Function prototypes
27 int m_unimp(WORD, WORD), m_badmode(WORD, WORD);
28 int m_self(WORD, WORD);
29 int m_abcd(WORD, WORD);
30 int m_reg(WORD, WORD);
31 int m_imm(WORD, WORD);
32 int m_imm8(WORD, WORD);
33 int m_shi(WORD, WORD);
34 int m_shr(WORD, WORD);
35 int m_bitop(WORD, WORD);
36 int m_exg(WORD, WORD);
38 int m_lea(WORD, WORD);
40 int m_dbra(WORD, WORD);
41 int m_link(WORD, WORD);
42 int m_adda(WORD, WORD);
43 int m_addq(WORD, WORD);
44 int m_move(WORD, WORD);
45 int m_moveq(WORD, WORD);
46 int m_usp(WORD, WORD);
47 int m_movep(WORD, WORD);
48 int m_trap(WORD, WORD);
49 int m_movem(WORD, WORD);
50 int m_clra(WORD, WORD);
51 int m_clrd(WORD, WORD);
53 int m_move30(WORD, WORD); // 68020/30/40/60
54 int m_br30(WORD inst, WORD siz);
55 int m_ea030(WORD inst, WORD siz);
56 int m_bfop(WORD inst, WORD siz);
57 int m_callm(WORD inst, WORD siz);
58 int m_cas(WORD inst, WORD siz);
59 int m_cas2(WORD inst, WORD siz);
60 int m_chk2(WORD inst, WORD siz);
61 int m_cmp2(WORD inst, WORD siz);
62 int m_bkpt(WORD inst, WORD siz);
63 int m_cpbcc(WORD inst, WORD siz);
64 int m_cpdbr(WORD inst, WORD siz);
65 int m_muls(WORD inst, WORD siz);
66 int m_move16a(WORD inst, WORD siz);
67 int m_move16b(WORD inst, WORD siz);
68 int m_pack(WORD inst, WORD siz);
69 int m_rtm(WORD inst, WORD siz);
70 int m_rtd(WORD inst, WORD siz);
71 int m_trapcc(WORD inst, WORD siz);
72 int m_cinv(WORD inst, WORD siz);
73 int m_cprest(WORD inst, WORD siz);
74 int m_movec(WORD inst, WORD siz);
75 int m_moves(WORD inst, WORD siz);
76 int m_lpstop(WORD inst, WORD siz);
77 int m_plpa(WORD inst, WORD siz);
80 int m_pbcc(WORD inst, WORD siz);
81 int m_pflusha(WORD inst, WORD siz);
82 int m_pflush(WORD inst, WORD siz);
83 int m_pflushr(WORD inst, WORD siz);
84 int m_pflushan(WORD inst, WORD siz);
85 int m_pload(WORD inst, WORD siz, WORD extension);
86 int m_pmove(WORD inst, WORD siz);
87 int m_pmovefd(WORD inst, WORD siz);
88 int m_ptest(WORD inst, WORD siz, WORD extension);
89 int m_ptestr(WORD inste, WORD siz);
90 int m_ptestw(WORD inste, WORD siz);
91 int m_ptrapcc(WORD inst, WORD siz);
92 int m_ploadr(WORD inst, WORD siz);
93 int m_ploadw(WORD inst, WORD siz);
96 int m_fabs(WORD inst, WORD siz);
97 int m_fbcc(WORD inst, WORD siz);
98 int m_facos(WORD inst, WORD siz);
99 int m_fadd(WORD inst, WORD siz);
100 int m_fasin(WORD inst, WORD siz);
101 int m_fatan(WORD inst, WORD siz);
102 int m_fatanh(WORD inst, WORD siz);
103 int m_fcmp(WORD inst, WORD siz);
104 int m_fcos(WORD inst, WORD siz);
105 int m_fcosh(WORD inst, WORD siz);
106 int m_fdabs(WORD inst, WORD siz);
107 int m_fdadd(WORD inst, WORD siz);
108 int m_fdbcc(WORD inst, WORD siz);
109 int m_fddiv(WORD inst, WORD siz);
110 int m_fdfsqrt(WORD inst, WORD siz);
111 int m_fdiv(WORD inst, WORD siz);
112 int m_fdmove(WORD inst, WORD siz);
113 int m_fdmul(WORD inst, WORD siz);
114 int m_fdneg(WORD inst, WORD siz);
115 int m_fdsub(WORD inst, WORD siz);
116 int m_fetox(WORD inst, WORD siz);
117 int m_fetoxm1(WORD inst, WORD siz);
118 int m_fgetexp(WORD inst, WORD siz);
119 int m_fgetman(WORD inst, WORD siz);
120 int m_fint(WORD inst, WORD siz);
121 int m_fintrz(WORD inst, WORD siz);
122 int m_flog10(WORD inst, WORD siz);
123 int m_flog2(WORD inst, WORD siz);
124 int m_flogn(WORD inst, WORD siz);
125 int m_flognp1(WORD inst, WORD siz);
126 int m_fmod(WORD inst, WORD siz);
127 int m_fmove(WORD inst, WORD siz);
128 int m_fmovescr(WORD inst, WORD siz);
129 int m_fmovecr(WORD inst, WORD siz);
130 int m_fmovem(WORD inst, WORD siz);
131 int m_fmul(WORD inst, WORD siz);
132 int m_fneg(WORD inst, WORD siz);
133 int m_fnop(WORD inst, WORD siz);
134 int m_frem(WORD inst, WORD siz);
135 int m_frestore(WORD inst, WORD siz);
136 int m_fsabs(WORD inst, WORD siz);
137 int m_fsadd(WORD inst, WORD siz);
138 int m_fscc(WORD inst, WORD siz);
139 int m_fscale(WORD inst, WORD siz);
140 int m_fsdiv(WORD inst, WORD siz);
141 int m_fsfsqrt(WORD inst, WORD siz);
142 int m_fsfsub(WORD inst, WORD siz);
143 int m_fsgldiv(WORD inst, WORD siz);
144 int m_fsglmul(WORD inst, WORD siz);
145 int m_fsin(WORD inst, WORD siz);
146 int m_fsincos(WORD inst, WORD siz);
147 int m_fsinh(WORD inst, WORD siz);
148 int m_fsmove(WORD inst, WORD siz);
149 int m_fsmul(WORD inst, WORD siz);
150 int m_fsneg(WORD inst, WORD siz);
151 int m_fsqrt(WORD inst, WORD siz);
152 int m_fsub(WORD inst, WORD siz);
153 int m_ftan(WORD inst, WORD siz);
154 int m_ftanh(WORD inst, WORD siz);
155 int m_ftentox(WORD inst, WORD siz);
156 int m_ftst(WORD inst, WORD siz);
157 int m_ftwotox(WORD inst, WORD siz);
158 int m_ftrapcc(WORD inst, WORD siz);
160 // Common error messages
161 char range_error[] = "expression out of range";
162 char abs_error[] = "illegal absolute expression";
163 char seg_error[] = "bad (section) expression";
164 char rel_error[] = "illegal relative address";
165 char siz_error[] = "bad size specified";
166 char undef_error[] = "undefined expression";
167 char fwd_error[] = "forward or undefined expression";
168 char unsupport[] = "unsupported for selected CPU";
170 // Include code tables
172 { 0xFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000, 0, m_badmode }, // 0
174 { 0, 0L, 0L, 0x0000, 0, m_unimp } // Last entry
177 // Register number << 9
179 0, 1 << 9, 2 << 9, 3 << 9, 4 << 9, 5 << 9, 6 << 9, 7 << 9
182 // SIZB==>00, SIZW==>01, SIZL==>10, SIZN==>01 << 6
186 1<<6, (WORD)-1, // SIZW, n/a
187 2<<6, (WORD)-1, (WORD)-1, (WORD)-1, // SIZL, n/a, n/a, n/a
191 // Byte/word/long size for MOVE instrs
195 0x3000, (WORD)-1, // Word
196 0x2000, (WORD)-1, (WORD)-1, (WORD)-1, // Long
197 0x3000 // Word (SIZN)
200 // Word/long size (0=.w, 1=.l) in bit 8
204 0, (WORD)-1, // SIZW, n/a
205 1<<8, (WORD)-1, (WORD)-1, (WORD)-1, // SIZL, n/a, n/a, n/a
209 // Byte/Word/long size (0=.w, 1=.l) in bit 9
213 1<<9, (WORD)-1, // Word
214 1<<10, (WORD)-1, (WORD)-1, (WORD)-1, // Long
218 // Addressing mode in bits 6..11 (register/mode fields are reversed)
220 00000, 01000, 02000, 03000, 04000, 05000, 06000, 07000,
221 00100, 01100, 02100, 03100, 04100, 05100, 06100, 07100,
222 00200, 01200, 02200, 03200, 04200, 05200, 06200, 07200,
223 00300, 01300, 02300, 03300, 04300, 05300, 06300, 07300,
224 00400, 01400, 02400, 03400, 04400, 05400, 06400, 07400,
225 00500, 01500, 02500, 03500, 04500, 05500, 06500, 07500,
226 00600, 01600, 02600, 03600, 04600, 05600, 06600, 07600,
227 00700, 01700, 02700, 03700, 04700, 05700, 06700, 07700
230 // Control registers lookup table
232 // MC68010/MC68020/MC68030/MC68040/CPU32
233 0x000, // Source Function Code(SFC)
234 0x001, // Destination Function Code(DFC)
235 0x800, // User Stack Pointer(USP)
236 0x801, // Vector Base Register(VBR)
237 // MC68020 / MC68030 / MC68040
238 0x002, // Cache Control Register(CACR)
239 0x802, // Cache Address Register(CAAR) (020/030 only)
240 0x803, // Master Stack Pointer(MSP)
241 0x804, // Interrupt Stack Pointer(ISP)
242 // MC68040 / MC68LC040
243 0x003, // MMU Translation Control Register(TC)
244 0x004, // Instruction Transparent Translation Register 0 (ITT0)
245 0x005, // Instruction Transparent Translation Register 1 (ITT1)
246 0x006, // Data Transparent Translation Register 0 (DTT0)
247 0x007, // Data Transparent Translation Register 1 (DTT1)
248 0x805, // MMU Status Register(MMUSR)
249 0x806, // User Root Pointer(URP)
250 0x807, // Supervisor Root Pointer(SRP)
252 0x004, // Instruction Access Control Register 0 (IACR0)
253 0x005, // Instruction Access Control Register 1 (IACR1)
254 0x006, // Data Access Control Register 0 (DACR1)
255 0x007, // Data Access Control Register 1 (DACR1)
257 0xFFF // CPU Root Pointer (CRP) - There's no movec with CRP in it, this is just a guard entry
262 int m_unimp(WORD unused1, WORD unused2)
264 return (int)error("unimplemented mnemonic");
268 //int m_badmode(void)
269 int m_badmode(WORD unused1, WORD unused2)
271 return (int)error("inappropriate addressing mode");
275 int m_self(WORD inst, WORD usused)
283 // Do one EA in bits 0..5
285 // Bits in `inst' have the following meaning:
287 // Bit zero specifies which ea (ea0 or ea1) to generate in the lower six bits
290 // If bit one is set, the OTHER ea (the one that wasn't generated by bit zero)
291 // is generated after the instruction. Regardless of bit 0's value, ea0 is
292 // always deposited in memory before ea1.
294 // If bit two is set, standard size bits are set in the instr in bits 6 and 7.
296 // If bit four is set, bit three specifies which eaXreg to place in bits 9..11
299 int m_ea(WORD inst, WORD siz)
301 WORD flg = inst; // Save flag bits
302 inst &= ~0x3F; // Clobber flag bits in instr
304 // Install "standard" instr size bits
310 // OR-in register number
312 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
314 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
320 inst |= am1 | a1reg; // Get ea1 into instr
321 D_word(inst); // Deposit instr
323 // Generate ea0 if requested
327 ea1gen(siz); // Generate ea1
332 inst |= am0 | a0reg; // Get ea0 into instr
333 D_word(inst); // Deposit instr
334 ea0gen(siz); // Generate ea0
336 // Generate ea1 if requested
346 // Check if lea x(an),an can be optimised to addq.w #x,an--otherwise fall back
349 int m_lea(WORD inst, WORD siz)
351 if (CHECK_OPTS(OPT_LEA_ADDQ)
352 && ((am0 == ADISP) && (a0reg == a1reg) && (a0exattr & DEFINED))
353 && ((a0exval > 0) && (a0exval <= 8)))
355 inst = B16(01010000, 01001000) | (((uint16_t)a0exval & 7) << 9) | (a0reg);
359 warn("lea size(An),An converted to addq #size,An");
364 return m_ea(inst, siz);
368 int m_ea030(WORD inst, WORD siz)
371 WORD flg = inst; // Save flag bits
372 inst &= ~0x3F; // Clobber flag bits in instr
374 // Install "standard" instr size bits
380 // OR-in register number
383 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
387 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
394 inst |= am1 | a1reg; // Get ea1 into instr
395 D_word(inst); // Deposit instr
397 // Generate ea0 if requested
401 ea1gen(siz); // Generate ea1
407 // We get here if we're doing 020+ addressing and an address
408 // register is used. For example, something like "tst a0". A bit of
409 // a corner case, so kludge it
411 else if (am0 == PCDISP)
412 // Another corner case (possibly!), so kludge ahoy
413 inst |= am0; // Get ea0 into instr
414 else if (am0 == IMMED && am1 == MEMPOST)
416 // Added for addi/andi/cmpi/eori/ori/subi #xx,(bd,An,Dm)
417 inst |= a1reg | AINDEXED;
419 else if (am0 == IMMED)
420 inst |= am0 | a0reg; // Get ea0 into instr
421 else if (am0 == AM_CCR)
423 else if (am0 == AIND)
426 inst |= a0reg; // Get ea0 into instr
427 D_word(inst); // Deposit instr
428 ea0gen(siz); // Generate ea0
430 // Generate ea1 if requested
440 // Dx,Dy nnnnXXXnssnnnYYY If bit 0 of `inst' is set, install size bits in bits
443 int m_abcd(WORD inst, WORD siz)
452 inst |= a0reg | reg_9[a1reg];
462 int m_adda(WORD inst, WORD siz)
464 if ((a0exattr & DEFINED) && (am0 == IMMED))
466 if (CHECK_OPTS(OPT_ADDA_ADDQ))
468 if ((a0exval > 1) && (a0exval <= 8))
470 // Immediate is between 1 and 8 so let's convert to addq
471 return m_addq(B16(01010000, 00000000), siz);
474 warn("adda/suba size(An),An converted to addq/subq #size,An");
478 if (CHECK_OPTS(OPT_ADDA_LEA))
480 if ((a0exval > 8) && ((a0exval + 0x8000) < 0x10000))
482 // Immediate is larger than 8 and word size so let's convert to lea
483 am0 = ADISP; // Change addressing mode
484 a0reg = a1reg; // In ADISP a0reg is used instead of a1reg!
486 if (!(inst & (1 << 14)))
488 // We have a suba #x,AREG so let's negate the value
492 // We're going to rely on +o4 for this, so let's ensure that
493 // it's on, even just for this instruction
495 int temp_flag = optim_flags[OPT_LEA_ADDQ];
496 optim_flags[OPT_LEA_ADDQ] = 1; // Temporarily save switch state
497 return_value = m_lea(B16(01000001, 11011000), SIZW);
498 optim_flags[OPT_LEA_ADDQ] = temp_flag; // Restore switch state
504 inst |= am0 | a0reg | lwsiz_8[siz] | reg_9[a1reg];
506 ea0gen(siz); // Generate EA
513 // If bit 0 of `inst' is 1, install size bits in bits 6..7 of instr.
514 // If bit 1 of `inst' is 1, install a1reg in bits 9..11 of instr.
516 int m_reg(WORD inst, WORD siz)
523 // Install other register (9..11)
524 inst |= reg_9[a1reg];
526 inst &= ~7; // Clear off crufty bits
527 inst |= a0reg; // Install first register
537 int m_imm(WORD inst, WORD siz)
549 int m_imm8(WORD inst, WORD siz)
562 int m_shr(WORD inst, WORD siz)
564 inst |= reg_9[a0reg] | a1reg | siz_6[siz];
574 int m_shi(WORD inst, WORD siz)
576 inst |= a1reg | siz_6[siz];
578 if (a0exattr & DEFINED)
581 return error(range_error);
583 inst |= (a0exval & 7) << 9;
588 AddFixup(FU_QUICK, sloc, a0expr);
597 // {bset, btst, bchg, bclr} -- #immed,ea -- Dn,ea
599 int m_bitop(WORD inst, WORD siz)
601 // Enforce instruction sizes
603 { // X,Dn must be .n or .l
604 if (siz & (SIZB | SIZW))
605 return error(siz_error);
607 else if (siz & (SIZW | SIZL)) // X,ea must be .n or .b
608 return error(siz_error);
610 // Construct instr and EAs
616 ea0gen(SIZB); // Immediate bit number
620 inst |= reg_9[a0reg];
631 int m_dbra(WORD inst, WORD siz)
637 if (a1exattr & DEFINED)
639 if ((a1exattr & TDB) != cursect)
640 return error(rel_error);
642 uint32_t v = (uint32_t)a1exval - sloc;
644 if (v + 0x8000 > 0x10000)
645 return error(range_error);
651 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
662 int m_exg(WORD inst, WORD siz)
668 if (am0 == DREG && am1 == DREG)
670 else if (am0 == AREG && am1 == AREG)
676 m = a1reg; // Get AREG into a1reg
684 inst |= m | reg_9[a0reg] | a1reg;
694 int m_link(WORD inst, WORD siz)
698 // Is this an error condition???
703 inst &= ~((3 << 9) | (1 << 6) | (1 << 4));
715 WORD extra_addressing[16]=
717 0x30, // 0100 (bd,An,Xn)
718 0x30, // 0101 ([bd,An],Xn,od)
719 0x30, // 0102 ([bc,An,Xn],od)
720 0x30, // 0103 (bd,PC,Xn)
721 0x30, // 0104 ([bd,PC],Xn,od)
722 0x30, // 0105 ([bc,PC,Xn],od)
737 // Handle MOVE <C_ALL> <C_ALTDATA>
738 // MOVE <C_ALL> <M_AREG>
740 // Optimize MOVE.L #<smalldata>,D0 to a MOVEQ
742 int m_move(WORD inst, WORD size)
744 // Cast the passed in value to an int
747 // Try to optimize to MOVEQ
748 // N.B.: We can get away with casting the uint64_t to a 32-bit value
749 // because it checks for a SIZL (i.e., a 32-bit value).
750 if (CHECK_OPTS(OPT_MOVEL_MOVEQ)
751 && (siz == SIZL) && (am0 == IMMED) && (am1 == DREG)
752 && ((a0exattr & (TDB | DEFINED)) == DEFINED)
753 && ((uint32_t)a0exval + 0x80 < 0x100))
755 m_moveq((WORD)0x7000, (WORD)0);
758 warn("move.l #size,dx converted to moveq");
762 if ((am0 < ABASE) && (am1 < ABASE)) // 68000 modes
764 inst |= siz_12[siz] | am_6[am1] | reg_9[a1reg] | am0 | a0reg;
772 ea1gen((WORD)siz | 0x8000); // Tell ea1gen we're move ea,ea
776 inst |= siz_12[siz] | reg_9[a1reg] | extra_addressing[am0 - ABASE];
793 // Handle MOVE <C_ALL030> <C_ALTDATA>
794 // MOVE <C_ALL030> <M_AREG>
796 int m_move30(WORD inst, WORD size)
800 inst |= siz_12[siz] | reg_9[a1reg & 7] | a0reg | extra_addressing[am0 - ABASE];
802 inst |= siz_12[siz] | reg_9[a1reg & 7] | a0reg | extra_addressing[am1 - ABASE] << 3;
817 // move USP,An -- move An,USP
819 int m_usp(WORD inst, WORD siz)
824 inst |= a1reg; // USP, An
826 inst |= a0reg; // An, USP
837 int m_moveq(WORD inst, WORD siz)
841 // Arrange for future fixup
842 if (!(a0exattr & DEFINED))
844 AddFixup(FU_BYTE | FU_SEXT, sloc + 1, a0expr);
847 else if ((uint32_t)a0exval + 0x100 >= 0x200)
848 return error(range_error);
850 inst |= reg_9[a1reg] | (a0exval & 0xFF);
858 // movep Dn, disp(An) -- movep disp(An), Dn
860 int m_movep(WORD inst, WORD siz)
862 // Tell ea0gen to lay off the 0(a0) optimisations on this one
870 inst |= reg_9[a0reg] | a1reg;
880 inst |= reg_9[a1reg] | a0reg;
897 int m_br(WORD inst, WORD siz)
899 if (a0exattr & DEFINED)
901 if ((a0exattr & TDB) != cursect)
903 //printf("m_br(): a0exattr = %X, cursect = %X, a0exval = %X, sloc = %X\n", a0exattr, cursect, a0exval, sloc);
904 return error(rel_error);
907 uint32_t v = (uint32_t)a0exval - (sloc + 2);
909 // Optimize branch instr. size
912 if (CHECK_OPTS(OPT_BSR_BCC_S) && (v != 0) && ((v + 0x80) < 0x100))
919 warn("Bcc.w/BSR.w converted to .s");
926 if ((v + 0x8000) > 0x10000)
927 return error(range_error);
935 if (siz == SIZB || siz == SIZS)
937 if ((v + 0x80) >= 0x100)
938 return error(range_error);
945 if ((v + 0x8000) >= 0x10000)
946 return error(range_error);
954 else if (siz == SIZN)
957 if (siz == SIZB || siz == SIZS)
960 AddFixup(FU_BBRA | FU_PCREL | FU_SEXT, sloc, a0expr);
961 // So here we have a small issue: this bra.s could be zero offset, but
962 // we can never know. Because unless we know beforehand that the
963 // offset will be zero (i.e. "bra.s +0"), it's going to be a label
964 // below this instruction! We do have an optimisation flag that can
965 // check against this during fixups, but we cannot rely on the state
966 // of the flag after all the file(s) have been processed because its
967 // state might have changed multiple times during file parsing. (Yes,
968 // there's a very low chance that this will ever happen but it's not
969 // zero!). So, we can use the byte that is going to be filled during
970 // fixups to store the state of the optimisation flag and read it
971 // during that stage so each bra.s will have its state stored neatly.
972 // Sleazy? Eh, who cares, like this will ever happen ;)
973 // One final note: we'd better be damn sure that the flag's value is
974 // less than 256 or magical stuff will happen!
975 D_word(inst | optim_flags[OPT_NULL_BRA]);
982 AddFixup(FU_WORD | FU_PCREL | FU_LBRA | FU_ISBRA, sloc, a0expr);
993 int m_addq(WORD inst, WORD siz)
995 inst |= siz_6[siz] | am1 | a1reg;
997 if (a0exattr & DEFINED)
999 if ((a0exval > 8) || (a0exval == 0)) // Range in 1..8
1000 return error(range_error);
1002 inst |= (a0exval & 7) << 9;
1007 AddFixup(FU_QUICK, sloc, a0expr);
1020 int m_trap(WORD inst, WORD siz)
1024 if (a0exattr & DEFINED)
1027 return error(abs_error);
1030 return error(range_error);
1036 return error(undef_error);
1043 // movem <rlist>,ea -- movem ea,<rlist>
1045 int m_movem(WORD inst, WORD siz)
1053 return error("bad size suffix");
1060 // Handle #<expr>, ea
1063 if (abs_expr(&eval) != OK)
1066 if (eval >= 0x10000L)
1067 return error(range_error);
1073 if ((*tok >= KW_D0) && (*tok <= KW_A7))
1076 if (reglist(&rmask) < 0)
1081 return error("missing comma");
1086 inst |= am0 | a0reg;
1088 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
1089 return error("invalid addressing mode");
1091 // If APREDEC, reverse register mask
1097 for(i=0x8000; i; i>>=1, w>>=1)
1098 rmask = (WORD)((rmask << 1) | (w & 1));
1107 inst |= 0x0400 | am0 | a0reg;
1110 return error("missing comma");
1113 return error("missing register list");
1120 if (abs_expr(&eval) != OK)
1123 if (eval >= 0x10000)
1124 return error(range_error);
1128 else if (reglist(&rmask) < 0)
1131 if (!(amsktab[am0] & (C_CTRL | M_APOSTINC)))
1132 return error("invalid addressing mode");
1144 // CLR.x An ==> SUBA.x An,An
1146 int m_clra(WORD inst, WORD siz)
1148 inst |= a0reg | reg_9[a0reg] | lwsiz_8[siz];
1156 // CLR.L Dn ==> CLR.L An or MOVEQ #0,Dx
1158 int m_clrd(WORD inst, WORD siz)
1160 if (!CHECK_OPTS(OPT_CLR_DX))
1163 inst = (a0reg << 9) | B16(01110000, 00000000);
1171 ////////////////////////////////////////
1173 // 68020/30/40/60 instructions
1175 ////////////////////////////////////////
1180 int m_br30(WORD inst, WORD siz)
1182 if (a0exattr & DEFINED)
1184 if ((a0exattr & TDB) != cursect)
1185 return error(rel_error);
1187 uint32_t v = (uint32_t)a0exval - (sloc + 2);
1196 AddFixup(FU_LONG | FU_PCREL | FU_SEXT, sloc, a0expr);
1204 // bfchg, bfclr, bfexts, bfextu, bfffo, bfins, bfset
1205 // (68020, 68030, 68040)
1207 int m_bfop(WORD inst, WORD siz)
1209 if ((bfval1 > 31) || (bfval1 < 0))
1210 return error("bfxxx offset: immediate value must be between 0 and 31");
1212 // First instruction word - just the opcode and first EA
1213 // Note: both am1 is ORed because solely of bfins - maybe it's a good idea
1214 // to make a dedicated function for it?
1221 if (bfval2 > 31 || bfval2 < 0)
1222 return error("bfxxx width: immediate value must be between 0 and 31");
1224 // For Dw both immediate and register number are stuffed
1225 // into the same field O_o
1226 bfparam2 = (bfval2 << 0);
1230 bfparam1 = (bfval1 << 6);
1232 bfparam1 = bfval1 << 12;
1234 //D_word((inst | am0 | a0reg | am1 | a1reg));
1235 if (inst == B16(11101111, 11000000))
1237 // bfins special case
1238 D_word((inst | am1 | a1reg));
1242 D_word((inst | am0 | a0reg));
1245 ea0gen(siz); // Generate EA
1247 // Second instruction word - Dest register (if exists), Do, Offset, Dw, Width
1248 if (inst == B16(11101111, 11000000))
1250 // bfins special case
1251 inst = bfparam1 | bfparam2;
1254 inst |= a0reg << 12;
1260 inst = bfparam1 | bfparam2;
1266 inst |= a1reg << 12;
1276 // bkpt (68EC000, 68010, 68020, 68030, 68040, CPU32)
1278 int m_bkpt(WORD inst, WORD siz)
1282 if (a0exattr & DEFINED)
1285 return error(abs_error);
1288 return error(range_error);
1294 return error(undef_error);
1303 int m_callm(WORD inst, WORD siz)
1310 if (a0exattr & DEFINED)
1313 return error(abs_error);
1316 return error(range_error);
1318 inst = (uint16_t)a0exval;
1322 return error(undef_error);
1332 // cas (68020, 68030, 68040)
1334 int m_cas(WORD inst, WORD siz)
1340 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1341 return error(unsupport);
1356 return error("bad size suffix");
1361 if ((*tok < KW_D0) && (*tok > KW_D7))
1362 return error("CAS accepts only data registers");
1364 inst2 = (*tok++) & 7;
1367 return error("missing comma");
1370 if ((*tok < KW_D0) && (*tok > KW_D7))
1371 return error("CAS accepts only data registers");
1373 inst2 |= ((*tok++) & 7) << 6;
1376 return error("missing comma");
1379 if ((modes = amode(1)) < 0)
1383 return error("too many ea fields");
1386 return error("extra (unexpected) text found");
1388 // Reject invalid ea modes
1389 amsk = amsktab[am0];
1391 if ((amsk & (M_AIND | M_APOSTINC | M_APREDEC | M_ADISP | M_AINDEXED | M_ABSW | M_ABSL | M_ABASE | M_MEMPOST | M_MEMPRE)) == 0)
1392 return error("unsupported addressing mode");
1394 inst |= am0 | a0reg;
1404 // cas2 (68020, 68030, 68040)
1406 int m_cas2(WORD inst, WORD siz)
1410 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1411 return error(unsupport);
1426 return error("bad size suffix");
1431 if ((*tok < KW_D0) && (*tok > KW_D7))
1432 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1434 inst2 = (*tok++) & 7;
1437 return error("missing colon");
1440 if ((*tok < KW_D0) && (*tok > KW_D7))
1441 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1443 inst3 = (*tok++) & 7;
1446 return error("missing comma");
1449 if ((*tok < KW_D0) && (*tok > KW_D7))
1450 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1452 inst2 |= ((*tok++) & 7) << 6;
1455 return error("missing colon");
1458 if ((*tok < KW_D0) && (*tok > KW_D7))
1459 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1461 inst3 |= ((*tok++) & 7) << 6;
1464 return error("missing comma");
1468 return error("missing (");
1469 if ((*tok >= KW_D0) && (*tok <= KW_D7))
1470 inst2 |= (((*tok++) & 7) << 12) | (0 << 15);
1471 else if ((*tok >= KW_A0) && (*tok <= KW_A7))
1472 inst2 |= (((*tok++) & 7) << 12) | (1 << 15);
1474 return error("CAS accepts either data or address registers for Rn1:Rn2 pair");
1477 return error("missing (");
1480 return error("missing colon");
1484 return error("missing (");
1485 if ((*tok >= KW_D0) && (*tok <= KW_D7))
1486 inst3 |= (((*tok++) & 7) << 12) | (0 << 15);
1487 else if ((*tok >= KW_A0) && (*tok <= KW_A7))
1488 inst3 |= (((*tok++) & 7) << 12) | (1 << 15);
1490 return error("CAS accepts either data or address registers for Rn1:Rn2 pair");
1493 return error("missing (");
1496 return error("extra (unexpected) text found");
1507 // cmp2 (68020, 68030, 68040, CPU32)
1509 int m_cmp2(WORD inst, WORD siz)
1511 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1512 return error(unsupport);
1514 switch (siz & 0x000F)
1528 WORD flg = inst; // Save flag bits
1529 inst &= ~0x3F; // Clobber flag bits in instr
1531 // Install "standard" instr size bits
1537 // OR-in register number
1539 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1541 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1547 inst |= am1 | a1reg; // Get ea1 into instr
1548 D_word(inst); // Deposit instr
1550 // Generate ea0 if requested
1554 ea1gen(siz); // Generate ea1
1559 inst |= am0 | a0reg; // Get ea0 into instr
1560 D_word(inst); // Deposit instr
1561 ea0gen(siz); // Generate ea0
1563 // Generate ea1 if requested
1568 // If we're called from chk2 then bit 11 of size will be set. This is just
1569 // a dumb mechanism to pass this, required by the extension word. (You might
1570 // have noticed the siz & 15 thing above!)
1571 inst = (a1reg << 12) | (siz & (1 << 11));
1583 // chk2 (68020, 68030, 68040, CPU32)
1585 int m_chk2(WORD inst, WORD siz)
1587 return m_cmp2(inst, siz | (1 << 11));
1592 // cpbcc(68020, 68030, 68040 (FBcc), 68060 (FBcc)), pbcc (68851)
1594 int m_fpbr(WORD inst, WORD siz)
1597 if (a0exattr & DEFINED)
1599 if ((a0exattr & TDB) != cursect)
1600 return error(rel_error);
1602 uint32_t v = (uint32_t)a0exval - (sloc + 2);
1604 // Optimize branch instr. size
1607 if ((v != 0) && ((v + 0x8000) < 0x10000))
1617 if ((v + 0x8000) >= 0x10000)
1618 return error(range_error);
1626 else if (siz == SIZN)
1633 AddFixup(FU_LONG | FU_PCREL | FU_SEXT, sloc, a0expr);
1641 AddFixup(FU_WORD | FU_PCREL | FU_SEXT, sloc, a0expr);
1650 // cpbcc(68020, 68030, 68040 (FBcc), 68060 (FBcc))
1652 int m_cpbcc(WORD inst, WORD siz)
1654 if (!(activecpu & (CPU_68020 | CPU_68030)))
1655 return error(unsupport);
1657 return m_fpbr(inst, siz);
1662 // fbcc(6808X, 68040, 68060)
1664 int m_fbcc(WORD inst, WORD siz)
1667 return m_fpbr(inst, siz);
1672 // pbcc(68851 but let's assume 68020 only)
1674 int m_pbcc(WORD inst, WORD siz)
1677 return m_fpbr(inst, siz);
1682 // cpdbcc(68020, 68030)
1684 int m_cpdbr(WORD inst, WORD siz)
1689 WORD condition = inst & 0x1F; // Grab condition sneakily placed in the lower 5 bits of inst
1690 inst &= 0xFFE0; // And then mask them out - you ain't seen me, roit?
1692 inst |= (1 << 9); // Bolt on FPU id
1699 if (a1exattr & DEFINED)
1701 if ((a1exattr & TDB) != cursect)
1702 return error(rel_error);
1704 v = (uint32_t)a1exval - sloc;
1706 if (v + 0x8000 > 0x10000)
1707 return error(range_error);
1713 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
1723 // muls.l / divs.l / divu.l / mulu.l (68020+)
1725 int m_muls(WORD inst, WORD siz)
1727 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1728 return error(unsupport);
1730 WORD flg = inst; // Save flag bits
1731 inst &= ~0x33F; // Clobber flag and extension bits in instr
1733 // Install "standard" instr size bits
1739 // OR-in register number
1741 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1743 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1746 // Regarding extension word: bit 11 is signed/unsigned selector
1747 // bit 10 is 32/64 bit selector
1748 // Both of these are packed in bits 9 and 8 of the instruction
1749 // field in 68ktab. Extra compilcations arise from the fact we
1750 // have to distinguish between divu/s.l Dn,Dm (which is encoded
1751 // as divu/s.l Dn,Dm:Dm) and divu/s.l Dn,Dm:Dx - the first is
1752 // 32 bit while the second 64 bit
1757 inst |= am1 | a1reg; // Get ea1 into instr
1758 D_word(inst); // Deposit instr
1762 inst = a1reg + (a2reg << 12) + ((flg & 0x200) << 2);
1764 inst = a1reg + (a2reg << 12) + ((flg & 0x300) << 2);
1768 // Generate ea0 if requested
1772 ea1gen(siz); // Generate ea1
1779 inst |= am0 | a0reg; // Get ea0 into instr
1780 D_word(inst); // Deposit instr
1784 inst = a1reg + (a2reg << 12) + ((flg & 0x200) << 2);
1786 inst = a1reg + (a2reg << 12) + ((flg & 0x300) << 2);
1790 ea0gen(siz); // Generate ea0
1792 // Generate ea1 if requested
1802 // move16 (ax)+,(ay)+
1804 int m_move16a(WORD inst, WORD siz)
1806 if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1807 return error(unsupport);
1811 inst = (1 << 15) + (a1reg << 12);
1819 // move16 with absolute address
1821 int m_move16b(WORD inst, WORD siz)
1823 if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1824 return error(unsupport);
1830 if (am0 == APOSTINC)
1833 return error("Wasn't this suppose to call m_move16a???");
1836 // move16 (ax)+,(xxx).L
1841 else if (am0 == ABSL)
1845 // move16 (xxx).L,(ax)+
1851 // move16 (xxx).L,(ax)
1856 else if (am0 == AIND)
1858 // move16 (ax),(xxx).L
1871 // pack/unpack (68020/68030/68040)
1873 int m_pack(WORD inst, WORD siz)
1878 return error("bad size suffix");
1880 if (*tok >= KW_D0 && *tok <= KW_D7)
1882 // Dx,Dy,#<adjustment>
1883 inst |= (0 << 3); // R/M
1884 inst |= (*tok++ & 7);
1886 if (*tok != ',' && tok[2] != ',')
1887 return error("missing comma");
1889 if (tok[1] < KW_D0 && tok[1] > KW_D7)
1890 return error(syntax_error);
1892 inst |= ((tok[1] & 7)<<9);
1895 // Fall through for adjustment (common in both valid cases)
1897 else if (*tok == '-')
1899 // -(Ax),-(Ay),#<adjustment>
1900 inst |= (1 << 3); // R/M
1901 tok++; // eat the minus
1903 if ((*tok != '(') && (tok[2]!=')') && (tok[3]!=',') && (tok[4] != '-') && (tok[5] != '(') && (tok[7] != ')') && (tok[8] != ','))
1904 return error(syntax_error);
1906 if (tok[1] < KW_A0 && tok[1] > KW_A7)
1907 return error(syntax_error);
1909 if (tok[5] < KW_A0 && tok[6] > KW_A7)
1910 return error(syntax_error);
1912 inst |= ((tok[1] & 7) << 0);
1913 inst |= ((tok[6] & 7) << 9);
1916 // Fall through for adjustment (common in both valid cases)
1919 return error("invalid syntax");
1921 if ((*tok != CONST) && (*tok != SYMBOL) && (*tok != '-'))
1922 return error(syntax_error);
1924 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
1927 if ((a0exattr & DEFINED) == 0)
1928 return error(undef_error);
1930 if (a0exval + 0x8000 > 0x10000)
1934 return error(extra_stuff);
1936 D_word((a0exval & 0xFFFF));
1945 int m_rtm(WORD inst, WORD siz)
1953 else if (am0 == AREG)
1955 inst |= (1 << 3) + a0reg;
1958 return error("rtm only allows data or address registers.");
1969 int m_rtd(WORD inst, WORD siz)
1973 if (a0exattr & DEFINED)
1976 return error(abs_error);
1978 if ((a0exval + 0x8000) <= 0x7FFF)
1979 return error(range_error);
1985 return error(undef_error);
1994 int m_trapcc(WORD inst, WORD siz)
2002 else if (am0 == IMMED)
2006 if (a0exval < 0x10000)
2013 return error("Immediate value too big");
2023 return error("Invalid parameter for trapcc");
2030 // cinvl/p/a (68040/68060)
2032 int m_cinv(WORD inst, WORD siz)
2037 inst |= (0 << 6) | (a1reg);
2041 inst |= (2 << 6) | (a1reg);
2044 inst |= (1 << 6) | (a1reg);
2047 inst |= (3 << 6) | (a1reg);
2056 int m_fpusavrest(WORD inst, WORD siz)
2058 inst |= am0 | a0reg;
2067 // cpSAVE/cpRESTORE (68020, 68030)
2069 int m_cprest(WORD inst, WORD siz)
2071 if (activecpu & !(CPU_68020 | CPU_68030))
2072 return error(unsupport);
2074 return m_fpusavrest(inst, siz);
2080 // FSAVE/FRESTORE (68040, 68060)
2082 int m_frestore(WORD inst, WORD siz)
2084 if ((!(activecpu & (CPU_68040 | CPU_68060))) ||
2085 (activefpu&(FPU_68881 | FPU_68882)))
2086 return error(unsupport);
2088 return m_fpusavrest(inst, siz);
2093 // movec (68010, 68020, 68030, 68040, 68060, CPU32)
2095 int m_movec(WORD inst, WORD siz)
2099 if (am0 == DREG || am0 == AREG)
2107 inst = (0 << 15) + (a0reg << 12) + CREGlut[a1reg];
2112 inst = (1 << 15) + (a0reg << 12) + CREGlut[a1reg];
2123 inst = (0 << 15) + (a1reg << 12) + CREGlut[a0reg];
2128 inst = (1 << 15) + (a1reg << 12) + CREGlut[a0reg];
2138 // moves (68010, 68020, 68030, 68040, CPU32)
2140 int m_moves(WORD inst, WORD siz)
2142 if (activecpu & !(CPU_68020 | CPU_68030 | CPU_68040))
2143 return error(unsupport);
2147 else if (siz == SIZL)
2154 inst |= am1 | a1reg;
2156 inst = (a0reg << 12) | (1 << 11) | (0 << 15);
2159 else if (am0 == AREG)
2161 inst |= am1 | a1reg;
2163 inst = (a0reg << 12) | (1 << 11) | (1 << 15);
2170 inst |= am0 | a0reg;
2172 inst = (a1reg << 12) | (0 << 11) | (0 << 15);
2177 inst |= am0 | a0reg;
2179 inst = (a1reg << 12) | (0 << 11) | (1 << 15);
2189 // pflusha (68030, 68040)
2191 int m_pflusha(WORD inst, WORD siz)
2193 if (activecpu == CPU_68030)
2196 inst = (1 << 13) | (1 << 10) | (0 << 5) | 0;
2200 else if (activecpu == CPU_68040)
2202 inst = B16(11110101, 00011000);
2207 return error(unsupport);
2214 // pflush (68030, 68040, 68060)
2216 int m_pflush(WORD inst, WORD siz)
2218 if (activecpu == CPU_68030)
2221 // PFLUSH FC, MASK, < ea >
2229 if (*tok != CONST && *tok != SYMBOL)
2230 return error("function code should be an expression");
2232 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2235 if ((a0exattr & DEFINED) == 0)
2236 return error("function code immediate should be defined");
2239 return error("function code out of range (0-7)");
2241 fc = (uint16_t)a0exval;
2251 fc = (1 << 4) | (*tok++ & 7);
2262 return error(syntax_error);
2266 return error("comma exptected");
2269 return error("mask should be an immediate value");
2271 if (*tok != CONST && *tok != SYMBOL)
2272 return error("mask is supposed to be immediate");
2274 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2277 if ((a0exattr & DEFINED) == 0)
2278 return error("mask immediate value should be defined");
2281 return error("function code out of range (0-7)");
2283 mask = (uint16_t)a0exval << 5;
2289 inst = (1 << 13) | fc | mask | (4 << 10);
2293 else if (*tok == ',')
2295 // PFLUSH FC, MASK, < ea >
2298 if (amode(0) == ERROR)
2302 return error(extra_stuff);
2304 if (am0 == AIND || am0 == ABSW || am0 == ABSL || am0 == ADISP || am0 == ADISP || am0 == AINDEXED || am0 == ABASE || am0 == MEMPOST || am0 == MEMPRE)
2306 inst |= am0 | a0reg;
2308 inst = (1 << 13) | fc | mask | (6 << 10);
2314 return error("unsupported addressing mode");
2318 return error(syntax_error);
2322 else if (activecpu == CPU_68040 || activecpu == CPU_68060)
2326 if (*tok != '(' && tok[2] != ')')
2327 return error(syntax_error);
2329 if (tok[1] < KW_A0 && tok[1] > KW_A7)
2330 return error("expected (An)");
2332 if ((inst & 7) == 7)
2333 // With pflushn/pflush there's no easy way to distinguish between
2334 // the two in 68040 mode. Ideally the opcode bitfields would have
2335 // been hardcoded in 68ktab but there is aliasing between 68030
2336 // and 68040 opcode. So we just set the 3 lower bits to 1 in
2337 // pflushn inside 68ktab and detect it here.
2338 inst = (inst & 0xff8) | 8;
2340 inst |= (tok[1] & 7) | (5 << 8);
2343 return error(extra_stuff);
2348 return error(unsupport);
2355 // pflushan (68040, 68060)
2357 int m_pflushan(WORD inst, WORD siz)
2359 if (activecpu == CPU_68040 || activecpu == CPU_68060)
2369 int m_pflushr(WORD inst, WORD siz)
2373 WORD flg = inst; // Save flag bits
2374 inst &= ~0x3F; // Clobber flag bits in instr
2376 // Install "standard" instr size bits
2382 // OR-in register number
2384 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
2386 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
2392 inst |= am1 | a1reg; // Get ea1 into instr
2393 D_word(inst); // Deposit instr
2395 // Generate ea0 if requested
2399 ea1gen(siz); // Generate ea1
2404 inst |= am0 | a0reg; // Get ea0 into instr
2405 D_word(inst); // Deposit instr
2406 ea0gen(siz); // Generate ea0
2408 // Generate ea1 if requested
2413 D_word(B16(10100000, 00000000));
2419 // ploadr, ploadw (68030)
2421 int m_pload(WORD inst, WORD siz, WORD extension)
2423 // TODO: 68851 support is not added yet.
2424 // None of the ST series of computers had a 68020 + 68851 socket and since
2425 // this is an Atari targetted assembler...
2434 if (a0reg == KW_SFC - KW_SFC)
2436 else if (a0reg == KW_DFC - KW_SFC)
2439 return error("illegal control register specified");
2443 inst = (1 << 3) | a0reg;
2446 if ((a0exattr & DEFINED) == 0)
2447 return error("constant value must be defined");
2450 return error("constant value must be between 0 and 7");
2452 inst = (2 << 3) | (uint16_t)a0exval;
2456 inst |= extension | (1 << 13);
2465 int m_ploadr(WORD inst, WORD siz)
2467 return m_pload(inst, siz, 1 << 9);
2471 int m_ploadw(WORD inst, WORD siz)
2473 return m_pload(inst, siz, 0 << 9);
2478 // pmove (68030/68851)
2480 int m_pmove(WORD inst, WORD siz)
2484 // TODO: 68851 support is not added yet. None of the ST series of
2485 // computers had a 68020 + 68851 socket and since this is an Atari
2486 // targetted assembler.... (same for 68EC030)
2489 inst2 = inst & (1 << 8); // Copy the flush bit over to inst2 in case we're called from m_pmovefd
2490 inst &= ~(1 << 8); // And mask it out
2497 else if (am1 == CREG)
2503 return error("pmove sez: Wut?");
2505 // The instruction is a quad-word (8 byte) operation
2506 // for the CPU root pointer and the supervisor root pointer.
2507 // It is a long-word operation for the translation control register
2508 // and the transparent translation registers(TT0 and TT1).
2509 // It is a word operation for the MMU status register.
2511 if (((reg == (KW_URP - KW_SFC)) || (reg == (KW_SRP - KW_SFC)))
2512 && ((siz != SIZD) && (siz != SIZN)))
2513 return error(siz_error);
2515 if (((reg == (KW_TC - KW_SFC)) || (reg == (KW_TT0 - KW_SFC)) || (reg == (KW_TT1 - KW_SFC)))
2516 && ((siz != SIZL) && (siz != SIZN)))
2517 return error(siz_error);
2519 if ((reg == (KW_MMUSR - KW_SFC)) && ((siz != SIZW) && (siz != SIZN)))
2520 return error(siz_error);
2524 inst |= am1 | a1reg;
2527 else if (am1 == CREG)
2529 inst |= am0 | a0reg;
2533 switch (reg + KW_SFC)
2536 inst2 |= (0 << 10) + (1 << 14); break;
2538 inst2 |= (2 << 10) + (1 << 14); break;
2540 inst2 |= (3 << 10) + (1 << 14); break;
2542 inst2 |= (2 << 10) + (0 << 13); break;
2544 inst2 |= (3 << 10) + (0 << 13); break;
2547 inst2 |= (1 << 9) + (3 << 13);
2549 inst2 |= (0 << 9) + (3 << 13);
2552 return error("unsupported register");
2560 else if (am1 == CREG)
2570 int m_pmovefd(WORD inst, WORD siz)
2574 return m_pmove(inst | (1 << 8), siz);
2581 int m_ptrapcc(WORD inst, WORD siz)
2584 // We stash the 5 condition bits inside the opcode in 68ktab (bits 0-4),
2585 // so we need to extract them first and fill in the clobbered bits.
2586 WORD opcode = inst & 0x1F;
2587 inst = (inst & 0xFFE0) | (0x18);
2596 else if (siz == SIZL)
2603 else if (siz == SIZN)
2615 // ptestr, ptestw (68030, 68040)
2616 // TODO See comment on m_pmove about 68851 support
2617 // TODO quite a good chunk of the 030 code is copied from m_pload, perhaps merge these somehow?
2619 int m_ptest(WORD inst, WORD siz, WORD extension)
2623 if (activecpu != CPU_68030 && activecpu != CPU_68040)
2624 return error(unsupport);
2626 if (activecpu == CPU_68030)
2634 if (a0reg == KW_SFC - KW_SFC)
2636 else if (a0reg == KW_DFC - KW_SFC)
2639 return error("illegal control register specified");
2642 extension |= (1 << 3) | a0reg;
2645 if ((a0exattr & DEFINED) == 0)
2646 return error("constant value must be defined");
2649 return error("constant value must be between 0 and 7");
2651 extension |= (2 << 3) | (uint16_t)a0exval;
2655 // Operand 3 must be an immediate
2659 return error("ptest level must be immediate");
2661 // Let's be a bit inflexible here and demand that this
2662 // is fully defined at this stage. Otherwise we'd have
2663 // to arrange for a bitfield fixup, which would mean
2664 // polluting the bitfields and codebase with special
2665 // cases that might most likely never be used.
2666 // So if anyone gets bit by this: sorry for being a butt!
2667 if (abs_expr(&eval) != OK)
2668 return OK; // We're returning OK because error() has already been called and error count has been increased
2671 return error("ptest level must be between 0 and 7");
2673 extension |= eval << 10;
2675 // Operand 4 is optional and must be an address register
2681 if ((*tok >= KW_A0) && (*tok <= KW_A7))
2683 extension |= (1 << 8) | ((*tok++ & 7) << 4);
2687 return error("fourth parameter must be an address register");
2697 return error("Not implemented yet.");
2702 int m_ptestr(WORD inst, WORD siz)
2704 return m_ptest(inst, siz, (1 << 15) | (0 << 9));
2707 int m_ptestw(WORD inst, WORD siz)
2709 return m_ptest(inst, siz, (1 << 15) | (1 << 9));
2712 //////////////////////////////////////////////////////////////////////////////
2714 // 68020/30/40/60 instructions
2715 // Note: the map of which instructions are allowed on which CPUs came from the
2716 // 68060 manual, section D-1 (page 392 of the PDF). The current implementation
2717 // is missing checks for the EC models which have a simplified FPU.
2719 //////////////////////////////////////////////////////////////////////////////
2722 #define FPU_NOWARN 0
2727 // Generate a FPU opcode
2729 static inline int gen_fpu(WORD inst, WORD siz, WORD opmode, WORD emul)
2731 if (am0 < AM_NONE) // Check first operand for ea or fp - is this right?
2733 inst |= (1 << 9); // Bolt on FPU id
2736 //if (am0 == DREG || am0 == AREG)
2740 inst = 1 << 14; // R/M field (we have ea so have to set this to 1)
2744 case SIZB: inst |= (6 << 10); break;
2745 case SIZW: inst |= (4 << 10); break;
2746 case SIZL: inst |= (0 << 10); break;
2748 case SIZS: inst |= (1 << 10); break;
2749 case SIZD: inst |= (5 << 10); break;
2750 case SIZX: inst |= (2 << 10); break;
2755 warn("This encoding will cause an unimplemented data type exception in the MC68040 to allow emulation in software.");
2759 return error("Something bad happened, possibly, in gen_fpu.");
2763 inst |= (a1reg << 7);
2770 inst |= (1 << 9); // Bolt on FPU id
2774 inst |= (a1reg << 7);
2779 if ((emul & FPU_FPSP) && (activefpu == (FPU_68040 | FPU_68060)))
2780 warn("Instruction is emulated in 68040/060");
2787 // fabs (6888X, 68040FPSP, 68060FPSP)
2789 int m_fabs(WORD inst, WORD siz)
2792 return gen_fpu(inst, siz, B8(00011000), FPU_NOWARN);
2797 // fsabs (68040, 68060)
2799 int m_fsabs(WORD inst, WORD siz)
2802 if (activefpu == FPU_68040)
2803 return gen_fpu(inst, siz, B8(01011000), FPU_NOWARN);
2805 return error("Unsupported in current FPU");
2810 // fdabs (68040, 68060)
2812 int m_fdabs(WORD inst, WORD siz)
2814 if (activefpu == FPU_68040)
2815 return gen_fpu(inst, siz, B8(01011100), FPU_NOWARN);
2817 return error("Unsupported in current FPU");
2822 // facos (6888X, 68040FPSP, 68060FPSP)
2824 int m_facos(WORD inst, WORD siz)
2827 return gen_fpu(inst, siz, B8(00011100), FPU_FPSP);
2832 // fadd (6888X, 68040, 68060)
2834 int m_fadd(WORD inst, WORD siz)
2837 return gen_fpu(inst, siz, B8(00100010), FPU_NOWARN);
2842 // fsadd (68040, 68060)
2844 int m_fsadd(WORD inst, WORD siz)
2846 if (activefpu & (FPU_68040 | FPU_68060))
2847 return gen_fpu(inst, siz, B8(01100010), FPU_NOWARN);
2849 return error("Unsupported in current FPU");
2856 int m_fdadd(WORD inst, WORD siz)
2858 if (activefpu & (FPU_68040 | FPU_68060))
2859 return gen_fpu(inst, siz, B8(01100110), FPU_NOWARN);
2861 return error("Unsupported in current FPU");
2866 // fasin (6888X, 68040FPSP, 68060FPSP)
2868 int m_fasin(WORD inst, WORD siz)
2871 return gen_fpu(inst, siz, B8(00001100), FPU_FPSP);
2876 // fatan (6888X, 68040FPSP, 68060FPSP)
2878 int m_fatan(WORD inst, WORD siz)
2881 return gen_fpu(inst, siz, B8(00001010), FPU_FPSP);
2886 // fatanh (6888X, 68040FPSP, 68060FPSP)
2888 int m_fatanh(WORD inst, WORD siz)
2891 return gen_fpu(inst, siz, B8(00001101), FPU_FPSP);
2896 // fcmp (6888X, 68040, 68060)
2898 int m_fcmp(WORD inst, WORD siz)
2901 return gen_fpu(inst, siz, B8(00111000), FPU_FPSP);
2906 // fcos (6888X, 68040FPSP, 68060FPSP)
2908 int m_fcos(WORD inst, WORD siz)
2911 return gen_fpu(inst, siz, B8(00011101), FPU_FPSP);
2916 // fcosh (6888X, 68040FPSP, 68060FPSP)
2918 int m_fcosh(WORD inst, WORD siz)
2921 return gen_fpu(inst, siz, B8(00011001), FPU_FPSP);
2926 // fdbcc (6888X, 68040, 68060FPSP)
2928 int m_fdbcc(WORD inst, WORD siz)
2931 WORD opcode = inst & 0x3F; // Grab conditional bitfield
2941 if (a1exattr & DEFINED)
2943 if ((a1exattr & TDB) != cursect)
2944 return error(rel_error);
2946 uint32_t v = (uint32_t)a1exval - sloc;
2948 if ((v + 0x8000) > 0x10000)
2949 return error(range_error);
2955 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
2959 if (activefpu == FPU_68060)
2960 warn("Instruction is emulated in 68060");
2967 // fdiv (6888X, 68040, 68060)
2969 int m_fdiv(WORD inst, WORD siz)
2972 return gen_fpu(inst, siz, B8(00100000), FPU_NOWARN);
2977 // fsdiv (68040, 68060)
2979 int m_fsdiv(WORD inst, WORD siz)
2981 if (activefpu & (FPU_68040 | FPU_68060))
2982 return gen_fpu(inst, siz, B8(01100000), FPU_NOWARN);
2984 return error("Unsupported in current FPU");
2989 // fddiv (68040, 68060)
2991 int m_fddiv(WORD inst, WORD siz)
2993 if (activefpu & (FPU_68040 | FPU_68060))
2994 return gen_fpu(inst, siz, B8(01100100), FPU_NOWARN);
2996 return error("Unsupported in current FPU");
3001 // fetox (6888X, 68040FPSP, 68060FPSP)
3003 int m_fetox(WORD inst, WORD siz)
3006 return gen_fpu(inst, siz, B8(00010000), FPU_FPSP);
3011 // fetoxm1 (6888X, 68040FPSP, 68060FPSP)
3013 int m_fetoxm1(WORD inst, WORD siz)
3016 return gen_fpu(inst, siz, B8(00001000), FPU_FPSP);
3021 // fgetexp (6888X, 68040FPSP, 68060FPSP)
3023 int m_fgetexp(WORD inst, WORD siz)
3026 return gen_fpu(inst, siz, B8(00011110), FPU_FPSP);
3031 // fgetman (6888X, 68040FPSP, 68060FPSP)
3033 int m_fgetman(WORD inst, WORD siz)
3036 return gen_fpu(inst, siz, B8(00011111), FPU_FPSP);
3041 // fint (6888X, 68040FPSP, 68060)
3043 int m_fint(WORD inst, WORD siz)
3046 // special case - fint fpx = fint fpx,fpx
3049 if (activefpu == FPU_68040)
3050 warn("Instruction is emulated in 68040");
3052 return gen_fpu(inst, siz, B8(00000001), FPU_NOWARN);
3057 // fintrz (6888X, 68040FPSP, 68060)
3059 int m_fintrz(WORD inst, WORD siz)
3062 // special case - fintrz fpx = fintrz fpx,fpx
3065 if (activefpu == FPU_68040)
3066 warn("Instruction is emulated in 68040");
3068 return gen_fpu(inst, siz, B8(00000011), FPU_NOWARN);
3073 // flog10 (6888X, 68040FPSP, 68060FPSP)
3075 int m_flog10(WORD inst, WORD siz)
3078 return gen_fpu(inst, siz, B8(00010101), FPU_FPSP);
3083 // flog2 (6888X, 68040FPSP, 68060FPSP)
3085 int m_flog2(WORD inst, WORD siz)
3088 return gen_fpu(inst, siz, B8(00010110), FPU_FPSP);
3093 // flogn (6888X, 68040FPSP, 68060FPSP)
3095 int m_flogn(WORD inst, WORD siz)
3098 return gen_fpu(inst, siz, B8(00010100), FPU_FPSP);
3103 // flognp1 (6888X, 68040FPSP, 68060FPSP)
3105 int m_flognp1(WORD inst, WORD siz)
3108 return gen_fpu(inst, siz, B8(00000110), FPU_FPSP);
3113 // fmod (6888X, 68040FPSP, 68060FPSP)
3115 int m_fmod(WORD inst, WORD siz)
3118 return gen_fpu(inst, siz, B8(00100001), FPU_FPSP);
3123 // fmove (6888X, 68040, 68060)
3125 int m_fmove(WORD inst, WORD siz)
3130 if ((am0 == FREG) && (am1 < AM_USP))
3134 inst |= am1 | a1reg;
3143 case SIZB: inst |= (6 << 10); break;
3144 case SIZW: inst |= (4 << 10); break;
3145 case SIZL: inst |= (0 << 10); break;
3147 case SIZS: inst |= (1 << 10); break;
3148 case SIZD: inst |= (5 << 10); break;
3149 case SIZX: inst |= (2 << 10); break;
3150 case SIZP: inst |= (3 << 10);
3151 // In P size we have 2 cases: {#k} where k is immediate
3152 // and {Dn} where Dn=Data register
3157 inst |= bfval1 << 4;
3162 if (bfval1 > 63 && bfval1 < -64)
3163 return error("K-factor must be between -64 and 63");
3165 inst |= bfval1 & 127;
3170 return error("Something bad happened, possibly.");
3174 // Destination specifier
3175 inst |= (a0reg << 7);
3183 else if ((am0 < AM_USP) && (am1 == FREG))
3188 inst |= am0 | a0reg;
3197 case SIZB: inst |= (6 << 10); break;
3198 case SIZW: inst |= (4 << 10); break;
3199 case SIZL: inst |= (0 << 10); break;
3201 case SIZS: inst |= (1 << 10); break;
3202 case SIZD: inst |= (5 << 10); break;
3203 case SIZX: inst |= (2 << 10); break;
3204 case SIZP: inst |= (3 << 10); break;
3206 return error("Something bad happened, possibly.");
3210 // Destination specifier
3211 inst |= (a1reg << 7);
3219 else if ((am0 == FREG) && (am1 == FREG))
3221 // register-to-register
3222 // Essentially ea to register with R/0=0
3231 if (siz != SIZX && siz != SIZN)
3232 return error("Invalid size");
3235 inst |= (a0reg << 10);
3237 // Destination register
3238 inst |= (a1reg << 7);
3248 // fmove (6888X, 68040, 68060)
3250 int m_fmovescr(WORD inst, WORD siz)
3254 // Move Floating-Point System Control Register (FPCR)
3258 if ((am0 == FPSCR) && (am1 < AM_USP))
3260 inst |= am1 | a1reg;
3262 inst = (1 << 13) + (1 << 15);
3268 else if ((am1 == FPSCR) && (am0 < AM_USP))
3270 inst |= am0 | a0reg;
3272 inst = (0 << 13) + (1 << 15);
3279 return error("m_fmovescr says: wut?");
3283 // fsmove/fdmove (68040, 68060)
3285 int m_fsmove(WORD inst, WORD siz)
3287 if (!(activefpu & (FPU_68040 | FPU_68060)))
3288 return error("Unsupported in current FPU");
3290 return gen_fpu(inst, siz, B8(01100100), FPU_FPSP);
3294 int m_fdmove(WORD inst, WORD siz)
3296 if (!(activefpu & (FPU_68040 | FPU_68060)))
3297 return error("Unsupported in current FPU");
3299 return gen_fpu(inst, siz, B8(01100100), FPU_FPSP);
3304 // fmovecr (6888X, 68040FPSP, 68060FPSP)
3306 int m_fmovecr(WORD inst, WORD siz)
3316 if (activefpu == FPU_68040)
3317 warn("Instruction is emulated in 68040/060");
3324 // fmovem (6888X, 68040, 68060FPSP)
3326 int m_fmovem(WORD inst, WORD siz)
3333 if (siz == SIZX || siz == SIZN)
3335 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
3337 // fmovem.x <rlist>,ea
3338 if (fpu_reglist_left(®mask) < 0)
3342 return error("missing comma");
3347 inst |= am0 | a0reg;
3349 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3350 return error("invalid addressing mode");
3353 inst = (1 << 15) | (1 << 14) | (1 << 13) | (0 << 11) | regmask;
3358 else if ((*tok >= KW_D0) && (*tok <= KW_D7))
3361 datareg = (*tok++ & 7) << 10;
3364 return error("missing comma");
3369 inst |= am0 | a0reg;
3371 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3372 return error("invalid addressing mode");
3374 // Quote from the 060 manual:
3375 // "[..] when the processor attempts an FMOVEM.X instruction using a dynamic register list."
3376 if (activefpu == FPU_68060)
3377 warn("Instruction is emulated in 68060");
3380 inst = (1 << 15) | (1 << 14) | (1 << 13) | (1 << 11) | (datareg << 4);
3391 inst |= am0 | a0reg;
3394 return error("missing comma");
3396 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
3398 // fmovem.x ea,<rlist>
3399 if (fpu_reglist_right(®mask) < 0)
3403 inst = (1 << 15) | (1 << 14) | (0 << 13) | (2 << 11) | regmask;
3411 datareg = (*tok++ & 7) << 10;
3413 // Quote from the 060 manual:
3414 // "[..] when the processor attempts an FMOVEM.X instruction using a dynamic register list."
3415 if (activefpu == FPU_68060)
3416 warn("Instruction is emulated in 68060");
3419 inst = (1 << 15) | (1 << 14) | (0 << 13) | (3 << 11) | (datareg << 4);
3426 else if (siz == SIZL)
3428 if ((*tok == KW_FPCR) || (*tok == KW_FPSR) || (*tok == KW_FPIAR))
3430 // fmovem.l <rlist>,ea
3431 regmask = (1 << 15) | (1 << 13);
3432 int no_control_regs = 0;
3435 if (*tok == KW_FPCR)
3437 regmask |= (1 << 12);
3443 if (*tok == KW_FPSR)
3445 regmask |= (1 << 11);
3451 if (*tok == KW_FPIAR)
3453 regmask |= (1 << 10);
3459 if ((*tok == '/') || (*tok == '-'))
3466 return error("missing comma");
3471 // Quote from the 060 manual:
3472 // "[..] when the processor attempts to execute an FMOVEM.L instruction with
3473 // an immediate addressing mode to more than one floating - point
3474 // control register (FPCR, FPSR, FPIAR)[..]"
3475 if (activefpu == FPU_68060)
3476 if (no_control_regs > 1 && am0 == IMMED)
3477 warn("Instruction is emulated in 68060");
3479 inst |= am0 | a0reg;
3486 // fmovem.l ea,<rlist>
3490 inst |= am0 | a0reg;
3493 return error("missing comma");
3495 regmask = (1 << 15) | (0 << 13);
3498 if (*tok == KW_FPCR)
3500 regmask |= (1 << 12);
3505 if (*tok == KW_FPSR)
3507 regmask |= (1 << 11);
3512 if (*tok == KW_FPIAR)
3514 regmask |= (1 << 10);
3519 if ((*tok == '/') || (*tok == '-'))
3526 return error("extra (unexpected) text found");
3528 inst |= am0 | a0reg;
3535 return error("bad size suffix");
3542 // fmul (6888X, 68040, 68060)
3544 int m_fmul(WORD inst, WORD siz)
3547 return gen_fpu(inst, siz, B8(00100011), FPU_NOWARN);
3552 // fsmul (68040, 68060)
3554 int m_fsmul(WORD inst, WORD siz)
3556 if (activefpu & (FPU_68040 | FPU_68060))
3557 return gen_fpu(inst, siz, B8(01100011), FPU_NOWARN);
3559 return error("Unsupported in current FPU");
3566 int m_fdmul(WORD inst, WORD siz)
3568 if (activefpu & (FPU_68040 | FPU_68060))
3569 return gen_fpu(inst, siz, B8(01100111), FPU_NOWARN);
3571 return error("Unsupported in current FPU");
3576 // fneg (6888X, 68040, 68060)
3578 int m_fneg(WORD inst, WORD siz)
3585 return gen_fpu(inst, siz, B8(00011010), FPU_NOWARN);
3588 return gen_fpu(inst, siz, B8(00011010), FPU_NOWARN);
3593 // fsneg (68040, 68060)
3595 int m_fsneg(WORD inst, WORD siz)
3597 if (activefpu & (FPU_68040 | FPU_68060))
3602 return gen_fpu(inst, siz, B8(01011010), FPU_NOWARN);
3605 return gen_fpu(inst, siz, B8(01011010), FPU_NOWARN);
3608 return error("Unsupported in current FPU");
3613 // fdneg (68040, 68060)
3615 int m_fdneg(WORD inst, WORD siz)
3617 if (activefpu & (FPU_68040 | FPU_68060))
3622 return gen_fpu(inst, siz, B8(01011110), FPU_NOWARN);
3625 return gen_fpu(inst, siz, B8(01011110), FPU_NOWARN);
3628 return error("Unsupported in current FPU");
3633 // fnop (6888X, 68040, 68060)
3635 int m_fnop(WORD inst, WORD siz)
3638 return gen_fpu(inst, siz, B8(00000000), FPU_NOWARN);
3643 // frem (6888X, 68040FPSP, 68060FPSP)
3645 int m_frem(WORD inst, WORD siz)
3648 return gen_fpu(inst, siz, B8(00100101), FPU_FPSP);
3653 // fscale (6888X, 68040FPSP, 68060FPSP)
3655 int m_fscale(WORD inst, WORD siz)
3658 return gen_fpu(inst, siz, B8(00100110), FPU_FPSP);
3663 // FScc (6888X, 68040, 68060), cpScc (68851, 68030), PScc (68851)
3664 // TODO: Add check for PScc to ensure 68020+68851 active
3665 // TODO: Add check for cpScc to ensure 68020+68851, 68030
3667 int m_fscc(WORD inst, WORD siz)
3671 // We stash the 5 condition bits inside the opcode in 68ktab (bits 4-0),
3672 // so we need to extract them first and fill in the clobbered bits.
3673 WORD opcode = inst & 0x1F;
3675 inst |= am0 | a0reg;
3679 if (activefpu == FPU_68060)
3680 warn("Instruction is emulated in 68060");
3686 // fsgldiv (6888X, 68040FPSP, 68060FPSP)
3688 int m_fsgldiv(WORD inst, WORD siz)
3691 return gen_fpu(inst, siz, B8(00100100), FPU_FPSP);
3696 // fsglmul (6888X, 68040, 68060FPSP)
3698 int m_fsglmul(WORD inst, WORD siz)
3701 return gen_fpu(inst, siz, B8(00100111), FPU_FPSP);
3706 // fsin (6888X, 68040FPSP, 68060FPSP)
3708 int m_fsin(WORD inst, WORD siz)
3711 return gen_fpu(inst, siz, B8(00001110), FPU_FPSP);
3716 // fsincos (6888X, 68040FPSP, 68060FPSP)
3718 int m_fsincos(WORD inst, WORD siz)
3722 // Swap a1reg, a2reg as a2reg should be stored in the bitfield gen_fpu
3729 if (gen_fpu(inst, siz, B8(00110000), FPU_FPSP) == OK)
3740 // fsinh (6888X, 68040FPSP, 68060FPSP)
3742 int m_fsinh(WORD inst, WORD siz)
3745 return gen_fpu(inst, siz, B8(00000010), FPU_FPSP);
3750 // fsqrt (6888X, 68040, 68060)
3752 int m_fsqrt(WORD inst, WORD siz)
3755 return gen_fpu(inst, siz, B8(00000100), FPU_NOWARN);
3760 // fsfsqrt (68040, 68060)
3762 int m_fsfsqrt(WORD inst, WORD siz)
3764 if (activefpu & (FPU_68040 | FPU_68060))
3765 return gen_fpu(inst, siz, B8(01000001), FPU_NOWARN);
3767 return error("Unsupported in current FPU");
3772 // fdfsqrt (68040, 68060)
3774 int m_fdfsqrt(WORD inst, WORD siz)
3776 if (activefpu & (FPU_68040 | FPU_68060))
3777 return gen_fpu(inst, siz, B8(01000101), FPU_NOWARN);
3779 return error("Unsupported in current FPU");
3784 // fsub (6888X, 68040, 68060)
3786 int m_fsub(WORD inst, WORD siz)
3789 return gen_fpu(inst, siz, B8(00101000), FPU_NOWARN);
3794 // fsfsub (68040, 68060)
3796 int m_fsfsub(WORD inst, WORD siz)
3798 if (activefpu & (FPU_68040 | FPU_68060))
3799 return gen_fpu(inst, siz, B8(01101000), FPU_NOWARN);
3801 return error("Unsupported in current FPU");
3806 // fdfsub (68040, 68060)
3808 int m_fdsub(WORD inst, WORD siz)
3810 if (activefpu & (FPU_68040 | FPU_68060))
3811 return gen_fpu(inst, siz, B8(01101100), FPU_NOWARN);
3813 return error("Unsupported in current FPU");
3818 // ftan (6888X, 68040FPSP, 68060FPSP)
3820 int m_ftan(WORD inst, WORD siz)
3823 return gen_fpu(inst, siz, B8(00001111), FPU_FPSP);
3828 // ftanh (6888X, 68040FPSP, 68060FPSP)
3830 int m_ftanh(WORD inst, WORD siz)
3833 return gen_fpu(inst, siz, B8(00001001), FPU_FPSP);
3838 // ftentox (6888X, 68040FPSP, 68060FPSP)
3840 int m_ftentox(WORD inst, WORD siz)
3843 return gen_fpu(inst, siz, B8(00010010), FPU_FPSP);
3848 // FTRAPcc (6888X, 68040, 68060FPSP)
3850 int m_ftrapcc(WORD inst, WORD siz)
3854 // We stash the 5 condition bits inside the opcode in 68ktab (bits 3-7),
3855 // so we need to extract them first and fill in the clobbered bits.
3856 WORD opcode = (inst >> 3) & 0x1F;
3857 inst = (inst & 0xFF07) | (0xF << 3);
3866 else if (siz == SIZL)
3873 else if (siz == SIZN)
3881 if (activefpu == FPU_68060)
3882 warn("Instruction is emulated in 68060");
3889 // ftst (6888X, 68040, 68060)
3891 int m_ftst(WORD inst, WORD siz)
3894 return gen_fpu(inst, siz, B8(00111010), FPU_NOWARN);
3899 // ftwotox (6888X, 68040FPSP, 68060FPSP)
3901 int m_ftwotox(WORD inst, WORD siz)
3904 return gen_fpu(inst, siz, B8(00010001), FPU_FPSP);
3908 /////////////////////////////////
3910 // 68060 specific instructions //
3912 /////////////////////////////////
3918 int m_lpstop(WORD inst, WORD siz)
3921 D_word(B16(00000001, 11000000));
3923 if (a0exattr & DEFINED)
3929 AddFixup(FU_WORD, sloc, a0expr);
3940 int m_plpa(WORD inst, WORD siz)
3943 inst |= a0reg; // Install register