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);
358 warn("lea size(An),An converted to addq #size,An");
362 return m_ea(inst, siz);
366 int m_ea030(WORD inst, WORD siz)
369 WORD flg = inst; // Save flag bits
370 inst &= ~0x3F; // Clobber flag bits in instr
372 // Install "standard" instr size bits
378 // OR-in register number
381 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
385 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
392 inst |= am1 | a1reg; // Get ea1 into instr
393 D_word(inst); // Deposit instr
395 // Generate ea0 if requested
399 ea1gen(siz); // Generate ea1
405 // We get here if we're doing 020+ addressing and an address
406 // register is used. For example, something like "tst a0". A bit of
407 // a corner case, so kludge it
409 else if (am0 == PCDISP)
410 // Another corner case (possibly!), so kludge ahoy
411 inst |= am0; // Get ea0 into instr
412 else if (am0 == IMMED && am1 == MEMPOST)
414 // Added for addi/andi/cmpi/eori/ori/subi #xx,(bd,An,Dm)
415 inst |= a1reg | AINDEXED;
417 else if (am0 == IMMED)
418 inst |= am0 | a0reg; // Get ea0 into instr
419 else if (am0 == AM_CCR)
421 else if (am0 == AIND)
424 inst |= a0reg; // Get ea0 into instr
425 D_word(inst); // Deposit instr
426 ea0gen(siz); // Generate ea0
428 // Generate ea1 if requested
438 // Dx,Dy nnnnXXXnssnnnYYY If bit 0 of `inst' is set, install size bits in bits
441 int m_abcd(WORD inst, WORD siz)
450 inst |= a0reg | reg_9[a1reg];
460 int m_adda(WORD inst, WORD siz)
462 if ((a0exattr & DEFINED) && (am0 == IMMED))
464 if (CHECK_OPTS(OPT_ADDA_ADDQ))
465 if (a0exval > 1 && a0exval <= 8)
467 // Immediate is between 1 and 8 so let's convert to addq
468 return m_addq(B16(01010000, 00000000), siz);
470 warn("adda/suba size(An),An converted to addq/subq #size,An");
472 if (CHECK_OPTS(OPT_ADDA_LEA))
473 if (a0exval > 8 && (a0exval + 0x8000) < 0x10000)
475 // Immediate is larger than 8 and word size so let's convert to lea
476 am0 = ADISP; // Change addressing mode
477 a0reg = a1reg; // In ADISP a0reg is used instead of a1reg!
478 if (!(inst & (1 << 14)))
480 // We have a suba #x,AREG so let's negate the value
484 // We're going to rely on +o4 for this, so let's ensure that it's on,
485 // even just for this instruction
487 int temp_flag = optim_flags[OPT_LEA_ADDQ];
488 optim_flags[OPT_LEA_ADDQ] = 1; // Temporarily save switch state
489 return_value = m_lea(B16(01000001, 11011000), SIZW);
490 optim_flags[OPT_LEA_ADDQ] = temp_flag; // Restore switch state
495 inst |= am0 | a0reg | lwsiz_8[siz] | reg_9[a1reg];
497 ea0gen(siz); // Generate EA
504 // If bit 0 of `inst' is 1, install size bits in bits 6..7 of instr.
505 // If bit 1 of `inst' is 1, install a1reg in bits 9..11 of instr.
507 int m_reg(WORD inst, WORD siz)
514 // Install other register (9..11)
515 inst |= reg_9[a1reg];
517 inst &= ~7; // Clear off crufty bits
518 inst |= a0reg; // Install first register
528 int m_imm(WORD inst, WORD siz)
540 int m_imm8(WORD inst, WORD siz)
553 int m_shr(WORD inst, WORD siz)
555 inst |= reg_9[a0reg] | a1reg | siz_6[siz];
565 int m_shi(WORD inst, WORD siz)
567 inst |= a1reg | siz_6[siz];
569 if (a0exattr & DEFINED)
572 return error(range_error);
574 inst |= (a0exval & 7) << 9;
579 AddFixup(FU_QUICK, sloc, a0expr);
588 // {bset, btst, bchg, bclr} -- #immed,ea -- Dn,ea
590 int m_bitop(WORD inst, WORD siz)
592 // Enforce instruction sizes
594 { // X,Dn must be .n or .l
595 if (siz & (SIZB | SIZW))
596 return error(siz_error);
598 else if (siz & (SIZW | SIZL)) // X,ea must be .n or .b
599 return error(siz_error);
601 // Construct instr and EAs
607 ea0gen(SIZB); // Immediate bit number
611 inst |= reg_9[a0reg];
622 int m_dbra(WORD inst, WORD siz)
628 if (a1exattr & DEFINED)
630 if ((a1exattr & TDB) != cursect)
631 return error(rel_error);
633 uint32_t v = (uint32_t)a1exval - sloc;
635 if (v + 0x8000 > 0x10000)
636 return error(range_error);
642 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
653 int m_exg(WORD inst, WORD siz)
659 if (am0 == DREG && am1 == DREG)
661 else if (am0 == AREG && am1 == AREG)
667 m = a1reg; // Get AREG into a1reg
675 inst |= m | reg_9[a0reg] | a1reg;
685 int m_link(WORD inst, WORD siz)
689 // Is this an error condition???
694 inst &= ~((3 << 9) | (1 << 6) | (1 << 4));
706 WORD extra_addressing[16]=
708 0x30, // 0100 (bd,An,Xn)
709 0x30, // 0101 ([bd,An],Xn,od)
710 0x30, // 0102 ([bc,An,Xn],od)
711 0x30, // 0103 (bd,PC,Xn)
712 0x30, // 0104 ([bd,PC],Xn,od)
713 0x30, // 0105 ([bc,PC,Xn],od)
728 // Handle MOVE <C_ALL> <C_ALTDATA>
729 // MOVE <C_ALL> <M_AREG>
731 // Optimize MOVE.L #<smalldata>,D0 to a MOVEQ
733 int m_move(WORD inst, WORD size)
735 // Cast the passed in value to an int
738 // Try to optimize to MOVEQ
739 // N.B.: We can get away with casting the uint64_t to a 32-bit value
740 // because it checks for a SIZL (i.e., a 32-bit value).
741 if (CHECK_OPTS(OPT_MOVEL_MOVEQ)
742 && (siz == SIZL) && (am0 == IMMED) && (am1 == DREG)
743 && ((a0exattr & (TDB | DEFINED)) == DEFINED)
744 && ((uint32_t)a0exval + 0x80 < 0x100))
746 m_moveq((WORD)0x7000, (WORD)0);
749 warn("move.l #size,dx converted to moveq");
753 if ((am0 < ABASE) && (am1 < ABASE)) // 68000 modes
755 inst |= siz_12[siz] | am_6[am1] | reg_9[a1reg] | am0 | a0reg;
763 ea1gen((WORD)siz | 0x8000); // Tell ea1gen we're move ea,ea
767 inst |= siz_12[siz] | reg_9[a1reg] | extra_addressing[am0 - ABASE];
784 // Handle MOVE <C_ALL030> <C_ALTDATA>
785 // MOVE <C_ALL030> <M_AREG>
787 int m_move30(WORD inst, WORD size)
790 inst |= siz_12[siz] | reg_9[a1reg & 7] | a0reg | extra_addressing[am0 - ABASE];
805 // move USP,An -- move An,USP
807 int m_usp(WORD inst, WORD siz)
812 inst |= a1reg; // USP, An
814 inst |= a0reg; // An, USP
825 int m_moveq(WORD inst, WORD siz)
829 // Arrange for future fixup
830 if (!(a0exattr & DEFINED))
832 AddFixup(FU_BYTE | FU_SEXT, sloc + 1, a0expr);
835 else if ((uint32_t)a0exval + 0x100 >= 0x200)
836 return error(range_error);
838 inst |= reg_9[a1reg] | (a0exval & 0xFF);
846 // movep Dn, disp(An) -- movep disp(An), Dn
848 int m_movep(WORD inst, WORD siz)
850 // Tell ea0gen to lay off the 0(a0) optimisations on this one
858 inst |= reg_9[a0reg] | a1reg;
868 inst |= reg_9[a1reg] | a0reg;
885 int m_br(WORD inst, WORD siz)
887 if (a0exattr & DEFINED)
889 if ((a0exattr & TDB) != cursect)
891 //printf("m_br(): a0exattr = %X, cursect = %X, a0exval = %X, sloc = %X\n", a0exattr, cursect, a0exval, sloc);
892 return error(rel_error);
895 uint32_t v = (uint32_t)a0exval - (sloc + 2);
897 // Optimize branch instr. size
900 if (CHECK_OPTS(OPT_BSR_BCC_S) && (v != 0) && ((v + 0x80) < 0x100))
907 warn("Bcc.w/BSR.w converted to .s");
914 if ((v + 0x8000) > 0x10000)
915 return error(range_error);
923 if (siz == SIZB || siz == SIZS)
925 if ((v + 0x80) >= 0x100)
926 return error(range_error);
933 if ((v + 0x8000) >= 0x10000)
934 return error(range_error);
942 else if (siz == SIZN)
945 if (siz == SIZB || siz == SIZS)
948 AddFixup(FU_BBRA | FU_PCREL | FU_SEXT, sloc, a0expr);
949 // So here we have a small issue: this bra.s could be zero offset, but we can never know.
950 // Because unless we know beforehand that the offset will be zero (i.e. "bra.s +0"), it's
951 // going to be a label below this instruction! We do have an optimisation flag that can
952 // check against this during fixups, but we cannot rely on the state of the flag after
953 // all the file(s) have been processed because its state might have changed multiple times
954 // during file parsing. (Yes, there's a very low chance that this will ever happen but
955 // it's not zero!). So, we can use the byte that is going to be filled during fixups
956 // to store the state of the optimisation flag and read it during that stage so each bra.s
957 // will have its state stored neatly. Sleazy? Eh, who cares, like this will ever happen ;)
958 // One final note: we'd better be damn sure that the flag's value is less than 256 or
959 // magical stuff will happen!
960 D_word(inst|optim_flags[OPT_NULL_BRA]);
967 AddFixup(FU_WORD | FU_PCREL | FU_LBRA | FU_ISBRA, sloc, a0expr);
978 int m_addq(WORD inst, WORD siz)
980 inst |= siz_6[siz] | am1 | a1reg;
982 if (a0exattr & DEFINED)
984 if ((a0exval > 8) || (a0exval == 0)) // Range in 1..8
985 return error(range_error);
987 inst |= (a0exval & 7) << 9;
992 AddFixup(FU_QUICK, sloc, a0expr);
1005 int m_trap(WORD inst, WORD siz)
1009 if (a0exattr & DEFINED)
1012 return error(abs_error);
1015 return error(range_error);
1021 return error(undef_error);
1028 // movem <rlist>,ea -- movem ea,<rlist>
1030 int m_movem(WORD inst, WORD siz)
1038 return error("bad size suffix");
1045 // Handle #<expr>, ea
1048 if (abs_expr(&eval) != OK)
1051 if (eval >= 0x10000L)
1052 return error(range_error);
1058 if ((*tok >= KW_D0) && (*tok <= KW_A7))
1061 if (reglist(&rmask) < 0)
1066 return error("missing comma");
1071 inst |= am0 | a0reg;
1073 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
1074 return error("invalid addressing mode");
1076 // If APREDEC, reverse register mask
1082 for(i=0x8000; i; i>>=1, w>>=1)
1083 rmask = (WORD)((rmask << 1) | (w & 1));
1092 inst |= 0x0400 | am0 | a0reg;
1095 return error("missing comma");
1098 return error("missing register list");
1105 if (abs_expr(&eval) != OK)
1108 if (eval >= 0x10000)
1109 return error(range_error);
1113 else if (reglist(&rmask) < 0)
1116 if (!(amsktab[am0] & (C_CTRL | M_APOSTINC)))
1117 return error("invalid addressing mode");
1129 // CLR.x An ==> SUBA.x An,An
1131 int m_clra(WORD inst, WORD siz)
1133 inst |= a0reg | reg_9[a0reg] | lwsiz_8[siz];
1141 // CLR.L Dn ==> CLR.L An or MOVEQ #0,Dx
1143 int m_clrd(WORD inst, WORD siz)
1145 if (!CHECK_OPTS(OPT_CLR_DX))
1148 inst = (a0reg << 9) | B16(01110000, 00000000);
1156 ////////////////////////////////////////
1158 // 68020/30/40/60 instructions
1160 ////////////////////////////////////////
1165 int m_br30(WORD inst, WORD siz)
1167 if (a0exattr & DEFINED)
1169 if ((a0exattr & TDB) != cursect)
1170 return error(rel_error);
1172 uint32_t v = (uint32_t)a0exval - (sloc + 2);
1181 AddFixup(FU_LONG | FU_PCREL | FU_SEXT, sloc, a0expr);
1189 // bfchg, bfclr, bfexts, bfextu, bfffo, bfins, bfset
1190 // (68020, 68030, 68040)
1192 int m_bfop(WORD inst, WORD siz)
1194 if ((bfval1 > 31) || (bfval1 < 0))
1195 return error("bfxxx offset: immediate value must be between 0 and 31");
1197 // First instruction word - just the opcode and first EA
1198 // Note: both am1 is ORed because solely of bfins - maybe it's a good idea
1199 // to make a dedicated function for it?
1206 if (bfval2 > 31 || bfval2 < 0)
1207 return error("bfxxx width: immediate value must be between 0 and 31");
1209 // For Dw both immediate and register number are stuffed
1210 // into the same field O_o
1211 bfparam2 = (bfval2 << 0);
1215 bfparam1 = (bfval1 << 6);
1217 bfparam1 = bfval1 << 12;
1219 //D_word((inst | am0 | a0reg | am1 | a1reg));
1220 if (inst == B16(11101111, 11000000))
1222 // bfins special case
1223 D_word((inst | am1 | a1reg));
1227 D_word((inst | am0 | a0reg));
1230 ea0gen(siz); // Generate EA
1232 // Second instruction word - Dest register (if exists), Do, Offset, Dw, Width
1233 if (inst == B16(11101111, 11000000))
1235 // bfins special case
1236 inst = bfparam1 | bfparam2;
1239 inst |= a0reg << 12;
1245 inst = bfparam1 | bfparam2;
1251 inst |= a1reg << 12;
1261 // bkpt (68EC000, 68010, 68020, 68030, 68040, CPU32)
1263 int m_bkpt(WORD inst, WORD siz)
1267 if (a0exattr & DEFINED)
1270 return error(abs_error);
1273 return error(range_error);
1279 return error(undef_error);
1288 int m_callm(WORD inst, WORD siz)
1295 if (a0exattr & DEFINED)
1298 return error(abs_error);
1301 return error(range_error);
1303 inst = (uint16_t)a0exval;
1307 return error(undef_error);
1317 // cas (68020, 68030, 68040)
1319 int m_cas(WORD inst, WORD siz)
1325 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1326 return error(unsupport);
1341 return error("bad size suffix");
1346 if ((*tok < KW_D0) && (*tok > KW_D7))
1347 return error("CAS accepts only data registers");
1349 inst2 = (*tok++) & 7;
1352 return error("missing comma");
1355 if ((*tok < KW_D0) && (*tok > KW_D7))
1356 return error("CAS accepts only data registers");
1358 inst2 |= ((*tok++) & 7) << 6;
1361 return error("missing comma");
1364 if ((modes = amode(1)) < 0)
1368 return error("too many ea fields");
1371 return error("extra (unexpected) text found");
1373 // Reject invalid ea modes
1374 amsk = amsktab[am0];
1376 if ((amsk & (M_AIND | M_APOSTINC | M_APREDEC | M_ADISP | M_AINDEXED | M_ABSW | M_ABSL | M_ABASE | M_MEMPOST | M_MEMPRE)) == 0)
1377 return error("unsupported addressing mode");
1379 inst |= am0 | a0reg;
1389 // cas2 (68020, 68030, 68040)
1391 int m_cas2(WORD inst, WORD siz)
1395 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1396 return error(unsupport);
1411 return error("bad size suffix");
1416 if ((*tok < KW_D0) && (*tok > KW_D7))
1417 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1419 inst2 = (*tok++) & 7;
1422 return error("missing colon");
1425 if ((*tok < KW_D0) && (*tok > KW_D7))
1426 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1428 inst3 = (*tok++) & 7;
1431 return error("missing comma");
1434 if ((*tok < KW_D0) && (*tok > KW_D7))
1435 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1437 inst2 |= ((*tok++) & 7) << 6;
1440 return error("missing colon");
1443 if ((*tok < KW_D0) && (*tok > KW_D7))
1444 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1446 inst3 |= ((*tok++) & 7) << 6;
1449 return error("missing comma");
1453 return error("missing (");
1454 if ((*tok >= KW_D0) && (*tok <= KW_D7))
1455 inst2 |= (((*tok++) & 7) << 12) | (0 << 15);
1456 else if ((*tok >= KW_A0) && (*tok <= KW_A7))
1457 inst2 |= (((*tok++) & 7) << 12) | (1 << 15);
1459 return error("CAS accepts either data or address registers for Rn1:Rn2 pair");
1462 return error("missing (");
1465 return error("missing colon");
1469 return error("missing (");
1470 if ((*tok >= KW_D0) && (*tok <= KW_D7))
1471 inst3 |= (((*tok++) & 7) << 12) | (0 << 15);
1472 else if ((*tok >= KW_A0) && (*tok <= KW_A7))
1473 inst3 |= (((*tok++) & 7) << 12) | (1 << 15);
1475 return error("CAS accepts either data or address registers for Rn1:Rn2 pair");
1478 return error("missing (");
1481 return error("extra (unexpected) text found");
1492 // cmp2 (68020, 68030, 68040, CPU32)
1494 int m_cmp2(WORD inst, WORD siz)
1496 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1497 return error(unsupport);
1499 switch (siz & 0x000F)
1513 WORD flg = inst; // Save flag bits
1514 inst &= ~0x3F; // Clobber flag bits in instr
1516 // Install "standard" instr size bits
1522 // OR-in register number
1524 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1526 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1532 inst |= am1 | a1reg; // Get ea1 into instr
1533 D_word(inst); // Deposit instr
1535 // Generate ea0 if requested
1539 ea1gen(siz); // Generate ea1
1544 inst |= am0 | a0reg; // Get ea0 into instr
1545 D_word(inst); // Deposit instr
1546 ea0gen(siz); // Generate ea0
1548 // Generate ea1 if requested
1553 // If we're called from chk2 then bit 11 of size will be set. This is just
1554 // a dumb mechanism to pass this, required by the extension word. (You might
1555 // have noticed the siz & 15 thing above!)
1556 inst = (a1reg << 12) | (siz & (1 << 11));
1568 // chk2 (68020, 68030, 68040, CPU32)
1570 int m_chk2(WORD inst, WORD siz)
1572 return m_cmp2(inst, siz | (1 << 11));
1577 // cpbcc(68020, 68030, 68040 (FBcc), 68060 (FBcc)), pbcc (68851)
1579 int m_fpbr(WORD inst, WORD siz)
1582 if (a0exattr & DEFINED)
1584 if ((a0exattr & TDB) != cursect)
1585 return error(rel_error);
1587 uint32_t v = (uint32_t)a0exval - (sloc + 2);
1589 // Optimize branch instr. size
1592 if ((v != 0) && ((v + 0x8000) < 0x10000))
1602 if ((v + 0x8000) >= 0x10000)
1603 return error(range_error);
1611 else if (siz == SIZN)
1618 AddFixup(FU_LONG | FU_PCREL | FU_SEXT, sloc, a0expr);
1626 AddFixup(FU_WORD | FU_PCREL | FU_SEXT, sloc, a0expr);
1635 // cpbcc(68020, 68030, 68040 (FBcc), 68060 (FBcc))
1637 int m_cpbcc(WORD inst, WORD siz)
1639 if (!(activecpu & (CPU_68020 | CPU_68030)))
1640 return error(unsupport);
1642 return m_fpbr(inst, siz);
1647 // fbcc(6808X, 68040, 68060)
1649 int m_fbcc(WORD inst, WORD siz)
1652 return m_fpbr(inst, siz);
1657 // pbcc(68851 but let's assume 68020 only)
1659 int m_pbcc(WORD inst, WORD siz)
1662 return m_fpbr(inst, siz);
1667 // cpdbcc(68020, 68030)
1669 int m_cpdbr(WORD inst, WORD siz)
1674 WORD condition = inst & 0x1F; // Grab condition sneakily placed in the lower 5 bits of inst
1675 inst &= 0xFFE0; // And then mask them out - you ain't seen me, roit?
1677 inst |= (1 << 9); // Bolt on FPU id
1684 if (a1exattr & DEFINED)
1686 if ((a1exattr & TDB) != cursect)
1687 return error(rel_error);
1689 v = (uint32_t)a1exval - sloc;
1691 if (v + 0x8000 > 0x10000)
1692 return error(range_error);
1698 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
1708 // muls.l / divs.l / divu.l / mulu.l (68020+)
1710 int m_muls(WORD inst, WORD siz)
1712 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1713 return error(unsupport);
1715 WORD flg = inst; // Save flag bits
1716 inst &= ~0x33F; // Clobber flag and extension bits in instr
1718 // Install "standard" instr size bits
1724 // OR-in register number
1726 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1728 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1731 // Regarding extension word: bit 11 is signed/unsigned selector
1732 // bit 10 is 32/64 bit selector
1733 // Both of these are packed in bits 9 and 8 of the instruction
1734 // field in 68ktab. Extra compilcations arise from the fact we
1735 // have to distinguish between divu/s.l Dn,Dm (which is encoded
1736 // as divu/s.l Dn,Dm:Dm) and divu/s.l Dn,Dm:Dx - the first is
1737 // 32 bit while the second 64 bit
1742 inst |= am1 | a1reg; // Get ea1 into instr
1743 D_word(inst); // Deposit instr
1747 inst = a1reg + (a2reg << 12) + ((flg & 0x200) << 2);
1749 inst = a1reg + (a2reg << 12) + ((flg & 0x300) << 2);
1753 // Generate ea0 if requested
1757 ea1gen(siz); // Generate ea1
1764 inst |= am0 | a0reg; // Get ea0 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 ea0gen(siz); // Generate ea0
1777 // Generate ea1 if requested
1787 // move16 (ax)+,(ay)+
1789 int m_move16a(WORD inst, WORD siz)
1791 if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1792 return error(unsupport);
1796 inst = (1 << 15) + (a1reg << 12);
1804 // move16 with absolute address
1806 int m_move16b(WORD inst, WORD siz)
1808 if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1809 return error(unsupport);
1815 if (am0 == APOSTINC)
1818 return error("Wasn't this suppose to call m_move16a???");
1821 // move16 (ax)+,(xxx).L
1826 else if (am0 == ABSL)
1830 // move16 (xxx).L,(ax)+
1836 // move16 (xxx).L,(ax)
1841 else if (am0 == AIND)
1843 // move16 (ax),(xxx).L
1856 // pack/unpack (68020/68030/68040)
1858 int m_pack(WORD inst, WORD siz)
1863 return error("bad size suffix");
1865 if (*tok >= KW_D0 && *tok <= KW_D7)
1867 // Dx,Dy,#<adjustment>
1868 inst |= (0 << 3); // R/M
1869 inst |= (*tok++ & 7);
1871 if (*tok != ',' && tok[2] != ',')
1872 return error("missing comma");
1874 if (tok[1] < KW_D0 && tok[1] > KW_D7)
1875 return error(syntax_error);
1877 inst |= ((tok[1] & 7)<<9);
1880 // Fall through for adjustment (common in both valid cases)
1882 else if (*tok == '-')
1884 // -(Ax),-(Ay),#<adjustment>
1885 inst |= (1 << 3); // R/M
1886 tok++; // eat the minus
1888 if ((*tok != '(') && (tok[2]!=')') && (tok[3]!=',') && (tok[4] != '-') && (tok[5] != '(') && (tok[7] != ')') && (tok[8] != ','))
1889 return error(syntax_error);
1891 if (tok[1] < KW_A0 && tok[1] > KW_A7)
1892 return error(syntax_error);
1894 if (tok[5] < KW_A0 && tok[6] > KW_A7)
1895 return error(syntax_error);
1897 inst |= ((tok[1] & 7) << 0);
1898 inst |= ((tok[6] & 7) << 9);
1901 // Fall through for adjustment (common in both valid cases)
1904 return error("invalid syntax");
1906 if ((*tok != CONST) && (*tok != SYMBOL) && (*tok != '-'))
1907 return error(syntax_error);
1909 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
1912 if ((a0exattr & DEFINED) == 0)
1913 return error(undef_error);
1915 if (a0exval + 0x8000 > 0x10000)
1919 return error(extra_stuff);
1921 D_word((a0exval & 0xFFFF));
1930 int m_rtm(WORD inst, WORD siz)
1938 else if (am0 == AREG)
1940 inst |= (1 << 3) + a0reg;
1943 return error("rtm only allows data or address registers.");
1954 int m_rtd(WORD inst, WORD siz)
1958 if (a0exattr & DEFINED)
1961 return error(abs_error);
1963 if ((a0exval + 0x8000) <= 0x7FFF)
1964 return error(range_error);
1970 return error(undef_error);
1979 int m_trapcc(WORD inst, WORD siz)
1987 else if (am0 == IMMED)
1991 if (a0exval < 0x10000)
1998 return error("Immediate value too big");
2008 return error("Invalid parameter for trapcc");
2015 // cinvl/p/a (68040/68060)
2017 int m_cinv(WORD inst, WORD siz)
2022 inst |= (0 << 6) | (a1reg);
2026 inst |= (2 << 6) | (a1reg);
2029 inst |= (1 << 6) | (a1reg);
2032 inst |= (3 << 6) | (a1reg);
2041 int m_fpusavrest(WORD inst, WORD siz)
2043 inst |= am0 | a0reg;
2052 // cpSAVE/cpRESTORE (68020, 68030)
2054 int m_cprest(WORD inst, WORD siz)
2056 if (activecpu & !(CPU_68020 | CPU_68030))
2057 return error(unsupport);
2059 return m_fpusavrest(inst, siz);
2065 // FSAVE/FRESTORE (68040, 68060)
2067 int m_frestore(WORD inst, WORD siz)
2069 if ((!(activecpu & (CPU_68040 | CPU_68060))) ||
2070 (activefpu&(FPU_68881 | FPU_68882)))
2071 return error(unsupport);
2073 return m_fpusavrest(inst, siz);
2078 // movec (68010, 68020, 68030, 68040, 68060, CPU32)
2080 int m_movec(WORD inst, WORD siz)
2084 if (am0 == DREG || am0 == AREG)
2092 inst = (0 << 15) + (a0reg << 12) + CREGlut[a1reg];
2097 inst = (1 << 15) + (a0reg << 12) + CREGlut[a1reg];
2108 inst = (0 << 15) + (a1reg << 12) + CREGlut[a0reg];
2113 inst = (1 << 15) + (a1reg << 12) + CREGlut[a0reg];
2123 // moves (68010, 68020, 68030, 68040, CPU32)
2125 int m_moves(WORD inst, WORD siz)
2127 if (activecpu & !(CPU_68020 | CPU_68030 | CPU_68040))
2128 return error(unsupport);
2132 else if (siz == SIZL)
2139 inst |= am1 | a1reg;
2141 inst = (a0reg << 12) | (1 << 11) | (0 << 15);
2144 else if (am0 == AREG)
2146 inst |= am1 | a1reg;
2148 inst = (a0reg << 12) | (1 << 11) | (1 << 15);
2155 inst |= am0 | a0reg;
2157 inst = (a1reg << 12) | (0 << 11) | (0 << 15);
2162 inst |= am0 | a0reg;
2164 inst = (a1reg << 12) | (0 << 11) | (1 << 15);
2174 // pflusha (68030, 68040)
2176 int m_pflusha(WORD inst, WORD siz)
2178 if (activecpu == CPU_68030)
2181 inst = (1 << 13) | (1 << 10) | (0 << 5) | 0;
2185 else if (activecpu == CPU_68040)
2187 inst = B16(11110101, 00011000);
2192 return error(unsupport);
2199 // pflush (68030, 68040, 68060)
2201 int m_pflush(WORD inst, WORD siz)
2203 if (activecpu == CPU_68030)
2206 // PFLUSH FC, MASK, < ea >
2214 if (*tok != CONST && *tok != SYMBOL)
2215 return error("function code should be an expression");
2217 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2220 if ((a0exattr & DEFINED) == 0)
2221 return error("function code immediate should be defined");
2224 return error("function code out of range (0-7)");
2226 fc = (uint16_t)a0exval;
2236 fc = (1 << 4) | (*tok++ & 7);
2247 return error(syntax_error);
2251 return error("comma exptected");
2254 return error("mask should be an immediate value");
2256 if (*tok != CONST && *tok != SYMBOL)
2257 return error("mask is supposed to be immediate");
2259 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2262 if ((a0exattr & DEFINED) == 0)
2263 return error("mask immediate value should be defined");
2266 return error("function code out of range (0-7)");
2268 mask = (uint16_t)a0exval << 5;
2274 inst = (1 << 13) | fc | mask | (4 << 10);
2278 else if (*tok == ',')
2280 // PFLUSH FC, MASK, < ea >
2283 if (amode(0) == ERROR)
2287 return error(extra_stuff);
2289 if (am0 == AIND || am0 == ABSW || am0 == ABSL || am0 == ADISP || am0 == ADISP || am0 == AINDEXED || am0 == ABASE || am0 == MEMPOST || am0 == MEMPRE)
2291 inst |= am0 | a0reg;
2293 inst = (1 << 13) | fc | mask | (6 << 10);
2299 return error("unsupported addressing mode");
2303 return error(syntax_error);
2307 else if (activecpu == CPU_68040 || activecpu == CPU_68060)
2311 if (*tok != '(' && tok[2] != ')')
2312 return error(syntax_error);
2314 if (tok[1] < KW_A0 && tok[1] > KW_A7)
2315 return error("expected (An)");
2317 if ((inst & 7) == 7)
2318 // With pflushn/pflush there's no easy way to distinguish between
2319 // the two in 68040 mode. Ideally the opcode bitfields would have
2320 // been hardcoded in 68ktab but there is aliasing between 68030
2321 // and 68040 opcode. So we just set the 3 lower bits to 1 in
2322 // pflushn inside 68ktab and detect it here.
2323 inst = (inst & 0xff8) | 8;
2325 inst |= (tok[1] & 7) | (5 << 8);
2328 return error(extra_stuff);
2333 return error(unsupport);
2340 // pflushan (68040, 68060)
2342 int m_pflushan(WORD inst, WORD siz)
2344 if (activecpu == CPU_68040 || activecpu == CPU_68060)
2354 int m_pflushr(WORD inst, WORD siz)
2358 WORD flg = inst; // Save flag bits
2359 inst &= ~0x3F; // Clobber flag bits in instr
2361 // Install "standard" instr size bits
2367 // OR-in register number
2369 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
2371 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
2377 inst |= am1 | a1reg; // Get ea1 into instr
2378 D_word(inst); // Deposit instr
2380 // Generate ea0 if requested
2384 ea1gen(siz); // Generate ea1
2389 inst |= am0 | a0reg; // Get ea0 into instr
2390 D_word(inst); // Deposit instr
2391 ea0gen(siz); // Generate ea0
2393 // Generate ea1 if requested
2398 D_word(B16(10100000, 00000000));
2404 // ploadr, ploadw (68030)
2406 int m_pload(WORD inst, WORD siz, WORD extension)
2408 // TODO: 68851 support is not added yet.
2409 // None of the ST series of computers had a 68020 + 68851 socket and since
2410 // this is an Atari targetted assembler...
2419 if (a0reg == KW_SFC - KW_SFC)
2421 else if (a0reg == KW_DFC - KW_SFC)
2424 return error("illegal control register specified");
2428 inst = (1 << 3) | a0reg;
2431 if ((a0exattr & DEFINED) == 0)
2432 return error("constant value must be defined");
2435 return error("constant value must be between 0 and 7");
2437 inst = (2 << 3) | (uint16_t)a0exval;
2441 inst |= extension | (1 << 13);
2450 int m_ploadr(WORD inst, WORD siz)
2452 return m_pload(inst, siz, 1 << 9);
2456 int m_ploadw(WORD inst, WORD siz)
2458 return m_pload(inst, siz, 0 << 9);
2463 // pmove (68030/68851)
2465 int m_pmove(WORD inst, WORD siz)
2469 // TODO: 68851 support is not added yet. None of the ST series of
2470 // computers had a 68020 + 68851 socket and since this is an Atari
2471 // targetted assembler.... (same for 68EC030)
2474 inst2 = inst & (1 << 8); // Copy the flush bit over to inst2 in case we're called from m_pmovefd
2475 inst &= ~(1 << 8); // And mask it out
2482 else if (am1 == CREG)
2488 return error("pmove sez: Wut?");
2490 // The instruction is a quad-word (8 byte) operation
2491 // for the CPU root pointer and the supervisor root pointer.
2492 // It is a long-word operation for the translation control register
2493 // and the transparent translation registers(TT0 and TT1).
2494 // It is a word operation for the MMU status register.
2496 if (((reg == (KW_URP - KW_SFC)) || (reg == (KW_SRP - KW_SFC)))
2497 && ((siz != SIZD) && (siz != SIZN)))
2498 return error(siz_error);
2500 if (((reg == (KW_TC - KW_SFC)) || (reg == (KW_TT0 - KW_SFC)) || (reg == (KW_TT1 - KW_SFC)))
2501 && ((siz != SIZL) && (siz != SIZN)))
2502 return error(siz_error);
2504 if ((reg == (KW_MMUSR - KW_SFC)) && ((siz != SIZW) && (siz != SIZN)))
2505 return error(siz_error);
2509 inst |= am1 | a1reg;
2512 else if (am1 == CREG)
2514 inst |= am0 | a0reg;
2518 switch (reg + KW_SFC)
2521 inst2 |= (0 << 10) + (1 << 14); break;
2523 inst2 |= (2 << 10) + (1 << 14); break;
2525 inst2 |= (3 << 10) + (1 << 14); break;
2527 inst2 |= (2 << 10) + (0 << 13); break;
2529 inst2 |= (3 << 10) + (0 << 13); break;
2532 inst2 |= (1 << 9) + (3 << 13);
2534 inst2 |= (0 << 9) + (3 << 13);
2537 return error("unsupported register");
2545 else if (am1 == CREG)
2555 int m_pmovefd(WORD inst, WORD siz)
2559 return m_pmove(inst | (1 << 8), siz);
2566 int m_ptrapcc(WORD inst, WORD siz)
2569 // We stash the 5 condition bits inside the opcode in 68ktab (bits 0-4),
2570 // so we need to extract them first and fill in the clobbered bits.
2571 WORD opcode = inst & 0x1F;
2572 inst = (inst & 0xFFE0) | (0x18);
2581 else if (siz == SIZL)
2588 else if (siz == SIZN)
2600 // ptestr, ptestw (68030, 68040)
2601 // TODO See comment on m_pmove about 68851 support
2602 // TODO quite a good chunk of the 030 code is copied from m_pload, perhaps merge these somehow?
2604 int m_ptest(WORD inst, WORD siz, WORD extension)
2608 if (activecpu != CPU_68030 && activecpu != CPU_68040)
2609 return error(unsupport);
2611 if (activecpu == CPU_68030)
2619 if (a0reg == KW_SFC - KW_SFC)
2621 else if (a0reg == KW_DFC - KW_SFC)
2624 return error("illegal control register specified");
2627 extension |= (1 << 3) | a0reg;
2630 if ((a0exattr & DEFINED) == 0)
2631 return error("constant value must be defined");
2634 return error("constant value must be between 0 and 7");
2636 extension |= (2 << 3) | (uint16_t)a0exval;
2640 // Operand 3 must be an immediate
2644 return error("ptest level must be immediate");
2646 // Let's be a bit inflexible here and demand that this
2647 // is fully defined at this stage. Otherwise we'd have
2648 // to arrange for a bitfield fixup, which would mean
2649 // polluting the bitfields and codebase with special
2650 // cases that might most likely never be used.
2651 // So if anyone gets bit by this: sorry for being a butt!
2652 if (abs_expr(&eval) != OK)
2653 return OK; // We're returning OK because error() has already been called and error count has been increased
2656 return error("ptest level must be between 0 and 7");
2658 extension |= eval << 10;
2660 // Operand 4 is optional and must be an address register
2666 if ((*tok >= KW_A0) && (*tok <= KW_A7))
2668 extension |= (1 << 8) | ((*tok++ & 7) << 4);
2672 return error("fourth parameter must be an address register");
2682 return error("Not implemented yet.");
2687 int m_ptestr(WORD inst, WORD siz)
2689 return m_ptest(inst, siz, (1 << 15) | (0 << 9));
2692 int m_ptestw(WORD inst, WORD siz)
2694 return m_ptest(inst, siz, (1 << 15) | (1 << 9));
2697 //////////////////////////////////////////////////////////////////////////////
2699 // 68020/30/40/60 instructions
2700 // Note: the map of which instructions are allowed on which CPUs came from the
2701 // 68060 manual, section D-1 (page 392 of the PDF). The current implementation
2702 // is missing checks for the EC models which have a simplified FPU.
2704 //////////////////////////////////////////////////////////////////////////////
2707 #define FPU_NOWARN 0
2712 // Generate a FPU opcode
2714 static inline int gen_fpu(WORD inst, WORD siz, WORD opmode, WORD emul)
2716 if (am0 < AM_NONE) // Check first operand for ea or fp - is this right?
2718 inst |= (1 << 9); // Bolt on FPU id
2721 //if (am0 == DREG || am0 == AREG)
2725 inst = 1 << 14; // R/M field (we have ea so have to set this to 1)
2729 case SIZB: inst |= (6 << 10); break;
2730 case SIZW: inst |= (4 << 10); break;
2731 case SIZL: inst |= (0 << 10); break;
2733 case SIZS: inst |= (1 << 10); break;
2734 case SIZD: inst |= (5 << 10); break;
2735 case SIZX: inst |= (2 << 10); break;
2740 warn("This encoding will cause an unimplemented data type exception in the MC68040 to allow emulation in software.");
2744 return error("Something bad happened, possibly, in gen_fpu.");
2748 inst |= (a1reg << 7);
2755 inst |= (1 << 9); // Bolt on FPU id
2759 inst |= (a1reg << 7);
2764 if ((emul & FPU_FPSP) && (activefpu == (FPU_68040 | FPU_68060)))
2765 warn("Instruction is emulated in 68040/060");
2772 // fabs (6888X, 68040FPSP, 68060FPSP)
2774 int m_fabs(WORD inst, WORD siz)
2777 return gen_fpu(inst, siz, B8(00011000), FPU_NOWARN);
2782 // fsabs (68040, 68060)
2784 int m_fsabs(WORD inst, WORD siz)
2787 if (activefpu == FPU_68040)
2788 return gen_fpu(inst, siz, B8(01011000), FPU_NOWARN);
2790 return error("Unsupported in current FPU");
2795 // fdabs (68040, 68060)
2797 int m_fdabs(WORD inst, WORD siz)
2799 if (activefpu == FPU_68040)
2800 return gen_fpu(inst, siz, B8(01011100), FPU_NOWARN);
2802 return error("Unsupported in current FPU");
2807 // facos (6888X, 68040FPSP, 68060FPSP)
2809 int m_facos(WORD inst, WORD siz)
2812 return gen_fpu(inst, siz, B8(00011100), FPU_FPSP);
2817 // fadd (6888X, 68040, 68060)
2819 int m_fadd(WORD inst, WORD siz)
2822 return gen_fpu(inst, siz, B8(00100010), FPU_NOWARN);
2827 // fsadd (68040, 68060)
2829 int m_fsadd(WORD inst, WORD siz)
2831 if (activefpu & (FPU_68040 | FPU_68060))
2832 return gen_fpu(inst, siz, B8(01100010), FPU_NOWARN);
2834 return error("Unsupported in current FPU");
2841 int m_fdadd(WORD inst, WORD siz)
2843 if (activefpu & (FPU_68040 | FPU_68060))
2844 return gen_fpu(inst, siz, B8(01100110), FPU_NOWARN);
2846 return error("Unsupported in current FPU");
2851 // fasin (6888X, 68040FPSP, 68060FPSP)
2853 int m_fasin(WORD inst, WORD siz)
2856 return gen_fpu(inst, siz, B8(00001100), FPU_FPSP);
2861 // fatan (6888X, 68040FPSP, 68060FPSP)
2863 int m_fatan(WORD inst, WORD siz)
2866 return gen_fpu(inst, siz, B8(00001010), FPU_FPSP);
2871 // fatanh (6888X, 68040FPSP, 68060FPSP)
2873 int m_fatanh(WORD inst, WORD siz)
2876 return gen_fpu(inst, siz, B8(00001101), FPU_FPSP);
2881 // fcmp (6888X, 68040, 68060)
2883 int m_fcmp(WORD inst, WORD siz)
2886 return gen_fpu(inst, siz, B8(00111000), FPU_FPSP);
2891 // fcos (6888X, 68040FPSP, 68060FPSP)
2893 int m_fcos(WORD inst, WORD siz)
2896 return gen_fpu(inst, siz, B8(00011101), FPU_FPSP);
2901 // fcosh (6888X, 68040FPSP, 68060FPSP)
2903 int m_fcosh(WORD inst, WORD siz)
2906 return gen_fpu(inst, siz, B8(00011001), FPU_FPSP);
2911 // fdbcc (6888X, 68040, 68060FPSP)
2913 int m_fdbcc(WORD inst, WORD siz)
2916 WORD opcode = inst & 0x3F; // Grab conditional bitfield
2926 if (a1exattr & DEFINED)
2928 if ((a1exattr & TDB) != cursect)
2929 return error(rel_error);
2931 uint32_t v = (uint32_t)a1exval - sloc;
2933 if ((v + 0x8000) > 0x10000)
2934 return error(range_error);
2940 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
2944 if (activefpu == FPU_68060)
2945 warn("Instruction is emulated in 68060");
2952 // fdiv (6888X, 68040, 68060)
2954 int m_fdiv(WORD inst, WORD siz)
2957 return gen_fpu(inst, siz, B8(00100000), FPU_NOWARN);
2962 // fsdiv (68040, 68060)
2964 int m_fsdiv(WORD inst, WORD siz)
2966 if (activefpu & (FPU_68040 | FPU_68060))
2967 return gen_fpu(inst, siz, B8(01100000), FPU_NOWARN);
2969 return error("Unsupported in current FPU");
2974 // fddiv (68040, 68060)
2976 int m_fddiv(WORD inst, WORD siz)
2978 if (activefpu & (FPU_68040 | FPU_68060))
2979 return gen_fpu(inst, siz, B8(01100100), FPU_NOWARN);
2981 return error("Unsupported in current FPU");
2986 // fetox (6888X, 68040FPSP, 68060FPSP)
2988 int m_fetox(WORD inst, WORD siz)
2991 return gen_fpu(inst, siz, B8(00010000), FPU_FPSP);
2996 // fetoxm1 (6888X, 68040FPSP, 68060FPSP)
2998 int m_fetoxm1(WORD inst, WORD siz)
3001 return gen_fpu(inst, siz, B8(00001000), FPU_FPSP);
3006 // fgetexp (6888X, 68040FPSP, 68060FPSP)
3008 int m_fgetexp(WORD inst, WORD siz)
3011 return gen_fpu(inst, siz, B8(00011110), FPU_FPSP);
3016 // fgetman (6888X, 68040FPSP, 68060FPSP)
3018 int m_fgetman(WORD inst, WORD siz)
3021 return gen_fpu(inst, siz, B8(00011111), FPU_FPSP);
3026 // fint (6888X, 68040FPSP, 68060)
3028 int m_fint(WORD inst, WORD siz)
3031 // special case - fint fpx = fint fpx,fpx
3034 if (activefpu == FPU_68040)
3035 warn("Instruction is emulated in 68040");
3037 return gen_fpu(inst, siz, B8(00000001), FPU_NOWARN);
3042 // fintrz (6888X, 68040FPSP, 68060)
3044 int m_fintrz(WORD inst, WORD siz)
3047 // special case - fintrz fpx = fintrz fpx,fpx
3050 if (activefpu == FPU_68040)
3051 warn("Instruction is emulated in 68040");
3053 return gen_fpu(inst, siz, B8(00000011), FPU_NOWARN);
3058 // flog10 (6888X, 68040FPSP, 68060FPSP)
3060 int m_flog10(WORD inst, WORD siz)
3063 return gen_fpu(inst, siz, B8(00010101), FPU_FPSP);
3068 // flog2 (6888X, 68040FPSP, 68060FPSP)
3070 int m_flog2(WORD inst, WORD siz)
3073 return gen_fpu(inst, siz, B8(00010110), FPU_FPSP);
3078 // flogn (6888X, 68040FPSP, 68060FPSP)
3080 int m_flogn(WORD inst, WORD siz)
3083 return gen_fpu(inst, siz, B8(00010100), FPU_FPSP);
3088 // flognp1 (6888X, 68040FPSP, 68060FPSP)
3090 int m_flognp1(WORD inst, WORD siz)
3093 return gen_fpu(inst, siz, B8(00000110), FPU_FPSP);
3098 // fmod (6888X, 68040FPSP, 68060FPSP)
3100 int m_fmod(WORD inst, WORD siz)
3103 return gen_fpu(inst, siz, B8(00100001), FPU_FPSP);
3108 // fmove (6888X, 68040, 68060)
3110 int m_fmove(WORD inst, WORD siz)
3115 if ((am0 == FREG) && (am1 < AM_USP))
3119 inst |= am1 | a1reg;
3128 case SIZB: inst |= (6 << 10); break;
3129 case SIZW: inst |= (4 << 10); break;
3130 case SIZL: inst |= (0 << 10); break;
3132 case SIZS: inst |= (1 << 10); break;
3133 case SIZD: inst |= (5 << 10); break;
3134 case SIZX: inst |= (2 << 10); break;
3135 case SIZP: inst |= (3 << 10);
3136 // In P size we have 2 cases: {#k} where k is immediate
3137 // and {Dn} where Dn=Data register
3142 inst |= bfval1 << 4;
3147 if (bfval1 > 63 && bfval1 < -64)
3148 return error("K-factor must be between -64 and 63");
3150 inst |= bfval1 & 127;
3155 return error("Something bad happened, possibly.");
3159 // Destination specifier
3160 inst |= (a0reg << 7);
3168 else if ((am0 < AM_USP) && (am1 == FREG))
3173 inst |= am0 | a0reg;
3182 case SIZB: inst |= (6 << 10); break;
3183 case SIZW: inst |= (4 << 10); break;
3184 case SIZL: inst |= (0 << 10); break;
3186 case SIZS: inst |= (1 << 10); break;
3187 case SIZD: inst |= (5 << 10); break;
3188 case SIZX: inst |= (2 << 10); break;
3189 case SIZP: inst |= (3 << 10); break;
3191 return error("Something bad happened, possibly.");
3195 // Destination specifier
3196 inst |= (a1reg << 7);
3204 else if ((am0 == FREG) && (am1 == FREG))
3206 // register-to-register
3207 // Essentially ea to register with R/0=0
3216 if (siz != SIZX && siz != SIZN)
3217 return error("Invalid size");
3220 inst |= (a0reg << 10);
3222 // Destination register
3223 inst |= (a1reg << 7);
3233 // fmove (6888X, 68040, 68060)
3235 int m_fmovescr(WORD inst, WORD siz)
3239 // Move Floating-Point System Control Register (FPCR)
3243 if ((am0 == FPSCR) && (am1 < AM_USP))
3245 inst |= am1 | a1reg;
3247 inst = (1 << 13) + (1 << 15);
3253 else if ((am1 == FPSCR) && (am0 < AM_USP))
3255 inst |= am0 | a0reg;
3257 inst = (0 << 13) + (1 << 15);
3264 return error("m_fmovescr says: wut?");
3268 // fsmove/fdmove (68040, 68060)
3270 int m_fsmove(WORD inst, WORD siz)
3272 if (!(activefpu & (FPU_68040 | FPU_68060)))
3273 return error("Unsupported in current FPU");
3275 return gen_fpu(inst, siz, B8(01100100), FPU_FPSP);
3279 int m_fdmove(WORD inst, WORD siz)
3281 if (!(activefpu & (FPU_68040 | FPU_68060)))
3282 return error("Unsupported in current FPU");
3284 return gen_fpu(inst, siz, B8(01100100), FPU_FPSP);
3289 // fmovecr (6888X, 68040FPSP, 68060FPSP)
3291 int m_fmovecr(WORD inst, WORD siz)
3301 if (activefpu == FPU_68040)
3302 warn("Instruction is emulated in 68040/060");
3309 // fmovem (6888X, 68040, 68060FPSP)
3311 int m_fmovem(WORD inst, WORD siz)
3318 if (siz == SIZX || siz == SIZN)
3320 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
3322 // fmovem.x <rlist>,ea
3323 if (fpu_reglist_left(®mask) < 0)
3327 return error("missing comma");
3332 inst |= am0 | a0reg;
3334 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3335 return error("invalid addressing mode");
3338 inst = (1 << 15) | (1 << 14) | (1 << 13) | (0 << 11) | regmask;
3343 else if ((*tok >= KW_D0) && (*tok <= KW_D7))
3346 datareg = (*tok++ & 7) << 10;
3349 return error("missing comma");
3354 inst |= am0 | a0reg;
3356 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3357 return error("invalid addressing mode");
3359 // Quote from the 060 manual:
3360 // "[..] when the processor attempts an FMOVEM.X instruction using a dynamic register list."
3361 if (activefpu == FPU_68060)
3362 warn("Instruction is emulated in 68060");
3365 inst = (1 << 15) | (1 << 14) | (1 << 13) | (1 << 11) | (datareg << 4);
3376 inst |= am0 | a0reg;
3379 return error("missing comma");
3381 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
3383 // fmovem.x ea,<rlist>
3384 if (fpu_reglist_right(®mask) < 0)
3388 inst = (1 << 15) | (1 << 14) | (0 << 13) | (2 << 11) | regmask;
3396 datareg = (*tok++ & 7) << 10;
3398 // Quote from the 060 manual:
3399 // "[..] when the processor attempts an FMOVEM.X instruction using a dynamic register list."
3400 if (activefpu == FPU_68060)
3401 warn("Instruction is emulated in 68060");
3404 inst = (1 << 15) | (1 << 14) | (0 << 13) | (3 << 11) | (datareg << 4);
3411 else if (siz == SIZL)
3413 if ((*tok == KW_FPCR) || (*tok == KW_FPSR) || (*tok == KW_FPIAR))
3415 // fmovem.l <rlist>,ea
3416 regmask = (1 << 15) | (1 << 13);
3417 int no_control_regs = 0;
3420 if (*tok == KW_FPCR)
3422 regmask |= (1 << 12);
3428 if (*tok == KW_FPSR)
3430 regmask |= (1 << 11);
3436 if (*tok == KW_FPIAR)
3438 regmask |= (1 << 10);
3444 if ((*tok == '/') || (*tok == '-'))
3451 return error("missing comma");
3456 // Quote from the 060 manual:
3457 // "[..] when the processor attempts to execute an FMOVEM.L instruction with
3458 // an immediate addressing mode to more than one floating - point
3459 // control register (FPCR, FPSR, FPIAR)[..]"
3460 if (activefpu == FPU_68060)
3461 if (no_control_regs > 1 && am0 == IMMED)
3462 warn("Instruction is emulated in 68060");
3464 inst |= am0 | a0reg;
3471 // fmovem.l ea,<rlist>
3475 inst |= am0 | a0reg;
3478 return error("missing comma");
3480 regmask = (1 << 15) | (0 << 13);
3483 if (*tok == KW_FPCR)
3485 regmask |= (1 << 12);
3490 if (*tok == KW_FPSR)
3492 regmask |= (1 << 11);
3497 if (*tok == KW_FPIAR)
3499 regmask |= (1 << 10);
3504 if ((*tok == '/') || (*tok == '-'))
3511 return error("extra (unexpected) text found");
3513 inst |= am0 | a0reg;
3520 return error("bad size suffix");
3527 // fmul (6888X, 68040, 68060)
3529 int m_fmul(WORD inst, WORD siz)
3532 return gen_fpu(inst, siz, B8(00100011), FPU_NOWARN);
3537 // fsmul (68040, 68060)
3539 int m_fsmul(WORD inst, WORD siz)
3541 if (activefpu & (FPU_68040 | FPU_68060))
3542 return gen_fpu(inst, siz, B8(01100011), FPU_NOWARN);
3544 return error("Unsupported in current FPU");
3551 int m_fdmul(WORD inst, WORD siz)
3553 if (activefpu & (FPU_68040 | FPU_68060))
3554 return gen_fpu(inst, siz, B8(01100111), FPU_NOWARN);
3556 return error("Unsupported in current FPU");
3561 // fneg (6888X, 68040, 68060)
3563 int m_fneg(WORD inst, WORD siz)
3570 return gen_fpu(inst, siz, B8(00011010), FPU_NOWARN);
3573 return gen_fpu(inst, siz, B8(00011010), FPU_NOWARN);
3578 // fsneg (68040, 68060)
3580 int m_fsneg(WORD inst, WORD siz)
3582 if (activefpu & (FPU_68040 | FPU_68060))
3587 return gen_fpu(inst, siz, B8(01011010), FPU_NOWARN);
3590 return gen_fpu(inst, siz, B8(01011010), FPU_NOWARN);
3593 return error("Unsupported in current FPU");
3598 // fdneg (68040, 68060)
3600 int m_fdneg(WORD inst, WORD siz)
3602 if (activefpu & (FPU_68040 | FPU_68060))
3607 return gen_fpu(inst, siz, B8(01011110), FPU_NOWARN);
3610 return gen_fpu(inst, siz, B8(01011110), FPU_NOWARN);
3613 return error("Unsupported in current FPU");
3618 // fnop (6888X, 68040, 68060)
3620 int m_fnop(WORD inst, WORD siz)
3623 return gen_fpu(inst, siz, B8(00000000), FPU_NOWARN);
3628 // frem (6888X, 68040FPSP, 68060FPSP)
3630 int m_frem(WORD inst, WORD siz)
3633 return gen_fpu(inst, siz, B8(00100101), FPU_FPSP);
3638 // fscale (6888X, 68040FPSP, 68060FPSP)
3640 int m_fscale(WORD inst, WORD siz)
3643 return gen_fpu(inst, siz, B8(00100110), FPU_FPSP);
3648 // FScc (6888X, 68040, 68060), cpScc (68851, 68030), PScc (68851)
3649 // TODO: Add check for PScc to ensure 68020+68851 active
3650 // TODO: Add check for cpScc to ensure 68020+68851, 68030
3652 int m_fscc(WORD inst, WORD siz)
3656 // We stash the 5 condition bits inside the opcode in 68ktab (bits 4-0),
3657 // so we need to extract them first and fill in the clobbered bits.
3658 WORD opcode = inst & 0x1F;
3660 inst |= am0 | a0reg;
3664 if (activefpu == FPU_68060)
3665 warn("Instruction is emulated in 68060");
3671 // fsgldiv (6888X, 68040FPSP, 68060FPSP)
3673 int m_fsgldiv(WORD inst, WORD siz)
3676 return gen_fpu(inst, siz, B8(00100100), FPU_FPSP);
3681 // fsglmul (6888X, 68040, 68060FPSP)
3683 int m_fsglmul(WORD inst, WORD siz)
3686 return gen_fpu(inst, siz, B8(00100111), FPU_FPSP);
3691 // fsin (6888X, 68040FPSP, 68060FPSP)
3693 int m_fsin(WORD inst, WORD siz)
3696 return gen_fpu(inst, siz, B8(00001110), FPU_FPSP);
3701 // fsincos (6888X, 68040FPSP, 68060FPSP)
3703 int m_fsincos(WORD inst, WORD siz)
3707 // Swap a1reg, a2reg as a2reg should be stored in the bitfield gen_fpu
3714 if (gen_fpu(inst, siz, B8(00110000), FPU_FPSP) == OK)
3725 // fsinh (6888X, 68040FPSP, 68060FPSP)
3727 int m_fsinh(WORD inst, WORD siz)
3730 return gen_fpu(inst, siz, B8(00000010), FPU_FPSP);
3735 // fsqrt (6888X, 68040, 68060)
3737 int m_fsqrt(WORD inst, WORD siz)
3740 return gen_fpu(inst, siz, B8(00000100), FPU_NOWARN);
3745 // fsfsqrt (68040, 68060)
3747 int m_fsfsqrt(WORD inst, WORD siz)
3749 if (activefpu & (FPU_68040 | FPU_68060))
3750 return gen_fpu(inst, siz, B8(01000001), FPU_NOWARN);
3752 return error("Unsupported in current FPU");
3757 // fdfsqrt (68040, 68060)
3759 int m_fdfsqrt(WORD inst, WORD siz)
3761 if (activefpu & (FPU_68040 | FPU_68060))
3762 return gen_fpu(inst, siz, B8(01000101), FPU_NOWARN);
3764 return error("Unsupported in current FPU");
3769 // fsub (6888X, 68040, 68060)
3771 int m_fsub(WORD inst, WORD siz)
3774 return gen_fpu(inst, siz, B8(00101000), FPU_NOWARN);
3779 // fsfsub (68040, 68060)
3781 int m_fsfsub(WORD inst, WORD siz)
3783 if (activefpu & (FPU_68040 | FPU_68060))
3784 return gen_fpu(inst, siz, B8(01101000), FPU_NOWARN);
3786 return error("Unsupported in current FPU");
3791 // fdfsub (68040, 68060)
3793 int m_fdsub(WORD inst, WORD siz)
3795 if (activefpu & (FPU_68040 | FPU_68060))
3796 return gen_fpu(inst, siz, B8(01101100), FPU_NOWARN);
3798 return error("Unsupported in current FPU");
3803 // ftan (6888X, 68040FPSP, 68060FPSP)
3805 int m_ftan(WORD inst, WORD siz)
3808 return gen_fpu(inst, siz, B8(00001111), FPU_FPSP);
3813 // ftanh (6888X, 68040FPSP, 68060FPSP)
3815 int m_ftanh(WORD inst, WORD siz)
3818 return gen_fpu(inst, siz, B8(00001001), FPU_FPSP);
3823 // ftentox (6888X, 68040FPSP, 68060FPSP)
3825 int m_ftentox(WORD inst, WORD siz)
3828 return gen_fpu(inst, siz, B8(00010010), FPU_FPSP);
3833 // FTRAPcc (6888X, 68040, 68060FPSP)
3835 int m_ftrapcc(WORD inst, WORD siz)
3839 // We stash the 5 condition bits inside the opcode in 68ktab (bits 3-7),
3840 // so we need to extract them first and fill in the clobbered bits.
3841 WORD opcode = (inst >> 3) & 0x1F;
3842 inst = (inst & 0xFF07) | (0xF << 3);
3851 else if (siz == SIZL)
3858 else if (siz == SIZN)
3866 if (activefpu == FPU_68060)
3867 warn("Instruction is emulated in 68060");
3874 // ftst (6888X, 68040, 68060)
3876 int m_ftst(WORD inst, WORD siz)
3879 return gen_fpu(inst, siz, B8(00111010), FPU_NOWARN);
3884 // ftwotox (6888X, 68040FPSP, 68060FPSP)
3886 int m_ftwotox(WORD inst, WORD siz)
3889 return gen_fpu(inst, siz, B8(00010001), FPU_FPSP);
3893 /////////////////////////////////
3895 // 68060 specific instructions //
3897 /////////////////////////////////
3903 int m_lpstop(WORD inst, WORD siz)
3906 D_word(B16(00000001, 11000000));
3908 if (a0exattr & DEFINED)
3914 AddFixup(FU_WORD, sloc, a0expr);
3925 int m_plpa(WORD inst, WORD siz)
3928 inst |= a0reg; // Install register