2 // RMAC - Renamed Macro Assembler for all Atari computers
3 // MACH.C - Code Generation
4 // Copyright (C) 199x Landon Dyer, 2011-2021 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 = 0b0101000001001000 | (((uint16_t)a0exval & 7) << 9) | (a0reg);
359 warn("o4: 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(0b0101000000000000, siz);
474 warn("o8: 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(0b0100000111011000, SIZW);
498 optim_flags[OPT_LEA_ADDQ] = temp_flag; // Restore switch state
500 warn("o9: adda.w/l #x,Ay converted to lea x(Dy),Ay");
506 inst |= am0 | a0reg | lwsiz_8[siz] | reg_9[a1reg];
508 ea0gen(siz); // Generate EA
515 // If bit 0 of `inst' is 1, install size bits in bits 6..7 of instr.
516 // If bit 1 of `inst' is 1, install a1reg in bits 9..11 of instr.
518 int m_reg(WORD inst, WORD siz)
525 // Install other register (9..11)
526 inst |= reg_9[a1reg];
528 inst &= ~7; // Clear off crufty bits
529 inst |= a0reg; // Install first register
539 int m_imm(WORD inst, WORD siz)
551 int m_imm8(WORD inst, WORD siz)
564 int m_shr(WORD inst, WORD siz)
566 inst |= reg_9[a0reg] | a1reg | siz_6[siz];
576 int m_shi(WORD inst, WORD siz)
578 inst |= a1reg | siz_6[siz];
580 if (a0exattr & DEFINED)
583 return error(range_error);
585 inst |= (a0exval & 7) << 9;
590 AddFixup(FU_QUICK, sloc, a0expr);
599 // {bset, btst, bchg, bclr} -- #immed,ea -- Dn,ea
601 int m_bitop(WORD inst, WORD siz)
603 // Enforce instruction sizes
605 { // X,Dn must be .n or .l
606 if (siz & (SIZB | SIZW))
607 return error(siz_error);
609 else if (siz & (SIZW | SIZL)) // X,ea must be .n or .b
610 return error(siz_error);
612 // Construct instr and EAs
618 ea0gen(SIZB); // Immediate bit number
622 inst |= reg_9[a0reg];
633 int m_dbra(WORD inst, WORD siz)
639 if (a1exattr & DEFINED)
641 if ((a1exattr & TDB) != cursect)
642 return error(rel_error);
644 uint32_t v = (uint32_t)a1exval - sloc;
646 if (v + 0x8000 > 0x10000)
647 return error(range_error);
653 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
664 int m_exg(WORD inst, WORD siz)
670 if (am0 == DREG && am1 == DREG)
672 else if (am0 == AREG && am1 == AREG)
678 m = a1reg; // Get AREG into a1reg
686 inst |= m | reg_9[a0reg] | a1reg;
696 int m_link(WORD inst, WORD siz)
700 // Is this an error condition???
705 inst &= ~((3 << 9) | (1 << 6) | (1 << 4));
717 WORD extra_addressing[16]=
719 0x30, // 0100 (bd,An,Xn)
720 0x30, // 0101 ([bd,An],Xn,od)
721 0x30, // 0102 ([bc,An,Xn],od)
722 0x30, // 0103 (bd,PC,Xn)
723 0x30, // 0104 ([bd,PC],Xn,od)
724 0x30, // 0105 ([bc,PC,Xn],od)
739 // Handle MOVE <C_ALL> <C_ALTDATA>
740 // MOVE <C_ALL> <M_AREG>
742 // Optimize MOVE.L #<smalldata>,D0 to a MOVEQ
744 int m_move(WORD inst, WORD size)
746 // Cast the passed in value to an int
749 // Try to optimize to MOVEQ
750 // N.B.: We can get away with casting the uint64_t to a 32-bit value
751 // because it checks for a SIZL (i.e., a 32-bit value).
752 if (CHECK_OPTS(OPT_MOVEL_MOVEQ)
753 && (siz == SIZL) && (am0 == IMMED) && (am1 == DREG)
754 && ((a0exattr & (TDB | DEFINED)) == DEFINED)
755 && ((uint32_t)a0exval + 0x80 < 0x100))
757 m_moveq((WORD)0x7000, (WORD)0);
760 warn("o1: move.l #size,dx converted to moveq");
764 if ((am0 < ABASE) && (am1 < ABASE)) // 68000 modes
766 inst |= siz_12[siz] | am_6[am1] | reg_9[a1reg] | am0 | a0reg;
774 ea1gen((WORD)siz | 0x8000); // Tell ea1gen we're move ea,ea
778 inst |= siz_12[siz] | reg_9[a1reg] | extra_addressing[am0 - ABASE];
795 // Handle MOVE <C_ALL030> <C_ALTDATA>
796 // MOVE <C_ALL030> <M_AREG>
798 int m_move30(WORD inst, WORD size)
803 inst |= siz_12[siz] | reg_9[a1reg & 7] | a0reg | extra_addressing[am0 - ABASE];
805 inst |= siz_12[siz] | reg_9[a1reg & 7] | a0reg | extra_addressing[am1 - ABASE] << 3;
820 // move USP,An -- move An,USP
822 int m_usp(WORD inst, WORD siz)
827 inst |= a1reg; // USP, An
829 inst |= a0reg; // An, USP
840 int m_moveq(WORD inst, WORD siz)
844 // Arrange for future fixup
845 if (!(a0exattr & DEFINED))
847 AddFixup(FU_BYTE | FU_SEXT, sloc + 1, a0expr);
850 else if ((uint32_t)a0exval + 0x100 >= 0x200)
851 return error(range_error);
853 inst |= reg_9[a1reg] | (a0exval & 0xFF);
861 // movep Dn, disp(An) -- movep disp(An), Dn
863 int m_movep(WORD inst, WORD siz)
865 // Tell ea0gen to lay off the 0(a0) optimisations on this one
873 inst |= reg_9[a0reg] | a1reg;
883 inst |= reg_9[a1reg] | a0reg;
900 int m_br(WORD inst, WORD siz)
902 if (a0exattr & DEFINED)
904 if ((a0exattr & TDB) != cursect)
906 //printf("m_br(): a0exattr = %X, cursect = %X, a0exval = %X, sloc = %X\n", a0exattr, cursect, a0exval, sloc);
907 return error(rel_error);
910 uint32_t v = (uint32_t)a0exval - (sloc + 2);
912 // Optimize branch instr. size
915 if (CHECK_OPTS(OPT_BSR_BCC_S) && (v != 0) && ((v + 0x80) < 0x100))
922 warn("o2: Bcc.w/BSR.w converted to .s");
929 if ((v + 0x8000) > 0x10000)
930 return error(range_error);
938 if (siz == SIZB || siz == SIZS)
940 if ((v + 0x80) >= 0x100)
941 return error(range_error);
948 if ((v + 0x8000) >= 0x10000)
949 return error(range_error);
957 else if (siz == SIZN)
960 if (siz == SIZB || siz == SIZS)
963 AddFixup(FU_BBRA | FU_PCREL | FU_SEXT, sloc, a0expr);
964 // So here we have a small issue: this bra.s could be zero offset, but
965 // we can never know. Because unless we know beforehand that the
966 // offset will be zero (i.e. "bra.s +0"), it's going to be a label
967 // below this instruction! We do have an optimisation flag that can
968 // check against this during fixups, but we cannot rely on the state
969 // of the flag after all the file(s) have been processed because its
970 // state might have changed multiple times during file parsing. (Yes,
971 // there's a very low chance that this will ever happen but it's not
972 // zero!). So, we can use the byte that is going to be filled during
973 // fixups to store the state of the optimisation flag and read it
974 // during that stage so each bra.s will have its state stored neatly.
975 // Sleazy? Eh, who cares, like this will ever happen ;)
976 // One final note: we'd better be damn sure that the flag's value is
977 // less than 256 or magical stuff will happen!
978 D_word(inst | optim_flags[OPT_NULL_BRA]);
985 AddFixup(FU_WORD | FU_PCREL | FU_LBRA | FU_ISBRA, sloc, a0expr);
996 int m_addq(WORD inst, WORD siz)
998 inst |= siz_6[siz] | am1 | a1reg;
1000 if (a0exattr & DEFINED)
1002 if ((a0exval > 8) || (a0exval == 0)) // Range in 1..8
1003 return error(range_error);
1005 inst |= (a0exval & 7) << 9;
1010 AddFixup(FU_QUICK, sloc, a0expr);
1023 int m_trap(WORD inst, WORD siz)
1027 if (a0exattr & DEFINED)
1030 return error(abs_error);
1033 return error(range_error);
1039 return error(undef_error);
1046 // movem <rlist>,ea -- movem ea,<rlist>
1048 int m_movem(WORD inst, WORD siz)
1056 return error("bad size suffix");
1063 // Handle #<expr>, ea
1066 if (abs_expr(&eval) != OK)
1069 if (eval >= 0x10000L)
1070 return error(range_error);
1076 if ((*tok >= REG68_D0) && (*tok <= REG68_A7))
1079 if (reglist(&rmask) < 0)
1084 return error("missing comma");
1089 inst |= am0 | a0reg;
1091 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
1092 return error("invalid addressing mode");
1094 // If APREDEC, reverse register mask
1100 for(i=0x8000; i; i>>=1, w>>=1)
1101 rmask = (WORD)((rmask << 1) | (w & 1));
1110 inst |= 0x0400 | am0 | a0reg;
1113 return error("missing comma");
1116 return error("missing register list");
1123 if (abs_expr(&eval) != OK)
1126 if (eval >= 0x10000)
1127 return error(range_error);
1131 else if (reglist(&rmask) < 0)
1134 if (!(amsktab[am0] & (C_CTRL | M_APOSTINC)))
1135 return error("invalid addressing mode");
1147 // CLR.x An ==> SUBA.x An,An
1149 int m_clra(WORD inst, WORD siz)
1151 inst |= a0reg | reg_9[a0reg] | lwsiz_8[siz];
1159 // CLR.L Dn ==> CLR.L An or MOVEQ #0,Dx
1161 int m_clrd(WORD inst, WORD siz)
1163 if (!CHECK_OPTS(OPT_CLR_DX))
1167 inst = (a0reg << 9) | 0b0111000000000000;
1168 if (optim_warn_flag)
1169 warn("o7: clr.l Dx converted to moveq #0,Dx");
1178 ////////////////////////////////////////
1180 // 68020/30/40/60 instructions
1182 ////////////////////////////////////////
1187 int m_br30(WORD inst, WORD siz)
1189 if (a0exattr & DEFINED)
1191 if ((a0exattr & TDB) != cursect)
1192 return error(rel_error);
1194 uint32_t v = (uint32_t)a0exval - (sloc + 2);
1203 AddFixup(FU_LONG | FU_PCREL | FU_SEXT, sloc, a0expr);
1211 // bfchg, bfclr, bfexts, bfextu, bfffo, bfins, bfset
1212 // (68020, 68030, 68040)
1214 int m_bfop(WORD inst, WORD siz)
1216 if ((bfval1 > 31) || (bfval1 < 0))
1217 return error("bfxxx offset: immediate value must be between 0 and 31");
1219 // First instruction word - just the opcode and first EA
1220 // Note: both am1 is ORed because solely of bfins - maybe it's a good idea
1221 // to make a dedicated function for it?
1228 if (bfval2 > 31 || bfval2 < 0)
1229 return error("bfxxx width: immediate value must be between 0 and 31");
1231 // For Dw both immediate and register number are stuffed
1232 // into the same field O_o
1233 bfparam2 = (bfval2 << 0);
1237 bfparam1 = (bfval1 << 6);
1239 bfparam1 = bfval1 << 12;
1241 //D_word((inst | am0 | a0reg | am1 | a1reg));
1242 if (inst == 0b1110111111000000)
1244 // bfins special case
1245 D_word((inst | am1 | a1reg));
1249 D_word((inst | am0 | a0reg));
1252 ea0gen(siz); // Generate EA
1254 // Second instruction word - Dest register (if exists), Do, Offset, Dw, Width
1255 if (inst == 0b1110111111000000)
1257 // bfins special case
1258 inst = bfparam1 | bfparam2;
1261 inst |= a0reg << 12;
1267 inst = bfparam1 | bfparam2;
1273 inst |= a1reg << 12;
1283 // bkpt (68EC000, 68010, 68020, 68030, 68040, CPU32)
1285 int m_bkpt(WORD inst, WORD siz)
1289 if (a0exattr & DEFINED)
1292 return error(abs_error);
1295 return error(range_error);
1301 return error(undef_error);
1310 int m_callm(WORD inst, WORD siz)
1317 if (a0exattr & DEFINED)
1320 return error(abs_error);
1323 return error(range_error);
1325 inst = (uint16_t)a0exval;
1329 return error(undef_error);
1339 // cas (68020, 68030, 68040)
1341 int m_cas(WORD inst, WORD siz)
1347 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1348 return error(unsupport);
1363 return error("bad size suffix");
1368 if ((*tok < REG68_D0) && (*tok > REG68_D7))
1369 return error("CAS accepts only data registers");
1371 inst2 = (*tok++) & 7;
1374 return error("missing comma");
1377 if ((*tok < REG68_D0) && (*tok > REG68_D7))
1378 return error("CAS accepts only data registers");
1380 inst2 |= ((*tok++) & 7) << 6;
1383 return error("missing comma");
1386 if ((modes = amode(1)) < 0)
1390 return error("too many ea fields");
1393 return error("extra (unexpected) text found");
1395 // Reject invalid ea modes
1396 amsk = amsktab[am0];
1398 if ((amsk & (M_AIND | M_APOSTINC | M_APREDEC | M_ADISP | M_AINDEXED | M_ABSW | M_ABSL | M_ABASE | M_MEMPOST | M_MEMPRE)) == 0)
1399 return error("unsupported addressing mode");
1401 inst |= am0 | a0reg;
1411 // cas2 (68020, 68030, 68040)
1413 int m_cas2(WORD inst, WORD siz)
1417 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1418 return error(unsupport);
1433 return error("bad size suffix");
1438 if ((*tok < REG68_D0) && (*tok > REG68_D7))
1439 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1441 inst2 = (*tok++) & 7;
1444 return error("missing colon");
1447 if ((*tok < REG68_D0) && (*tok > REG68_D7))
1448 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1450 inst3 = (*tok++) & 7;
1453 return error("missing comma");
1456 if ((*tok < REG68_D0) && (*tok > REG68_D7))
1457 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1459 inst2 |= ((*tok++) & 7) << 6;
1462 return error("missing colon");
1465 if ((*tok < REG68_D0) && (*tok > REG68_D7))
1466 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1468 inst3 |= ((*tok++) & 7) << 6;
1471 return error("missing comma");
1475 return error("missing (");
1476 if ((*tok >= REG68_D0) && (*tok <= REG68_D7))
1477 inst2 |= (((*tok++) & 7) << 12) | (0 << 15);
1478 else if ((*tok >= REG68_A0) && (*tok <= REG68_A7))
1479 inst2 |= (((*tok++) & 7) << 12) | (1 << 15);
1481 return error("CAS accepts either data or address registers for Rn1:Rn2 pair");
1484 return error("missing (");
1487 return error("missing colon");
1491 return error("missing (");
1492 if ((*tok >= REG68_D0) && (*tok <= REG68_D7))
1493 inst3 |= (((*tok++) & 7) << 12) | (0 << 15);
1494 else if ((*tok >= REG68_A0) && (*tok <= REG68_A7))
1495 inst3 |= (((*tok++) & 7) << 12) | (1 << 15);
1497 return error("CAS accepts either data or address registers for Rn1:Rn2 pair");
1500 return error("missing (");
1503 return error("extra (unexpected) text found");
1514 // cmp2 (68020, 68030, 68040, CPU32)
1516 int m_cmp2(WORD inst, WORD siz)
1518 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1519 return error(unsupport);
1521 switch (siz & 0x000F)
1535 WORD flg = inst; // Save flag bits
1536 inst &= ~0x3F; // Clobber flag bits in instr
1538 // Install "standard" instr size bits
1544 // OR-in register number
1546 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1548 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1554 inst |= am1 | a1reg; // Get ea1 into instr
1555 D_word(inst); // Deposit instr
1557 // Generate ea0 if requested
1561 ea1gen(siz); // Generate ea1
1566 inst |= am0 | a0reg; // Get ea0 into instr
1567 D_word(inst); // Deposit instr
1568 ea0gen(siz); // Generate ea0
1570 // Generate ea1 if requested
1575 // If we're called from chk2 then bit 11 of size will be set. This is just
1576 // a dumb mechanism to pass this, required by the extension word. (You might
1577 // have noticed the siz & 15 thing above!)
1578 inst = (a1reg << 12) | (siz & (1 << 11));
1590 // chk2 (68020, 68030, 68040, CPU32)
1592 int m_chk2(WORD inst, WORD siz)
1594 return m_cmp2(inst, siz | (1 << 11));
1599 // cpbcc(68020, 68030, 68040 (FBcc), 68060 (FBcc)), pbcc (68851)
1601 int m_fpbr(WORD inst, WORD siz)
1604 if (a0exattr & DEFINED)
1606 if ((a0exattr & TDB) != cursect)
1607 return error(rel_error);
1609 uint32_t v = (uint32_t)a0exval - (sloc + 2);
1611 // Optimize branch instr. size
1614 if ((v != 0) && ((v + 0x8000) < 0x10000))
1624 if ((v + 0x8000) >= 0x10000)
1625 return error(range_error);
1633 else if (siz == SIZN)
1640 AddFixup(FU_LONG | FU_PCREL | FU_SEXT, sloc, a0expr);
1648 AddFixup(FU_WORD | FU_PCREL | FU_SEXT, sloc, a0expr);
1657 // cpbcc(68020, 68030, 68040 (FBcc), 68060 (FBcc))
1659 int m_cpbcc(WORD inst, WORD siz)
1661 if (!(activecpu & (CPU_68020 | CPU_68030)))
1662 return error(unsupport);
1664 return m_fpbr(inst, siz);
1669 // fbcc(6808X, 68040, 68060)
1671 int m_fbcc(WORD inst, WORD siz)
1674 return m_fpbr(inst, siz);
1679 // pbcc(68851 but let's assume 68020 only)
1681 int m_pbcc(WORD inst, WORD siz)
1684 return m_fpbr(inst, siz);
1689 // cpdbcc(68020, 68030)
1691 int m_cpdbr(WORD inst, WORD siz)
1696 WORD condition = inst & 0x1F; // Grab condition sneakily placed in the lower 5 bits of inst
1697 inst &= 0xFFE0; // And then mask them out - you ain't seen me, roit?
1699 inst |= (1 << 9); // Bolt on FPU id
1706 if (a1exattr & DEFINED)
1708 if ((a1exattr & TDB) != cursect)
1709 return error(rel_error);
1711 v = (uint32_t)a1exval - sloc;
1713 if (v + 0x8000 > 0x10000)
1714 return error(range_error);
1720 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
1730 // muls.l / divs.l / divu.l / mulu.l (68020+)
1732 int m_muls(WORD inst, WORD siz)
1734 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1735 return error(unsupport);
1737 WORD flg = inst; // Save flag bits
1738 inst &= ~0x33F; // Clobber flag and extension bits in instr
1740 // Install "standard" instr size bits
1746 // OR-in register number
1748 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1750 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1753 // Regarding extension word: bit 11 is signed/unsigned selector
1754 // bit 10 is 32/64 bit selector
1755 // Both of these are packed in bits 9 and 8 of the instruction
1756 // field in 68ktab. Extra compilcations arise from the fact we
1757 // have to distinguish between divu/s.l Dn,Dm (which is encoded
1758 // as divu/s.l Dn,Dm:Dm) and divu/s.l Dn,Dm:Dx - the first is
1759 // 32 bit while the second 64 bit
1764 inst |= am1 | a1reg; // Get ea1 into instr
1765 D_word(inst); // Deposit instr
1769 inst = a1reg + (a2reg << 12) + ((flg & 0x200) << 2);
1771 inst = a1reg + (a2reg << 12) + ((flg & 0x300) << 2);
1775 // Generate ea0 if requested
1779 ea1gen(siz); // Generate ea1
1786 inst |= am0 | a0reg; // Get ea0 into instr
1787 D_word(inst); // Deposit instr
1791 inst = a1reg + (a2reg << 12) + ((flg & 0x200) << 2);
1793 inst = a1reg + (a2reg << 12) + ((flg & 0x300) << 2);
1797 ea0gen(siz); // Generate ea0
1799 // Generate ea1 if requested
1809 // move16 (ax)+,(ay)+
1811 int m_move16a(WORD inst, WORD siz)
1813 if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1814 return error(unsupport);
1818 inst = (1 << 15) + (a1reg << 12);
1826 // move16 with absolute address
1828 int m_move16b(WORD inst, WORD siz)
1830 if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1831 return error(unsupport);
1837 if (am0 == APOSTINC)
1840 return error("Wasn't this suppose to call m_move16a???");
1843 // move16 (ax)+,(xxx).L
1848 else if (am0 == ABSL)
1852 // move16 (xxx).L,(ax)+
1858 // move16 (xxx).L,(ax)
1863 else if (am0 == AIND)
1865 // move16 (ax),(xxx).L
1878 // pack/unpack (68020/68030/68040)
1880 int m_pack(WORD inst, WORD siz)
1885 return error("bad size suffix");
1887 if (*tok >= REG68_D0 && *tok <= REG68_D7)
1889 // Dx,Dy,#<adjustment>
1890 inst |= (0 << 3); // R/M
1891 inst |= (*tok++ & 7);
1893 if (*tok != ',' && tok[2] != ',')
1894 return error("missing comma");
1896 if (tok[1] < REG68_D0 && tok[1] > REG68_D7)
1897 return error(syntax_error);
1899 inst |= ((tok[1] & 7)<<9);
1902 // Fall through for adjustment (common in both valid cases)
1904 else if (*tok == '-')
1906 // -(Ax),-(Ay),#<adjustment>
1907 inst |= (1 << 3); // R/M
1908 tok++; // eat the minus
1910 if ((*tok != '(') && (tok[2]!=')') && (tok[3]!=',') && (tok[4] != '-') && (tok[5] != '(') && (tok[7] != ')') && (tok[8] != ','))
1911 return error(syntax_error);
1913 if (tok[1] < REG68_A0 && tok[1] > REG68_A7)
1914 return error(syntax_error);
1916 if (tok[5] < REG68_A0 && tok[6] > REG68_A7)
1917 return error(syntax_error);
1919 inst |= ((tok[1] & 7) << 0);
1920 inst |= ((tok[6] & 7) << 9);
1923 // Fall through for adjustment (common in both valid cases)
1926 return error("invalid syntax");
1928 if ((*tok != CONST) && (*tok != SYMBOL) && (*tok != '-'))
1929 return error(syntax_error);
1931 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
1934 if ((a0exattr & DEFINED) == 0)
1935 return error(undef_error);
1937 if (a0exval + 0x8000 > 0x10000)
1941 return error(extra_stuff);
1943 D_word((a0exval & 0xFFFF));
1952 int m_rtm(WORD inst, WORD siz)
1960 else if (am0 == AREG)
1962 inst |= (1 << 3) + a0reg;
1965 return error("rtm only allows data or address registers.");
1976 int m_rtd(WORD inst, WORD siz)
1980 if (a0exattr & DEFINED)
1983 return error(abs_error);
1985 if ((a0exval + 0x8000) <= 0x7FFF)
1986 return error(range_error);
1992 return error(undef_error);
2001 int m_trapcc(WORD inst, WORD siz)
2009 else if (am0 == IMMED)
2013 if (a0exval < 0x10000)
2020 return error("Immediate value too big");
2030 return error("Invalid parameter for trapcc");
2037 // cinvl/p/a (68040/68060)
2039 int m_cinv(WORD inst, WORD siz)
2044 inst |= (0 << 6) | (a1reg);
2047 case 0: // REG68_IC40
2048 inst |= (2 << 6) | (a1reg);
2050 case 1: // REG68_DC40
2051 inst |= (1 << 6) | (a1reg);
2053 case 2: // REG68_BC40
2054 inst |= (3 << 6) | (a1reg);
2063 int m_fpusavrest(WORD inst, WORD siz)
2065 inst |= am0 | a0reg;
2074 // cpSAVE/cpRESTORE (68020, 68030)
2076 int m_cprest(WORD inst, WORD siz)
2078 if (activecpu & !(CPU_68020 | CPU_68030))
2079 return error(unsupport);
2081 return m_fpusavrest(inst, siz);
2087 // FSAVE/FRESTORE (68040, 68060)
2089 int m_frestore(WORD inst, WORD siz)
2091 if ((!(activecpu & (CPU_68040 | CPU_68060))) ||
2092 (activefpu&(FPU_68881 | FPU_68882)))
2093 return error(unsupport);
2095 return m_fpusavrest(inst, siz);
2100 // movec (68010, 68020, 68030, 68040, 68060, CPU32)
2102 int m_movec(WORD inst, WORD siz)
2106 if (am0 == DREG || am0 == AREG)
2114 inst = (0 << 15) + (a0reg << 12) + CREGlut[a1reg];
2119 inst = (1 << 15) + (a0reg << 12) + CREGlut[a1reg];
2130 inst = (0 << 15) + (a1reg << 12) + CREGlut[a0reg];
2135 inst = (1 << 15) + (a1reg << 12) + CREGlut[a0reg];
2145 // moves (68010, 68020, 68030, 68040, CPU32)
2147 int m_moves(WORD inst, WORD siz)
2149 if (activecpu & !(CPU_68020 | CPU_68030 | CPU_68040))
2150 return error(unsupport);
2154 else if (siz == SIZL)
2161 inst |= am1 | a1reg;
2163 inst = (a0reg << 12) | (1 << 11) | (0 << 15);
2166 else if (am0 == AREG)
2168 inst |= am1 | a1reg;
2170 inst = (a0reg << 12) | (1 << 11) | (1 << 15);
2177 inst |= am0 | a0reg;
2179 inst = (a1reg << 12) | (0 << 11) | (0 << 15);
2184 inst |= am0 | a0reg;
2186 inst = (a1reg << 12) | (0 << 11) | (1 << 15);
2196 // pflusha (68030, 68040)
2198 int m_pflusha(WORD inst, WORD siz)
2200 if (activecpu == CPU_68030)
2203 inst = (1 << 13) | (1 << 10) | (0 << 5) | 0;
2207 else if (activecpu == CPU_68040)
2209 inst = 0b1111010100011000;
2214 return error(unsupport);
2221 // pflush (68030, 68040, 68060)
2223 int m_pflush(WORD inst, WORD siz)
2225 if (activecpu == CPU_68030)
2228 // PFLUSH FC, MASK, < ea >
2236 if (*tok != CONST && *tok != SYMBOL)
2237 return error("function code should be an expression");
2239 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2242 if ((a0exattr & DEFINED) == 0)
2243 return error("function code immediate should be defined");
2246 return error("function code out of range (0-7)");
2248 fc = (uint16_t)a0exval;
2258 fc = (1 << 4) | (*tok++ & 7);
2269 return error(syntax_error);
2273 return error("comma exptected");
2276 return error("mask should be an immediate value");
2278 if (*tok != CONST && *tok != SYMBOL)
2279 return error("mask is supposed to be immediate");
2281 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2284 if ((a0exattr & DEFINED) == 0)
2285 return error("mask immediate value should be defined");
2288 return error("function code out of range (0-7)");
2290 mask = (uint16_t)a0exval << 5;
2296 inst = (1 << 13) | fc | mask | (4 << 10);
2300 else if (*tok == ',')
2302 // PFLUSH FC, MASK, < ea >
2305 if (amode(0) == ERROR)
2309 return error(extra_stuff);
2311 if (am0 == AIND || am0 == ABSW || am0 == ABSL || am0 == ADISP || am0 == ADISP || am0 == AINDEXED || am0 == ABASE || am0 == MEMPOST || am0 == MEMPRE)
2313 inst |= am0 | a0reg;
2315 inst = (1 << 13) | fc | mask | (6 << 10);
2321 return error("unsupported addressing mode");
2325 return error(syntax_error);
2329 else if (activecpu == CPU_68040 || activecpu == CPU_68060)
2333 if (*tok != '(' && tok[2] != ')')
2334 return error(syntax_error);
2336 if (tok[1] < REG68_A0 && tok[1] > REG68_A7)
2337 return error("expected (An)");
2339 if ((inst & 7) == 7)
2340 // With pflushn/pflush there's no easy way to distinguish between
2341 // the two in 68040 mode. Ideally the opcode bitfields would have
2342 // been hardcoded in 68ktab but there is aliasing between 68030
2343 // and 68040 opcode. So we just set the 3 lower bits to 1 in
2344 // pflushn inside 68ktab and detect it here.
2345 inst = (inst & 0xff8) | 8;
2347 inst |= (tok[1] & 7) | (5 << 8);
2350 return error(extra_stuff);
2355 return error(unsupport);
2362 // pflushan (68040, 68060)
2364 int m_pflushan(WORD inst, WORD siz)
2366 if (activecpu == CPU_68040 || activecpu == CPU_68060)
2376 int m_pflushr(WORD inst, WORD siz)
2380 WORD flg = inst; // Save flag bits
2381 inst &= ~0x3F; // Clobber flag bits in instr
2383 // Install "standard" instr size bits
2389 // OR-in register number
2391 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
2393 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
2399 inst |= am1 | a1reg; // Get ea1 into instr
2400 D_word(inst); // Deposit instr
2402 // Generate ea0 if requested
2406 ea1gen(siz); // Generate ea1
2411 inst |= am0 | a0reg; // Get ea0 into instr
2412 D_word(inst); // Deposit instr
2413 ea0gen(siz); // Generate ea0
2415 // Generate ea1 if requested
2420 D_word(0b1010000000000000);
2426 // ploadr, ploadw (68030)
2428 int m_pload(WORD inst, WORD siz, WORD extension)
2430 // TODO: 68851 support is not added yet.
2431 // None of the ST series of computers had a 68020 + 68851 socket and since
2432 // this is an Atari targetted assembler...
2441 if (a0reg == REG68_SFC - REG68_SFC)
2443 else if (a0reg == REG68_DFC - REG68_SFC)
2446 return error("illegal control register specified");
2449 inst = (1 << 3) | a0reg;
2452 if ((a0exattr & DEFINED) == 0)
2453 return error("constant value must be defined");
2456 return error("constant value must be between 0 and 7");
2458 inst = (2 << 3) | (uint16_t)a0exval;
2462 inst |= extension | (1 << 13);
2471 int m_ploadr(WORD inst, WORD siz)
2473 return m_pload(inst, siz, 1 << 9);
2477 int m_ploadw(WORD inst, WORD siz)
2479 return m_pload(inst, siz, 0 << 9);
2484 // pmove (68030/68851)
2486 int m_pmove(WORD inst, WORD siz)
2490 // TODO: 68851 support is not added yet. None of the ST series of
2491 // computers had a 68020 + 68851 socket and since this is an Atari
2492 // targetted assembler.... (same for 68EC030)
2495 inst2 = inst & (1 << 8); // Copy the flush bit over to inst2 in case we're called from m_pmovefd
2496 inst &= ~(1 << 8); // And mask it out
2503 else if (am1 == CREG)
2509 return error("pmove sez: Wut?");
2511 // The instruction is a quad-word (8 byte) operation
2512 // for the CPU root pointer and the supervisor root pointer.
2513 // It is a long-word operation for the translation control register
2514 // and the transparent translation registers(TT0 and TT1).
2515 // It is a word operation for the MMU status register.
2517 if (((reg == (REG68_URP - REG68_SFC)) || (reg == (REG68_SRP - REG68_SFC)))
2518 && ((siz != SIZD) && (siz != SIZN)))
2519 return error(siz_error);
2521 if (((reg == (REG68_TC - REG68_SFC)) || (reg == (REG68_TT0 - REG68_SFC)) || (reg == (REG68_TT1 - REG68_SFC)))
2522 && ((siz != SIZL) && (siz != SIZN)))
2523 return error(siz_error);
2525 if ((reg == (REG68_MMUSR - REG68_SFC)) && ((siz != SIZW) && (siz != SIZN)))
2526 return error(siz_error);
2530 inst |= am1 | a1reg;
2533 else if (am1 == CREG)
2535 inst |= am0 | a0reg;
2539 switch (reg + REG68_SFC)
2542 inst2 |= (0 << 10) + (1 << 14); break;
2544 inst2 |= (2 << 10) + (1 << 14); break;
2546 inst2 |= (3 << 10) + (1 << 14); break;
2548 inst2 |= (2 << 10) + (0 << 13); break;
2550 inst2 |= (3 << 10) + (0 << 13); break;
2553 inst2 |= (1 << 9) + (3 << 13);
2555 inst2 |= (0 << 9) + (3 << 13);
2558 return error("unsupported register");
2566 else if (am1 == CREG)
2576 int m_pmovefd(WORD inst, WORD siz)
2580 return m_pmove(inst | (1 << 8), siz);
2587 int m_ptrapcc(WORD inst, WORD siz)
2590 // We stash the 5 condition bits inside the opcode in 68ktab (bits 0-4),
2591 // so we need to extract them first and fill in the clobbered bits.
2592 WORD opcode = inst & 0x1F;
2593 inst = (inst & 0xFFE0) | (0x18);
2602 else if (siz == SIZL)
2609 else if (siz == SIZN)
2621 // ptestr, ptestw (68030, 68040)
2622 // TODO See comment on m_pmove about 68851 support
2623 // TODO quite a good chunk of the 030 code is copied from m_pload, perhaps merge these somehow?
2625 int m_ptest(WORD inst, WORD siz, WORD extension)
2629 if (activecpu != CPU_68030 && activecpu != CPU_68040)
2630 return error(unsupport);
2632 if (activecpu == CPU_68030)
2640 if (a0reg == REG68_SFC - REG68_SFC)
2642 else if (a0reg == REG68_DFC - REG68_SFC)
2645 return error("illegal control register specified");
2648 extension |= (1 << 3) | a0reg;
2651 if ((a0exattr & DEFINED) == 0)
2652 return error("constant value must be defined");
2655 return error("constant value must be between 0 and 7");
2657 extension |= (2 << 3) | (uint16_t)a0exval;
2661 // Operand 3 must be an immediate
2665 return error("ptest level must be immediate");
2667 // Let's be a bit inflexible here and demand that this
2668 // is fully defined at this stage. Otherwise we'd have
2669 // to arrange for a bitfield fixup, which would mean
2670 // polluting the bitfields and codebase with special
2671 // cases that might most likely never be used.
2672 // So if anyone gets bit by this: sorry for being a butt!
2673 if (abs_expr(&eval) != OK)
2674 return OK; // We're returning OK because error() has already been called and error count has been increased
2677 return error("ptest level must be between 0 and 7");
2679 extension |= eval << 10;
2681 // Operand 4 is optional and must be an address register
2687 if ((*tok >= REG68_A0) && (*tok <= REG68_A7))
2689 extension |= (1 << 8) | ((*tok++ & 7) << 4);
2693 return error("fourth parameter must be an address register");
2703 return error("Not implemented yet.");
2708 int m_ptestr(WORD inst, WORD siz)
2710 return m_ptest(inst, siz, (1 << 15) | (0 << 9));
2713 int m_ptestw(WORD inst, WORD siz)
2715 return m_ptest(inst, siz, (1 << 15) | (1 << 9));
2718 //////////////////////////////////////////////////////////////////////////////
2720 // 68020/30/40/60 instructions
2721 // Note: the map of which instructions are allowed on which CPUs came from the
2722 // 68060 manual, section D-1 (page 392 of the PDF). The current implementation
2723 // is missing checks for the EC models which have a simplified FPU.
2725 //////////////////////////////////////////////////////////////////////////////
2728 #define FPU_NOWARN 0
2733 // Generate a FPU opcode
2735 static inline int gen_fpu(WORD inst, WORD siz, WORD opmode, WORD emul)
2737 if (am0 < AM_NONE) // Check first operand for ea or fp - is this right?
2739 inst |= (1 << 9); // Bolt on FPU id
2742 //if (am0 == DREG || am0 == AREG)
2746 inst = 1 << 14; // R/M field (we have ea so have to set this to 1)
2750 case SIZB: inst |= (6 << 10); break;
2751 case SIZW: inst |= (4 << 10); break;
2752 case SIZL: inst |= (0 << 10); break;
2754 case SIZS: inst |= (1 << 10); break;
2755 case SIZD: inst |= (5 << 10); break;
2756 case SIZX: inst |= (2 << 10); break;
2761 warn("This encoding will cause an unimplemented data type exception in the MC68040 to allow emulation in software.");
2765 return error("Something bad happened, possibly, in gen_fpu.");
2769 inst |= (a1reg << 7);
2776 inst |= (1 << 9); // Bolt on FPU id
2780 inst |= (a1reg << 7);
2785 if ((emul & FPU_FPSP) && (activefpu == (FPU_68040 | FPU_68060)))
2786 warn("Instruction is emulated in 68040/060");
2793 // fabs (6888X, 68040FPSP, 68060FPSP)
2795 int m_fabs(WORD inst, WORD siz)
2798 return gen_fpu(inst, siz, 0b00011000, FPU_NOWARN);
2803 // fsabs (68040, 68060)
2805 int m_fsabs(WORD inst, WORD siz)
2808 if (activefpu == FPU_68040)
2809 return gen_fpu(inst, siz, 0b01011000, FPU_NOWARN);
2811 return error("Unsupported in current FPU");
2816 // fdabs (68040, 68060)
2818 int m_fdabs(WORD inst, WORD siz)
2820 if (activefpu == FPU_68040)
2821 return gen_fpu(inst, siz, 0b01011100, FPU_NOWARN);
2823 return error("Unsupported in current FPU");
2828 // facos (6888X, 68040FPSP, 68060FPSP)
2830 int m_facos(WORD inst, WORD siz)
2833 return gen_fpu(inst, siz, 0b00011100, FPU_FPSP);
2838 // fadd (6888X, 68040, 68060)
2840 int m_fadd(WORD inst, WORD siz)
2843 return gen_fpu(inst, siz, 0b00100010, FPU_NOWARN);
2848 // fsadd (68040, 68060)
2850 int m_fsadd(WORD inst, WORD siz)
2852 if (activefpu & (FPU_68040 | FPU_68060))
2853 return gen_fpu(inst, siz, 0b01100010, FPU_NOWARN);
2855 return error("Unsupported in current FPU");
2862 int m_fdadd(WORD inst, WORD siz)
2864 if (activefpu & (FPU_68040 | FPU_68060))
2865 return gen_fpu(inst, siz, 0b01100110, FPU_NOWARN);
2867 return error("Unsupported in current FPU");
2872 // fasin (6888X, 68040FPSP, 68060FPSP)
2874 int m_fasin(WORD inst, WORD siz)
2877 return gen_fpu(inst, siz, 0b00001100, FPU_FPSP);
2882 // fatan (6888X, 68040FPSP, 68060FPSP)
2884 int m_fatan(WORD inst, WORD siz)
2887 return gen_fpu(inst, siz, 0b00001010, FPU_FPSP);
2892 // fatanh (6888X, 68040FPSP, 68060FPSP)
2894 int m_fatanh(WORD inst, WORD siz)
2897 return gen_fpu(inst, siz, 0b00001101, FPU_FPSP);
2902 // fcmp (6888X, 68040, 68060)
2904 int m_fcmp(WORD inst, WORD siz)
2907 return gen_fpu(inst, siz, 0b00111000, FPU_FPSP);
2912 // fcos (6888X, 68040FPSP, 68060FPSP)
2914 int m_fcos(WORD inst, WORD siz)
2917 return gen_fpu(inst, siz, 0b00011101, FPU_FPSP);
2922 // fcosh (6888X, 68040FPSP, 68060FPSP)
2924 int m_fcosh(WORD inst, WORD siz)
2927 return gen_fpu(inst, siz, 0b00011001, FPU_FPSP);
2932 // fdbcc (6888X, 68040, 68060FPSP)
2934 int m_fdbcc(WORD inst, WORD siz)
2937 WORD opcode = inst & 0x3F; // Grab conditional bitfield
2947 if (a1exattr & DEFINED)
2949 if ((a1exattr & TDB) != cursect)
2950 return error(rel_error);
2952 uint32_t v = (uint32_t)a1exval - sloc;
2954 if ((v + 0x8000) > 0x10000)
2955 return error(range_error);
2961 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
2965 if (activefpu == FPU_68060)
2966 warn("Instruction is emulated in 68060");
2973 // fdiv (6888X, 68040, 68060)
2975 int m_fdiv(WORD inst, WORD siz)
2978 return gen_fpu(inst, siz, 0b00100000, FPU_NOWARN);
2983 // fsdiv (68040, 68060)
2985 int m_fsdiv(WORD inst, WORD siz)
2987 if (activefpu & (FPU_68040 | FPU_68060))
2988 return gen_fpu(inst, siz, 0b01100000, FPU_NOWARN);
2990 return error("Unsupported in current FPU");
2995 // fddiv (68040, 68060)
2997 int m_fddiv(WORD inst, WORD siz)
2999 if (activefpu & (FPU_68040 | FPU_68060))
3000 return gen_fpu(inst, siz, 0b01100100, FPU_NOWARN);
3002 return error("Unsupported in current FPU");
3007 // fetox (6888X, 68040FPSP, 68060FPSP)
3009 int m_fetox(WORD inst, WORD siz)
3012 return gen_fpu(inst, siz, 0b00010000, FPU_FPSP);
3017 // fetoxm1 (6888X, 68040FPSP, 68060FPSP)
3019 int m_fetoxm1(WORD inst, WORD siz)
3022 return gen_fpu(inst, siz, 0b00001000, FPU_FPSP);
3027 // fgetexp (6888X, 68040FPSP, 68060FPSP)
3029 int m_fgetexp(WORD inst, WORD siz)
3032 return gen_fpu(inst, siz, 0b00011110, FPU_FPSP);
3037 // fgetman (6888X, 68040FPSP, 68060FPSP)
3039 int m_fgetman(WORD inst, WORD siz)
3042 return gen_fpu(inst, siz, 0b00011111, FPU_FPSP);
3047 // fint (6888X, 68040FPSP, 68060)
3049 int m_fint(WORD inst, WORD siz)
3052 // special case - fint fpx = fint fpx,fpx
3055 if (activefpu == FPU_68040)
3056 warn("Instruction is emulated in 68040");
3058 return gen_fpu(inst, siz, 0b00000001, FPU_NOWARN);
3063 // fintrz (6888X, 68040FPSP, 68060)
3065 int m_fintrz(WORD inst, WORD siz)
3068 // special case - fintrz fpx = fintrz fpx,fpx
3071 if (activefpu == FPU_68040)
3072 warn("Instruction is emulated in 68040");
3074 return gen_fpu(inst, siz, 0b00000011, FPU_NOWARN);
3079 // flog10 (6888X, 68040FPSP, 68060FPSP)
3081 int m_flog10(WORD inst, WORD siz)
3084 return gen_fpu(inst, siz, 0b00010101, FPU_FPSP);
3089 // flog2 (6888X, 68040FPSP, 68060FPSP)
3091 int m_flog2(WORD inst, WORD siz)
3094 return gen_fpu(inst, siz, 0b00010110, FPU_FPSP);
3099 // flogn (6888X, 68040FPSP, 68060FPSP)
3101 int m_flogn(WORD inst, WORD siz)
3104 return gen_fpu(inst, siz, 0b00010100, FPU_FPSP);
3109 // flognp1 (6888X, 68040FPSP, 68060FPSP)
3111 int m_flognp1(WORD inst, WORD siz)
3114 return gen_fpu(inst, siz, 0b00000110, FPU_FPSP);
3119 // fmod (6888X, 68040FPSP, 68060FPSP)
3121 int m_fmod(WORD inst, WORD siz)
3124 return gen_fpu(inst, siz, 0b00100001, FPU_FPSP);
3129 // fmove (6888X, 68040, 68060)
3131 int m_fmove(WORD inst, WORD siz)
3136 if ((am0 == FREG) && (am1 < AM_USP))
3140 inst |= am1 | a1reg;
3149 case SIZB: inst |= (6 << 10); break;
3150 case SIZW: inst |= (4 << 10); break;
3151 case SIZL: inst |= (0 << 10); break;
3153 case SIZS: inst |= (1 << 10); break;
3154 case SIZD: inst |= (5 << 10); break;
3155 case SIZX: inst |= (2 << 10); break;
3156 case SIZP: inst |= (3 << 10);
3157 // In P size we have 2 cases: {#k} where k is immediate
3158 // and {Dn} where Dn=Data register
3163 inst |= bfval1 << 4;
3168 if (bfval1 > 63 && bfval1 < -64)
3169 return error("K-factor must be between -64 and 63");
3171 inst |= bfval1 & 127;
3176 return error("Something bad happened, possibly.");
3180 // Destination specifier
3181 inst |= (a0reg << 7);
3189 else if ((am0 < AM_USP) && (am1 == FREG))
3194 inst |= am0 | a0reg;
3203 case SIZB: inst |= (6 << 10); break;
3204 case SIZW: inst |= (4 << 10); break;
3205 case SIZL: inst |= (0 << 10); break;
3207 case SIZS: inst |= (1 << 10); break;
3208 case SIZD: inst |= (5 << 10); break;
3209 case SIZX: inst |= (2 << 10); break;
3210 case SIZP: inst |= (3 << 10); break;
3212 return error("Something bad happened, possibly.");
3216 // Destination specifier
3217 inst |= (a1reg << 7);
3225 else if ((am0 == FREG) && (am1 == FREG))
3227 // register-to-register
3228 // Essentially ea to register with R/0=0
3237 if (siz != SIZX && siz != SIZN)
3238 return error("Invalid size");
3241 inst |= (a0reg << 10);
3243 // Destination register
3244 inst |= (a1reg << 7);
3254 // fmove (6888X, 68040, 68060)
3256 int m_fmovescr(WORD inst, WORD siz)
3260 // Move Floating-Point System Control Register (FPCR)
3264 if ((am0 == FPSCR) && (am1 < AM_USP))
3266 inst |= am1 | a1reg;
3268 inst = (1 << 13) + (1 << 15);
3274 else if ((am1 == FPSCR) && (am0 < AM_USP))
3276 inst |= am0 | a0reg;
3278 inst = (0 << 13) + (1 << 15);
3285 return error("m_fmovescr says: wut?");
3289 // fsmove/fdmove (68040, 68060)
3291 int m_fsmove(WORD inst, WORD siz)
3293 if (!(activefpu & (FPU_68040 | FPU_68060)))
3294 return error("Unsupported in current FPU");
3296 return gen_fpu(inst, siz, 0b01100100, FPU_FPSP);
3300 int m_fdmove(WORD inst, WORD siz)
3302 if (!(activefpu & (FPU_68040 | FPU_68060)))
3303 return error("Unsupported in current FPU");
3305 return gen_fpu(inst, siz, 0b01100100, FPU_FPSP);
3310 // fmovecr (6888X, 68040FPSP, 68060FPSP)
3312 int m_fmovecr(WORD inst, WORD siz)
3322 if (activefpu == FPU_68040)
3323 warn("Instruction is emulated in 68040/060");
3330 // fmovem (6888X, 68040, 68060FPSP)
3332 int m_fmovem(WORD inst, WORD siz)
3339 if (siz == SIZX || siz == SIZN)
3341 if ((*tok >= REG68_FP0) && (*tok <= REG68_FP7))
3343 // fmovem.x <rlist>,ea
3344 if (fpu_reglist_left(®mask) < 0)
3348 return error("missing comma");
3353 inst |= am0 | a0reg;
3355 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3356 return error("invalid addressing mode");
3359 inst = (1 << 15) | (1 << 14) | (1 << 13) | (0 << 11) | regmask;
3364 else if ((*tok >= REG68_D0) && (*tok <= REG68_D7))
3367 datareg = (*tok++ & 7) << 10;
3370 return error("missing comma");
3375 inst |= am0 | a0reg;
3377 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3378 return error("invalid addressing mode");
3380 // Quote from the 060 manual:
3381 // "[..] when the processor attempts an FMOVEM.X instruction using a dynamic register list."
3382 if (activefpu == FPU_68060)
3383 warn("Instruction is emulated in 68060");
3386 inst = (1 << 15) | (1 << 14) | (1 << 13) | (1 << 11) | (datareg << 4);
3397 inst |= am0 | a0reg;
3400 return error("missing comma");
3402 if ((*tok >= REG68_FP0) && (*tok <= REG68_FP7))
3404 // fmovem.x ea,<rlist>
3405 if (fpu_reglist_right(®mask) < 0)
3409 inst = (1 << 15) | (1 << 14) | (0 << 13) | (2 << 11) | regmask;
3417 datareg = (*tok++ & 7) << 10;
3419 // Quote from the 060 manual:
3420 // "[..] when the processor attempts an FMOVEM.X instruction using a dynamic register list."
3421 if (activefpu == FPU_68060)
3422 warn("Instruction is emulated in 68060");
3425 inst = (1 << 15) | (1 << 14) | (0 << 13) | (3 << 11) | (datareg << 4);
3432 else if (siz == SIZL)
3434 if ((*tok == REG68_FPCR) || (*tok == REG68_FPSR) || (*tok == REG68_FPIAR))
3436 // fmovem.l <rlist>,ea
3437 regmask = (1 << 15) | (1 << 13);
3438 int no_control_regs = 0;
3441 if (*tok == REG68_FPCR)
3443 regmask |= (1 << 12);
3449 if (*tok == REG68_FPSR)
3451 regmask |= (1 << 11);
3457 if (*tok == REG68_FPIAR)
3459 regmask |= (1 << 10);
3465 if ((*tok == '/') || (*tok == '-'))
3472 return error("missing comma");
3477 // Quote from the 060 manual:
3478 // "[..] when the processor attempts to execute an FMOVEM.L instruction with
3479 // an immediate addressing mode to more than one floating - point
3480 // control register (FPCR, FPSR, FPIAR)[..]"
3481 if (activefpu == FPU_68060)
3482 if (no_control_regs > 1 && am0 == IMMED)
3483 warn("Instruction is emulated in 68060");
3485 inst |= am0 | a0reg;
3492 // fmovem.l ea,<rlist>
3496 inst |= am0 | a0reg;
3499 return error("missing comma");
3501 regmask = (1 << 15) | (0 << 13);
3504 if (*tok == REG68_FPCR)
3506 regmask |= (1 << 12);
3511 if (*tok == REG68_FPSR)
3513 regmask |= (1 << 11);
3518 if (*tok == REG68_FPIAR)
3520 regmask |= (1 << 10);
3525 if ((*tok == '/') || (*tok == '-'))
3532 return error("extra (unexpected) text found");
3534 inst |= am0 | a0reg;
3541 return error("bad size suffix");
3548 // fmul (6888X, 68040, 68060)
3550 int m_fmul(WORD inst, WORD siz)
3553 return gen_fpu(inst, siz, 0b00100011, FPU_NOWARN);
3558 // fsmul (68040, 68060)
3560 int m_fsmul(WORD inst, WORD siz)
3562 if (activefpu & (FPU_68040 | FPU_68060))
3563 return gen_fpu(inst, siz, 0b01100011, FPU_NOWARN);
3565 return error("Unsupported in current FPU");
3572 int m_fdmul(WORD inst, WORD siz)
3574 if (activefpu & (FPU_68040 | FPU_68060))
3575 return gen_fpu(inst, siz, 0b01100111, FPU_NOWARN);
3577 return error("Unsupported in current FPU");
3582 // fneg (6888X, 68040, 68060)
3584 int m_fneg(WORD inst, WORD siz)
3591 return gen_fpu(inst, siz, 0b00011010, FPU_NOWARN);
3594 return gen_fpu(inst, siz, 0b00011010, FPU_NOWARN);
3599 // fsneg (68040, 68060)
3601 int m_fsneg(WORD inst, WORD siz)
3603 if (activefpu & (FPU_68040 | FPU_68060))
3608 return gen_fpu(inst, siz, 0b01011010, FPU_NOWARN);
3611 return gen_fpu(inst, siz, 0b01011010, FPU_NOWARN);
3614 return error("Unsupported in current FPU");
3619 // fdneg (68040, 68060)
3621 int m_fdneg(WORD inst, WORD siz)
3623 if (activefpu & (FPU_68040 | FPU_68060))
3628 return gen_fpu(inst, siz, 0b01011110, FPU_NOWARN);
3631 return gen_fpu(inst, siz, 0b01011110, FPU_NOWARN);
3634 return error("Unsupported in current FPU");
3639 // fnop (6888X, 68040, 68060)
3641 int m_fnop(WORD inst, WORD siz)
3644 return gen_fpu(inst, siz, 0b00000000, FPU_NOWARN);
3649 // frem (6888X, 68040FPSP, 68060FPSP)
3651 int m_frem(WORD inst, WORD siz)
3654 return gen_fpu(inst, siz, 0b00100101, FPU_FPSP);
3659 // fscale (6888X, 68040FPSP, 68060FPSP)
3661 int m_fscale(WORD inst, WORD siz)
3664 return gen_fpu(inst, siz, 0b00100110, FPU_FPSP);
3669 // FScc (6888X, 68040, 68060), cpScc (68851, 68030), PScc (68851)
3670 // TODO: Add check for PScc to ensure 68020+68851 active
3671 // TODO: Add check for cpScc to ensure 68020+68851, 68030
3673 int m_fscc(WORD inst, WORD siz)
3677 // We stash the 5 condition bits inside the opcode in 68ktab (bits 4-0),
3678 // so we need to extract them first and fill in the clobbered bits.
3679 WORD opcode = inst & 0x1F;
3681 inst |= am0 | a0reg;
3685 if (activefpu == FPU_68060)
3686 warn("Instruction is emulated in 68060");
3692 // fsgldiv (6888X, 68040FPSP, 68060FPSP)
3694 int m_fsgldiv(WORD inst, WORD siz)
3697 return gen_fpu(inst, siz, 0b00100100, FPU_FPSP);
3702 // fsglmul (6888X, 68040, 68060FPSP)
3704 int m_fsglmul(WORD inst, WORD siz)
3707 return gen_fpu(inst, siz, 0b00100111, FPU_FPSP);
3712 // fsin (6888X, 68040FPSP, 68060FPSP)
3714 int m_fsin(WORD inst, WORD siz)
3717 return gen_fpu(inst, siz, 0b00001110, FPU_FPSP);
3722 // fsincos (6888X, 68040FPSP, 68060FPSP)
3724 int m_fsincos(WORD inst, WORD siz)
3728 // Swap a1reg, a2reg as a2reg should be stored in the bitfield gen_fpu
3735 if (gen_fpu(inst, siz, 0b00110000, FPU_FPSP) == OK)
3746 // fsinh (6888X, 68040FPSP, 68060FPSP)
3748 int m_fsinh(WORD inst, WORD siz)
3751 return gen_fpu(inst, siz, 0b00000010, FPU_FPSP);
3756 // fsqrt (6888X, 68040, 68060)
3758 int m_fsqrt(WORD inst, WORD siz)
3761 return gen_fpu(inst, siz, 0b00000100, FPU_NOWARN);
3766 // fsfsqrt (68040, 68060)
3768 int m_fsfsqrt(WORD inst, WORD siz)
3770 if (activefpu & (FPU_68040 | FPU_68060))
3771 return gen_fpu(inst, siz, 0b01000001, FPU_NOWARN);
3773 return error("Unsupported in current FPU");
3778 // fdfsqrt (68040, 68060)
3780 int m_fdfsqrt(WORD inst, WORD siz)
3782 if (activefpu & (FPU_68040 | FPU_68060))
3783 return gen_fpu(inst, siz, 0b01000101, FPU_NOWARN);
3785 return error("Unsupported in current FPU");
3790 // fsub (6888X, 68040, 68060)
3792 int m_fsub(WORD inst, WORD siz)
3795 return gen_fpu(inst, siz, 0b00101000, FPU_NOWARN);
3800 // fsfsub (68040, 68060)
3802 int m_fsfsub(WORD inst, WORD siz)
3804 if (activefpu & (FPU_68040 | FPU_68060))
3805 return gen_fpu(inst, siz, 0b01101000, FPU_NOWARN);
3807 return error("Unsupported in current FPU");
3812 // fdfsub (68040, 68060)
3814 int m_fdsub(WORD inst, WORD siz)
3816 if (activefpu & (FPU_68040 | FPU_68060))
3817 return gen_fpu(inst, siz, 0b01101100, FPU_NOWARN);
3819 return error("Unsupported in current FPU");
3824 // ftan (6888X, 68040FPSP, 68060FPSP)
3826 int m_ftan(WORD inst, WORD siz)
3829 return gen_fpu(inst, siz, 0b00001111, FPU_FPSP);
3834 // ftanh (6888X, 68040FPSP, 68060FPSP)
3836 int m_ftanh(WORD inst, WORD siz)
3839 return gen_fpu(inst, siz, 0b00001001, FPU_FPSP);
3844 // ftentox (6888X, 68040FPSP, 68060FPSP)
3846 int m_ftentox(WORD inst, WORD siz)
3849 return gen_fpu(inst, siz, 0b00010010, FPU_FPSP);
3854 // FTRAPcc (6888X, 68040, 68060FPSP)
3856 int m_ftrapcc(WORD inst, WORD siz)
3860 // We stash the 5 condition bits inside the opcode in 68ktab (bits 3-7),
3861 // so we need to extract them first and fill in the clobbered bits.
3862 WORD opcode = (inst >> 3) & 0x1F;
3863 inst = (inst & 0xFF07) | (0xF << 3);
3872 else if (siz == SIZL)
3879 else if (siz == SIZN)
3887 if (activefpu == FPU_68060)
3888 warn("Instruction is emulated in 68060");
3895 // ftst (6888X, 68040, 68060)
3897 int m_ftst(WORD inst, WORD siz)
3900 return gen_fpu(inst, siz, 0b00111010, FPU_NOWARN);
3905 // ftwotox (6888X, 68040FPSP, 68060FPSP)
3907 int m_ftwotox(WORD inst, WORD siz)
3910 return gen_fpu(inst, siz, 0b00010001, FPU_FPSP);
3914 /////////////////////////////////
3916 // 68060 specific instructions //
3918 /////////////////////////////////
3924 int m_lpstop(WORD inst, WORD siz)
3927 D_word(0b0000000111000000);
3929 if (a0exattr & DEFINED)
3935 AddFixup(FU_WORD, sloc, a0expr);
3946 int m_plpa(WORD inst, WORD siz)
3949 inst |= a0reg; // Install register