2 // RMAC - Reboot's Macro Assembler for all Atari computers
3 // MACH.C - Code Generation
4 // Copyright (C) 199x Landon Dyer, 2011-2020 Reboot and Friends
5 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
6 // Source utilised with the kind permission of Landon Dyer
24 int movep = 0; // Global flag to indicate we're generating a movep instruction
26 // Function prototypes
27 int m_unimp(WORD, WORD), m_badmode(WORD, WORD);
28 int m_self(WORD, WORD);
29 int m_abcd(WORD, WORD);
30 int m_reg(WORD, WORD);
31 int m_imm(WORD, WORD);
32 int m_imm8(WORD, WORD);
33 int m_shi(WORD, WORD);
34 int m_shr(WORD, WORD);
35 int m_bitop(WORD, WORD);
36 int m_exg(WORD, WORD);
38 int m_lea(WORD, WORD);
40 int m_dbra(WORD, WORD);
41 int m_link(WORD, WORD);
42 int m_adda(WORD, WORD);
43 int m_addq(WORD, WORD);
44 int m_move(WORD, WORD);
45 int m_moveq(WORD, WORD);
46 int m_usp(WORD, WORD);
47 int m_movep(WORD, WORD);
48 int m_trap(WORD, WORD);
49 int m_movem(WORD, WORD);
50 int m_clra(WORD, WORD);
51 int m_clrd(WORD, WORD);
53 int m_move30(WORD, WORD); // 68020/30/40/60
54 int m_br30(WORD inst, WORD siz);
55 int m_ea030(WORD inst, WORD siz);
56 int m_bfop(WORD inst, WORD siz);
57 int m_callm(WORD inst, WORD siz);
58 int m_cas(WORD inst, WORD siz);
59 int m_cas2(WORD inst, WORD siz);
60 int m_chk2(WORD inst, WORD siz);
61 int m_cmp2(WORD inst, WORD siz);
62 int m_bkpt(WORD inst, WORD siz);
63 int m_cpbcc(WORD inst, WORD siz);
64 int m_cpdbr(WORD inst, WORD siz);
65 int m_muls(WORD inst, WORD siz);
66 int m_move16a(WORD inst, WORD siz);
67 int m_move16b(WORD inst, WORD siz);
68 int m_pack(WORD inst, WORD siz);
69 int m_rtm(WORD inst, WORD siz);
70 int m_rtd(WORD inst, WORD siz);
71 int m_trapcc(WORD inst, WORD siz);
72 int m_cinv(WORD inst, WORD siz);
73 int m_cprest(WORD inst, WORD siz);
74 int m_movec(WORD inst, WORD siz);
75 int m_moves(WORD inst, WORD siz);
76 int m_lpstop(WORD inst, WORD siz);
77 int m_plpa(WORD inst, WORD siz);
80 int m_pbcc(WORD inst, WORD siz);
81 int m_pflusha(WORD inst, WORD siz);
82 int m_pflush(WORD inst, WORD siz);
83 int m_pflushr(WORD inst, WORD siz);
84 int m_pflushan(WORD inst, WORD siz);
85 int m_pload(WORD inst, WORD siz, WORD extension);
86 int m_pmove(WORD inst, WORD siz);
87 int m_pmovefd(WORD inst, WORD siz);
88 int m_ptest(WORD inst, WORD siz, WORD extension);
89 int m_ptestr(WORD inste, WORD siz);
90 int m_ptestw(WORD inste, WORD siz);
91 int m_ptrapcc(WORD inst, WORD siz);
92 int m_ploadr(WORD inst, WORD siz);
93 int m_ploadw(WORD inst, WORD siz);
96 int m_fabs(WORD inst, WORD siz);
97 int m_fbcc(WORD inst, WORD siz);
98 int m_facos(WORD inst, WORD siz);
99 int m_fadd(WORD inst, WORD siz);
100 int m_fasin(WORD inst, WORD siz);
101 int m_fatan(WORD inst, WORD siz);
102 int m_fatanh(WORD inst, WORD siz);
103 int m_fcmp(WORD inst, WORD siz);
104 int m_fcos(WORD inst, WORD siz);
105 int m_fcosh(WORD inst, WORD siz);
106 int m_fdabs(WORD inst, WORD siz);
107 int m_fdadd(WORD inst, WORD siz);
108 int m_fdbcc(WORD inst, WORD siz);
109 int m_fddiv(WORD inst, WORD siz);
110 int m_fdfsqrt(WORD inst, WORD siz);
111 int m_fdiv(WORD inst, WORD siz);
112 int m_fdmove(WORD inst, WORD siz);
113 int m_fdmul(WORD inst, WORD siz);
114 int m_fdneg(WORD inst, WORD siz);
115 int m_fdsub(WORD inst, WORD siz);
116 int m_fetox(WORD inst, WORD siz);
117 int m_fetoxm1(WORD inst, WORD siz);
118 int m_fgetexp(WORD inst, WORD siz);
119 int m_fgetman(WORD inst, WORD siz);
120 int m_fint(WORD inst, WORD siz);
121 int m_fintrz(WORD inst, WORD siz);
122 int m_flog10(WORD inst, WORD siz);
123 int m_flog2(WORD inst, WORD siz);
124 int m_flogn(WORD inst, WORD siz);
125 int m_flognp1(WORD inst, WORD siz);
126 int m_fmod(WORD inst, WORD siz);
127 int m_fmove(WORD inst, WORD siz);
128 int m_fmovescr(WORD inst, WORD siz);
129 int m_fmovecr(WORD inst, WORD siz);
130 int m_fmovem(WORD inst, WORD siz);
131 int m_fmul(WORD inst, WORD siz);
132 int m_fneg(WORD inst, WORD siz);
133 int m_fnop(WORD inst, WORD siz);
134 int m_frem(WORD inst, WORD siz);
135 int m_frestore(WORD inst, WORD siz);
136 int m_fsabs(WORD inst, WORD siz);
137 int m_fsadd(WORD inst, WORD siz);
138 int m_fscc(WORD inst, WORD siz);
139 int m_fscale(WORD inst, WORD siz);
140 int m_fsdiv(WORD inst, WORD siz);
141 int m_fsfsqrt(WORD inst, WORD siz);
142 int m_fsfsub(WORD inst, WORD siz);
143 int m_fsgldiv(WORD inst, WORD siz);
144 int m_fsglmul(WORD inst, WORD siz);
145 int m_fsin(WORD inst, WORD siz);
146 int m_fsincos(WORD inst, WORD siz);
147 int m_fsinh(WORD inst, WORD siz);
148 int m_fsmove(WORD inst, WORD siz);
149 int m_fsmul(WORD inst, WORD siz);
150 int m_fsneg(WORD inst, WORD siz);
151 int m_fsqrt(WORD inst, WORD siz);
152 int m_fsub(WORD inst, WORD siz);
153 int m_ftan(WORD inst, WORD siz);
154 int m_ftanh(WORD inst, WORD siz);
155 int m_ftentox(WORD inst, WORD siz);
156 int m_ftst(WORD inst, WORD siz);
157 int m_ftwotox(WORD inst, WORD siz);
158 int m_ftrapcc(WORD inst, WORD siz);
160 // Common error messages
161 char range_error[] = "expression out of range";
162 char abs_error[] = "illegal absolute expression";
163 char seg_error[] = "bad (section) expression";
164 char rel_error[] = "illegal relative address";
165 char siz_error[] = "bad size specified";
166 char undef_error[] = "undefined expression";
167 char fwd_error[] = "forward or undefined expression";
168 char unsupport[] = "unsupported for selected CPU";
170 // Include code tables
172 { 0xFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000, 0, m_badmode }, // 0
174 { 0, 0L, 0L, 0x0000, 0, m_unimp } // Last entry
177 // Register number << 9
179 0, 1 << 9, 2 << 9, 3 << 9, 4 << 9, 5 << 9, 6 << 9, 7 << 9
182 // SIZB==>00, SIZW==>01, SIZL==>10, SIZN==>01 << 6
186 1<<6, (WORD)-1, // SIZW, n/a
187 2<<6, (WORD)-1, (WORD)-1, (WORD)-1, // SIZL, n/a, n/a, n/a
191 // Byte/word/long size for MOVE instrs
195 0x3000, (WORD)-1, // Word
196 0x2000, (WORD)-1, (WORD)-1, (WORD)-1, // Long
197 0x3000 // Word (SIZN)
200 // Word/long size (0=.w, 1=.l) in bit 8
204 0, (WORD)-1, // SIZW, n/a
205 1<<8, (WORD)-1, (WORD)-1, (WORD)-1, // SIZL, n/a, n/a, n/a
209 // Byte/Word/long size (0=.w, 1=.l) in bit 9
213 1<<9, (WORD)-1, // Word
214 1<<10, (WORD)-1, (WORD)-1, (WORD)-1, // Long
218 // Addressing mode in bits 6..11 (register/mode fields are reversed)
220 00000, 01000, 02000, 03000, 04000, 05000, 06000, 07000,
221 00100, 01100, 02100, 03100, 04100, 05100, 06100, 07100,
222 00200, 01200, 02200, 03200, 04200, 05200, 06200, 07200,
223 00300, 01300, 02300, 03300, 04300, 05300, 06300, 07300,
224 00400, 01400, 02400, 03400, 04400, 05400, 06400, 07400,
225 00500, 01500, 02500, 03500, 04500, 05500, 06500, 07500,
226 00600, 01600, 02600, 03600, 04600, 05600, 06600, 07600,
227 00700, 01700, 02700, 03700, 04700, 05700, 06700, 07700
230 // Control registers lookup table
232 // MC68010/MC68020/MC68030/MC68040/CPU32
233 0x000, // Source Function Code(SFC)
234 0x001, // Destination Function Code(DFC)
235 0x800, // User Stack Pointer(USP)
236 0x801, // Vector Base Register(VBR)
237 // MC68020 / MC68030 / MC68040
238 0x002, // Cache Control Register(CACR)
239 0x802, // Cache Address Register(CAAR) (020/030 only)
240 0x803, // Master Stack Pointer(MSP)
241 0x804, // Interrupt Stack Pointer(ISP)
242 // MC68040 / MC68LC040
243 0x003, // MMU Translation Control Register(TC)
244 0x004, // Instruction Transparent Translation Register 0 (ITT0)
245 0x005, // Instruction Transparent Translation Register 1 (ITT1)
246 0x006, // Data Transparent Translation Register 0 (DTT0)
247 0x007, // Data Transparent Translation Register 1 (DTT1)
248 0x805, // MMU Status Register(MMUSR)
249 0x806, // User Root Pointer(URP)
250 0x807, // Supervisor Root Pointer(SRP)
252 0x004, // Instruction Access Control Register 0 (IACR0)
253 0x005, // Instruction Access Control Register 1 (IACR1)
254 0x006, // Data Access Control Register 0 (DACR1)
255 0x007, // Data Access Control Register 1 (DACR1)
257 0xFFF // CPU Root Pointer (CRP) - There's no movec with CRP in it, this is just a guard entry
262 int m_unimp(WORD unused1, WORD unused2)
264 return (int)error("unimplemented mnemonic");
268 //int m_badmode(void)
269 int m_badmode(WORD unused1, WORD unused2)
271 return (int)error("inappropriate addressing mode");
275 int m_self(WORD inst, WORD usused)
283 // Do one EA in bits 0..5
285 // Bits in `inst' have the following meaning:
287 // Bit zero specifies which ea (ea0 or ea1) to generate in the lower six bits
290 // If bit one is set, the OTHER ea (the one that wasn't generated by bit zero)
291 // is generated after the instruction. Regardless of bit 0's value, ea0 is
292 // always deposited in memory before ea1.
294 // If bit two is set, standard size bits are set in the instr in bits 6 and 7.
296 // If bit four is set, bit three specifies which eaXreg to place in bits 9..11
299 int m_ea(WORD inst, WORD siz)
301 WORD flg = inst; // Save flag bits
302 inst &= ~0x3F; // Clobber flag bits in instr
304 // Install "standard" instr size bits
310 // OR-in register number
312 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
314 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
320 inst |= am1 | a1reg; // Get ea1 into instr
321 D_word(inst); // Deposit instr
323 // Generate ea0 if requested
327 ea1gen(siz); // Generate ea1
332 inst |= am0 | a0reg; // Get ea0 into instr
333 D_word(inst); // Deposit instr
334 ea0gen(siz); // Generate ea0
336 // Generate ea1 if requested
346 // Check if lea x(an),an can be optimised to addq.w #x,an--otherwise fall back
349 int m_lea(WORD inst, WORD siz)
351 if (CHECK_OPTS(OPT_LEA_ADDQ)
352 && ((am0 == ADISP) && (a0reg == a1reg) && (a0exattr & DEFINED))
353 && ((a0exval > 0) && (a0exval <= 8)))
355 inst = B16(01010000, 01001000) | (((uint16_t)a0exval & 7) << 9) | (a0reg);
359 warn("lea size(An),An converted to addq #size,An");
364 return m_ea(inst, siz);
368 int m_ea030(WORD inst, WORD siz)
371 WORD flg = inst; // Save flag bits
372 inst &= ~0x3F; // Clobber flag bits in instr
374 // Install "standard" instr size bits
380 // OR-in register number
383 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
387 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
394 inst |= am1 | a1reg; // Get ea1 into instr
395 D_word(inst); // Deposit instr
397 // Generate ea0 if requested
401 ea1gen(siz); // Generate ea1
407 // We get here if we're doing 020+ addressing and an address
408 // register is used. For example, something like "tst a0". A bit of
409 // a corner case, so kludge it
411 else if (am0 == PCDISP)
412 // Another corner case (possibly!), so kludge ahoy
413 inst |= am0; // Get ea0 into instr
414 else if (am0 == IMMED && am1 == MEMPOST)
416 // Added for addi/andi/cmpi/eori/ori/subi #xx,(bd,An,Dm)
417 inst |= a1reg | AINDEXED;
419 else if (am0 == IMMED)
420 inst |= am0 | a0reg; // Get ea0 into instr
421 else if (am0 == AM_CCR)
423 else if (am0 == AIND)
426 inst |= a0reg; // Get ea0 into instr
427 D_word(inst); // Deposit instr
428 ea0gen(siz); // Generate ea0
430 // Generate ea1 if requested
440 // Dx,Dy nnnnXXXnssnnnYYY If bit 0 of `inst' is set, install size bits in bits
443 int m_abcd(WORD inst, WORD siz)
452 inst |= a0reg | reg_9[a1reg];
462 int m_adda(WORD inst, WORD siz)
464 if ((a0exattr & DEFINED) && (am0 == IMMED))
466 if (CHECK_OPTS(OPT_ADDA_ADDQ))
468 if ((a0exval > 1) && (a0exval <= 8))
470 // Immediate is between 1 and 8 so let's convert to addq
471 return m_addq(B16(01010000, 00000000), siz);
474 warn("adda/suba size(An),An converted to addq/subq #size,An");
478 if (CHECK_OPTS(OPT_ADDA_LEA))
480 if ((a0exval > 8) && ((a0exval + 0x8000) < 0x10000))
482 // Immediate is larger than 8 and word size so let's convert to lea
483 am0 = ADISP; // Change addressing mode
484 a0reg = a1reg; // In ADISP a0reg is used instead of a1reg!
486 if (!(inst & (1 << 14)))
488 // We have a suba #x,AREG so let's negate the value
492 // We're going to rely on +o4 for this, so let's ensure that
493 // it's on, even just for this instruction
495 int temp_flag = optim_flags[OPT_LEA_ADDQ];
496 optim_flags[OPT_LEA_ADDQ] = 1; // Temporarily save switch state
497 return_value = m_lea(B16(01000001, 11011000), SIZW);
498 optim_flags[OPT_LEA_ADDQ] = temp_flag; // Restore switch state
504 inst |= am0 | a0reg | lwsiz_8[siz] | reg_9[a1reg];
506 ea0gen(siz); // Generate EA
513 // If bit 0 of `inst' is 1, install size bits in bits 6..7 of instr.
514 // If bit 1 of `inst' is 1, install a1reg in bits 9..11 of instr.
516 int m_reg(WORD inst, WORD siz)
523 // Install other register (9..11)
524 inst |= reg_9[a1reg];
526 inst &= ~7; // Clear off crufty bits
527 inst |= a0reg; // Install first register
537 int m_imm(WORD inst, WORD siz)
549 int m_imm8(WORD inst, WORD siz)
562 int m_shr(WORD inst, WORD siz)
564 inst |= reg_9[a0reg] | a1reg | siz_6[siz];
574 int m_shi(WORD inst, WORD siz)
576 inst |= a1reg | siz_6[siz];
578 if (a0exattr & DEFINED)
581 return error(range_error);
583 inst |= (a0exval & 7) << 9;
588 AddFixup(FU_QUICK, sloc, a0expr);
597 // {bset, btst, bchg, bclr} -- #immed,ea -- Dn,ea
599 int m_bitop(WORD inst, WORD siz)
601 // Enforce instruction sizes
603 { // X,Dn must be .n or .l
604 if (siz & (SIZB | SIZW))
605 return error(siz_error);
607 else if (siz & (SIZW | SIZL)) // X,ea must be .n or .b
608 return error(siz_error);
610 // Construct instr and EAs
616 ea0gen(SIZB); // Immediate bit number
620 inst |= reg_9[a0reg];
631 int m_dbra(WORD inst, WORD siz)
637 if (a1exattr & DEFINED)
639 if ((a1exattr & TDB) != cursect)
640 return error(rel_error);
642 uint32_t v = (uint32_t)a1exval - sloc;
644 if (v + 0x8000 > 0x10000)
645 return error(range_error);
651 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
662 int m_exg(WORD inst, WORD siz)
668 if (am0 == DREG && am1 == DREG)
670 else if (am0 == AREG && am1 == AREG)
676 m = a1reg; // Get AREG into a1reg
684 inst |= m | reg_9[a0reg] | a1reg;
694 int m_link(WORD inst, WORD siz)
698 // Is this an error condition???
703 inst &= ~((3 << 9) | (1 << 6) | (1 << 4));
715 WORD extra_addressing[16]=
717 0x30, // 0100 (bd,An,Xn)
718 0x30, // 0101 ([bd,An],Xn,od)
719 0x30, // 0102 ([bc,An,Xn],od)
720 0x30, // 0103 (bd,PC,Xn)
721 0x30, // 0104 ([bd,PC],Xn,od)
722 0x30, // 0105 ([bc,PC,Xn],od)
737 // Handle MOVE <C_ALL> <C_ALTDATA>
738 // MOVE <C_ALL> <M_AREG>
740 // Optimize MOVE.L #<smalldata>,D0 to a MOVEQ
742 int m_move(WORD inst, WORD size)
744 // Cast the passed in value to an int
747 // Try to optimize to MOVEQ
748 // N.B.: We can get away with casting the uint64_t to a 32-bit value
749 // because it checks for a SIZL (i.e., a 32-bit value).
750 if (CHECK_OPTS(OPT_MOVEL_MOVEQ)
751 && (siz == SIZL) && (am0 == IMMED) && (am1 == DREG)
752 && ((a0exattr & (TDB | DEFINED)) == DEFINED)
753 && ((uint32_t)a0exval + 0x80 < 0x100))
755 m_moveq((WORD)0x7000, (WORD)0);
758 warn("move.l #size,dx converted to moveq");
762 if ((am0 < ABASE) && (am1 < ABASE)) // 68000 modes
764 inst |= siz_12[siz] | am_6[am1] | reg_9[a1reg] | am0 | a0reg;
772 ea1gen((WORD)siz | 0x8000); // Tell ea1gen we're move ea,ea
776 inst |= siz_12[siz] | reg_9[a1reg] | extra_addressing[am0 - ABASE];
793 // Handle MOVE <C_ALL030> <C_ALTDATA>
794 // MOVE <C_ALL030> <M_AREG>
796 int m_move30(WORD inst, WORD size)
799 inst |= siz_12[siz] | reg_9[a1reg & 7] | a0reg | extra_addressing[am0 - ABASE];
814 // move USP,An -- move An,USP
816 int m_usp(WORD inst, WORD siz)
821 inst |= a1reg; // USP, An
823 inst |= a0reg; // An, USP
834 int m_moveq(WORD inst, WORD siz)
838 // Arrange for future fixup
839 if (!(a0exattr & DEFINED))
841 AddFixup(FU_BYTE | FU_SEXT, sloc + 1, a0expr);
844 else if ((uint32_t)a0exval + 0x100 >= 0x200)
845 return error(range_error);
847 inst |= reg_9[a1reg] | (a0exval & 0xFF);
855 // movep Dn, disp(An) -- movep disp(An), Dn
857 int m_movep(WORD inst, WORD siz)
859 // Tell ea0gen to lay off the 0(a0) optimisations on this one
867 inst |= reg_9[a0reg] | a1reg;
877 inst |= reg_9[a1reg] | a0reg;
894 int m_br(WORD inst, WORD siz)
896 if (a0exattr & DEFINED)
898 if ((a0exattr & TDB) != cursect)
900 //printf("m_br(): a0exattr = %X, cursect = %X, a0exval = %X, sloc = %X\n", a0exattr, cursect, a0exval, sloc);
901 return error(rel_error);
904 uint32_t v = (uint32_t)a0exval - (sloc + 2);
906 // Optimize branch instr. size
909 if (CHECK_OPTS(OPT_BSR_BCC_S) && (v != 0) && ((v + 0x80) < 0x100))
916 warn("Bcc.w/BSR.w converted to .s");
923 if ((v + 0x8000) > 0x10000)
924 return error(range_error);
932 if (siz == SIZB || siz == SIZS)
934 if ((v + 0x80) >= 0x100)
935 return error(range_error);
942 if ((v + 0x8000) >= 0x10000)
943 return error(range_error);
951 else if (siz == SIZN)
954 if (siz == SIZB || siz == SIZS)
957 AddFixup(FU_BBRA | FU_PCREL | FU_SEXT, sloc, a0expr);
958 // So here we have a small issue: this bra.s could be zero offset, but
959 // we can never know. Because unless we know beforehand that the
960 // offset will be zero (i.e. "bra.s +0"), it's going to be a label
961 // below this instruction! We do have an optimisation flag that can
962 // check against this during fixups, but we cannot rely on the state
963 // of the flag after all the file(s) have been processed because its
964 // state might have changed multiple times during file parsing. (Yes,
965 // there's a very low chance that this will ever happen but it's not
966 // zero!). So, we can use the byte that is going to be filled during
967 // fixups to store the state of the optimisation flag and read it
968 // during that stage so each bra.s will have its state stored neatly.
969 // Sleazy? Eh, who cares, like this will ever happen ;)
970 // One final note: we'd better be damn sure that the flag's value is
971 // less than 256 or magical stuff will happen!
972 D_word(inst | optim_flags[OPT_NULL_BRA]);
979 AddFixup(FU_WORD | FU_PCREL | FU_LBRA | FU_ISBRA, sloc, a0expr);
990 int m_addq(WORD inst, WORD siz)
992 inst |= siz_6[siz] | am1 | a1reg;
994 if (a0exattr & DEFINED)
996 if ((a0exval > 8) || (a0exval == 0)) // Range in 1..8
997 return error(range_error);
999 inst |= (a0exval & 7) << 9;
1004 AddFixup(FU_QUICK, sloc, a0expr);
1017 int m_trap(WORD inst, WORD siz)
1021 if (a0exattr & DEFINED)
1024 return error(abs_error);
1027 return error(range_error);
1033 return error(undef_error);
1040 // movem <rlist>,ea -- movem ea,<rlist>
1042 int m_movem(WORD inst, WORD siz)
1050 return error("bad size suffix");
1057 // Handle #<expr>, ea
1060 if (abs_expr(&eval) != OK)
1063 if (eval >= 0x10000L)
1064 return error(range_error);
1070 if ((*tok >= KW_D0) && (*tok <= KW_A7))
1073 if (reglist(&rmask) < 0)
1078 return error("missing comma");
1083 inst |= am0 | a0reg;
1085 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
1086 return error("invalid addressing mode");
1088 // If APREDEC, reverse register mask
1094 for(i=0x8000; i; i>>=1, w>>=1)
1095 rmask = (WORD)((rmask << 1) | (w & 1));
1104 inst |= 0x0400 | am0 | a0reg;
1107 return error("missing comma");
1110 return error("missing register list");
1117 if (abs_expr(&eval) != OK)
1120 if (eval >= 0x10000)
1121 return error(range_error);
1125 else if (reglist(&rmask) < 0)
1128 if (!(amsktab[am0] & (C_CTRL | M_APOSTINC)))
1129 return error("invalid addressing mode");
1141 // CLR.x An ==> SUBA.x An,An
1143 int m_clra(WORD inst, WORD siz)
1145 inst |= a0reg | reg_9[a0reg] | lwsiz_8[siz];
1153 // CLR.L Dn ==> CLR.L An or MOVEQ #0,Dx
1155 int m_clrd(WORD inst, WORD siz)
1157 if (!CHECK_OPTS(OPT_CLR_DX))
1160 inst = (a0reg << 9) | B16(01110000, 00000000);
1168 ////////////////////////////////////////
1170 // 68020/30/40/60 instructions
1172 ////////////////////////////////////////
1177 int m_br30(WORD inst, WORD siz)
1179 if (a0exattr & DEFINED)
1181 if ((a0exattr & TDB) != cursect)
1182 return error(rel_error);
1184 uint32_t v = (uint32_t)a0exval - (sloc + 2);
1193 AddFixup(FU_LONG | FU_PCREL | FU_SEXT, sloc, a0expr);
1201 // bfchg, bfclr, bfexts, bfextu, bfffo, bfins, bfset
1202 // (68020, 68030, 68040)
1204 int m_bfop(WORD inst, WORD siz)
1206 if ((bfval1 > 31) || (bfval1 < 0))
1207 return error("bfxxx offset: immediate value must be between 0 and 31");
1209 // First instruction word - just the opcode and first EA
1210 // Note: both am1 is ORed because solely of bfins - maybe it's a good idea
1211 // to make a dedicated function for it?
1218 if (bfval2 > 31 || bfval2 < 0)
1219 return error("bfxxx width: immediate value must be between 0 and 31");
1221 // For Dw both immediate and register number are stuffed
1222 // into the same field O_o
1223 bfparam2 = (bfval2 << 0);
1227 bfparam1 = (bfval1 << 6);
1229 bfparam1 = bfval1 << 12;
1231 //D_word((inst | am0 | a0reg | am1 | a1reg));
1232 if (inst == B16(11101111, 11000000))
1234 // bfins special case
1235 D_word((inst | am1 | a1reg));
1239 D_word((inst | am0 | a0reg));
1242 ea0gen(siz); // Generate EA
1244 // Second instruction word - Dest register (if exists), Do, Offset, Dw, Width
1245 if (inst == B16(11101111, 11000000))
1247 // bfins special case
1248 inst = bfparam1 | bfparam2;
1251 inst |= a0reg << 12;
1257 inst = bfparam1 | bfparam2;
1263 inst |= a1reg << 12;
1273 // bkpt (68EC000, 68010, 68020, 68030, 68040, CPU32)
1275 int m_bkpt(WORD inst, WORD siz)
1279 if (a0exattr & DEFINED)
1282 return error(abs_error);
1285 return error(range_error);
1291 return error(undef_error);
1300 int m_callm(WORD inst, WORD siz)
1307 if (a0exattr & DEFINED)
1310 return error(abs_error);
1313 return error(range_error);
1315 inst = (uint16_t)a0exval;
1319 return error(undef_error);
1329 // cas (68020, 68030, 68040)
1331 int m_cas(WORD inst, WORD siz)
1337 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1338 return error(unsupport);
1353 return error("bad size suffix");
1358 if ((*tok < KW_D0) && (*tok > KW_D7))
1359 return error("CAS accepts only data registers");
1361 inst2 = (*tok++) & 7;
1364 return error("missing comma");
1367 if ((*tok < KW_D0) && (*tok > KW_D7))
1368 return error("CAS accepts only data registers");
1370 inst2 |= ((*tok++) & 7) << 6;
1373 return error("missing comma");
1376 if ((modes = amode(1)) < 0)
1380 return error("too many ea fields");
1383 return error("extra (unexpected) text found");
1385 // Reject invalid ea modes
1386 amsk = amsktab[am0];
1388 if ((amsk & (M_AIND | M_APOSTINC | M_APREDEC | M_ADISP | M_AINDEXED | M_ABSW | M_ABSL | M_ABASE | M_MEMPOST | M_MEMPRE)) == 0)
1389 return error("unsupported addressing mode");
1391 inst |= am0 | a0reg;
1401 // cas2 (68020, 68030, 68040)
1403 int m_cas2(WORD inst, WORD siz)
1407 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1408 return error(unsupport);
1423 return error("bad size suffix");
1428 if ((*tok < KW_D0) && (*tok > KW_D7))
1429 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1431 inst2 = (*tok++) & 7;
1434 return error("missing colon");
1437 if ((*tok < KW_D0) && (*tok > KW_D7))
1438 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1440 inst3 = (*tok++) & 7;
1443 return error("missing comma");
1446 if ((*tok < KW_D0) && (*tok > KW_D7))
1447 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1449 inst2 |= ((*tok++) & 7) << 6;
1452 return error("missing colon");
1455 if ((*tok < KW_D0) && (*tok > KW_D7))
1456 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1458 inst3 |= ((*tok++) & 7) << 6;
1461 return error("missing comma");
1465 return error("missing (");
1466 if ((*tok >= KW_D0) && (*tok <= KW_D7))
1467 inst2 |= (((*tok++) & 7) << 12) | (0 << 15);
1468 else if ((*tok >= KW_A0) && (*tok <= KW_A7))
1469 inst2 |= (((*tok++) & 7) << 12) | (1 << 15);
1471 return error("CAS accepts either data or address registers for Rn1:Rn2 pair");
1474 return error("missing (");
1477 return error("missing colon");
1481 return error("missing (");
1482 if ((*tok >= KW_D0) && (*tok <= KW_D7))
1483 inst3 |= (((*tok++) & 7) << 12) | (0 << 15);
1484 else if ((*tok >= KW_A0) && (*tok <= KW_A7))
1485 inst3 |= (((*tok++) & 7) << 12) | (1 << 15);
1487 return error("CAS accepts either data or address registers for Rn1:Rn2 pair");
1490 return error("missing (");
1493 return error("extra (unexpected) text found");
1504 // cmp2 (68020, 68030, 68040, CPU32)
1506 int m_cmp2(WORD inst, WORD siz)
1508 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1509 return error(unsupport);
1511 switch (siz & 0x000F)
1525 WORD flg = inst; // Save flag bits
1526 inst &= ~0x3F; // Clobber flag bits in instr
1528 // Install "standard" instr size bits
1534 // OR-in register number
1536 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1538 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1544 inst |= am1 | a1reg; // Get ea1 into instr
1545 D_word(inst); // Deposit instr
1547 // Generate ea0 if requested
1551 ea1gen(siz); // Generate ea1
1556 inst |= am0 | a0reg; // Get ea0 into instr
1557 D_word(inst); // Deposit instr
1558 ea0gen(siz); // Generate ea0
1560 // Generate ea1 if requested
1565 // If we're called from chk2 then bit 11 of size will be set. This is just
1566 // a dumb mechanism to pass this, required by the extension word. (You might
1567 // have noticed the siz & 15 thing above!)
1568 inst = (a1reg << 12) | (siz & (1 << 11));
1580 // chk2 (68020, 68030, 68040, CPU32)
1582 int m_chk2(WORD inst, WORD siz)
1584 return m_cmp2(inst, siz | (1 << 11));
1589 // cpbcc(68020, 68030, 68040 (FBcc), 68060 (FBcc)), pbcc (68851)
1591 int m_fpbr(WORD inst, WORD siz)
1594 if (a0exattr & DEFINED)
1596 if ((a0exattr & TDB) != cursect)
1597 return error(rel_error);
1599 uint32_t v = (uint32_t)a0exval - (sloc + 2);
1601 // Optimize branch instr. size
1604 if ((v != 0) && ((v + 0x8000) < 0x10000))
1614 if ((v + 0x8000) >= 0x10000)
1615 return error(range_error);
1623 else if (siz == SIZN)
1630 AddFixup(FU_LONG | FU_PCREL | FU_SEXT, sloc, a0expr);
1638 AddFixup(FU_WORD | FU_PCREL | FU_SEXT, sloc, a0expr);
1647 // cpbcc(68020, 68030, 68040 (FBcc), 68060 (FBcc))
1649 int m_cpbcc(WORD inst, WORD siz)
1651 if (!(activecpu & (CPU_68020 | CPU_68030)))
1652 return error(unsupport);
1654 return m_fpbr(inst, siz);
1659 // fbcc(6808X, 68040, 68060)
1661 int m_fbcc(WORD inst, WORD siz)
1664 return m_fpbr(inst, siz);
1669 // pbcc(68851 but let's assume 68020 only)
1671 int m_pbcc(WORD inst, WORD siz)
1674 return m_fpbr(inst, siz);
1679 // cpdbcc(68020, 68030)
1681 int m_cpdbr(WORD inst, WORD siz)
1686 WORD condition = inst & 0x1F; // Grab condition sneakily placed in the lower 5 bits of inst
1687 inst &= 0xFFE0; // And then mask them out - you ain't seen me, roit?
1689 inst |= (1 << 9); // Bolt on FPU id
1696 if (a1exattr & DEFINED)
1698 if ((a1exattr & TDB) != cursect)
1699 return error(rel_error);
1701 v = (uint32_t)a1exval - sloc;
1703 if (v + 0x8000 > 0x10000)
1704 return error(range_error);
1710 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
1720 // muls.l / divs.l / divu.l / mulu.l (68020+)
1722 int m_muls(WORD inst, WORD siz)
1724 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1725 return error(unsupport);
1727 WORD flg = inst; // Save flag bits
1728 inst &= ~0x33F; // Clobber flag and extension bits in instr
1730 // Install "standard" instr size bits
1736 // OR-in register number
1738 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1740 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1743 // Regarding extension word: bit 11 is signed/unsigned selector
1744 // bit 10 is 32/64 bit selector
1745 // Both of these are packed in bits 9 and 8 of the instruction
1746 // field in 68ktab. Extra compilcations arise from the fact we
1747 // have to distinguish between divu/s.l Dn,Dm (which is encoded
1748 // as divu/s.l Dn,Dm:Dm) and divu/s.l Dn,Dm:Dx - the first is
1749 // 32 bit while the second 64 bit
1754 inst |= am1 | a1reg; // Get ea1 into instr
1755 D_word(inst); // Deposit instr
1759 inst = a1reg + (a2reg << 12) + ((flg & 0x200) << 2);
1761 inst = a1reg + (a2reg << 12) + ((flg & 0x300) << 2);
1765 // Generate ea0 if requested
1769 ea1gen(siz); // Generate ea1
1776 inst |= am0 | a0reg; // Get ea0 into instr
1777 D_word(inst); // Deposit instr
1781 inst = a1reg + (a2reg << 12) + ((flg & 0x200) << 2);
1783 inst = a1reg + (a2reg << 12) + ((flg & 0x300) << 2);
1787 ea0gen(siz); // Generate ea0
1789 // Generate ea1 if requested
1799 // move16 (ax)+,(ay)+
1801 int m_move16a(WORD inst, WORD siz)
1803 if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1804 return error(unsupport);
1808 inst = (1 << 15) + (a1reg << 12);
1816 // move16 with absolute address
1818 int m_move16b(WORD inst, WORD siz)
1820 if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1821 return error(unsupport);
1827 if (am0 == APOSTINC)
1830 return error("Wasn't this suppose to call m_move16a???");
1833 // move16 (ax)+,(xxx).L
1838 else if (am0 == ABSL)
1842 // move16 (xxx).L,(ax)+
1848 // move16 (xxx).L,(ax)
1853 else if (am0 == AIND)
1855 // move16 (ax),(xxx).L
1868 // pack/unpack (68020/68030/68040)
1870 int m_pack(WORD inst, WORD siz)
1875 return error("bad size suffix");
1877 if (*tok >= KW_D0 && *tok <= KW_D7)
1879 // Dx,Dy,#<adjustment>
1880 inst |= (0 << 3); // R/M
1881 inst |= (*tok++ & 7);
1883 if (*tok != ',' && tok[2] != ',')
1884 return error("missing comma");
1886 if (tok[1] < KW_D0 && tok[1] > KW_D7)
1887 return error(syntax_error);
1889 inst |= ((tok[1] & 7)<<9);
1892 // Fall through for adjustment (common in both valid cases)
1894 else if (*tok == '-')
1896 // -(Ax),-(Ay),#<adjustment>
1897 inst |= (1 << 3); // R/M
1898 tok++; // eat the minus
1900 if ((*tok != '(') && (tok[2]!=')') && (tok[3]!=',') && (tok[4] != '-') && (tok[5] != '(') && (tok[7] != ')') && (tok[8] != ','))
1901 return error(syntax_error);
1903 if (tok[1] < KW_A0 && tok[1] > KW_A7)
1904 return error(syntax_error);
1906 if (tok[5] < KW_A0 && tok[6] > KW_A7)
1907 return error(syntax_error);
1909 inst |= ((tok[1] & 7) << 0);
1910 inst |= ((tok[6] & 7) << 9);
1913 // Fall through for adjustment (common in both valid cases)
1916 return error("invalid syntax");
1918 if ((*tok != CONST) && (*tok != SYMBOL) && (*tok != '-'))
1919 return error(syntax_error);
1921 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
1924 if ((a0exattr & DEFINED) == 0)
1925 return error(undef_error);
1927 if (a0exval + 0x8000 > 0x10000)
1931 return error(extra_stuff);
1933 D_word((a0exval & 0xFFFF));
1942 int m_rtm(WORD inst, WORD siz)
1950 else if (am0 == AREG)
1952 inst |= (1 << 3) + a0reg;
1955 return error("rtm only allows data or address registers.");
1966 int m_rtd(WORD inst, WORD siz)
1970 if (a0exattr & DEFINED)
1973 return error(abs_error);
1975 if ((a0exval + 0x8000) <= 0x7FFF)
1976 return error(range_error);
1982 return error(undef_error);
1991 int m_trapcc(WORD inst, WORD siz)
1999 else if (am0 == IMMED)
2003 if (a0exval < 0x10000)
2010 return error("Immediate value too big");
2020 return error("Invalid parameter for trapcc");
2027 // cinvl/p/a (68040/68060)
2029 int m_cinv(WORD inst, WORD siz)
2034 inst |= (0 << 6) | (a1reg);
2038 inst |= (2 << 6) | (a1reg);
2041 inst |= (1 << 6) | (a1reg);
2044 inst |= (3 << 6) | (a1reg);
2053 int m_fpusavrest(WORD inst, WORD siz)
2055 inst |= am0 | a0reg;
2064 // cpSAVE/cpRESTORE (68020, 68030)
2066 int m_cprest(WORD inst, WORD siz)
2068 if (activecpu & !(CPU_68020 | CPU_68030))
2069 return error(unsupport);
2071 return m_fpusavrest(inst, siz);
2077 // FSAVE/FRESTORE (68040, 68060)
2079 int m_frestore(WORD inst, WORD siz)
2081 if ((!(activecpu & (CPU_68040 | CPU_68060))) ||
2082 (activefpu&(FPU_68881 | FPU_68882)))
2083 return error(unsupport);
2085 return m_fpusavrest(inst, siz);
2090 // movec (68010, 68020, 68030, 68040, 68060, CPU32)
2092 int m_movec(WORD inst, WORD siz)
2096 if (am0 == DREG || am0 == AREG)
2104 inst = (0 << 15) + (a0reg << 12) + CREGlut[a1reg];
2109 inst = (1 << 15) + (a0reg << 12) + CREGlut[a1reg];
2120 inst = (0 << 15) + (a1reg << 12) + CREGlut[a0reg];
2125 inst = (1 << 15) + (a1reg << 12) + CREGlut[a0reg];
2135 // moves (68010, 68020, 68030, 68040, CPU32)
2137 int m_moves(WORD inst, WORD siz)
2139 if (activecpu & !(CPU_68020 | CPU_68030 | CPU_68040))
2140 return error(unsupport);
2144 else if (siz == SIZL)
2151 inst |= am1 | a1reg;
2153 inst = (a0reg << 12) | (1 << 11) | (0 << 15);
2156 else if (am0 == AREG)
2158 inst |= am1 | a1reg;
2160 inst = (a0reg << 12) | (1 << 11) | (1 << 15);
2167 inst |= am0 | a0reg;
2169 inst = (a1reg << 12) | (0 << 11) | (0 << 15);
2174 inst |= am0 | a0reg;
2176 inst = (a1reg << 12) | (0 << 11) | (1 << 15);
2186 // pflusha (68030, 68040)
2188 int m_pflusha(WORD inst, WORD siz)
2190 if (activecpu == CPU_68030)
2193 inst = (1 << 13) | (1 << 10) | (0 << 5) | 0;
2197 else if (activecpu == CPU_68040)
2199 inst = B16(11110101, 00011000);
2204 return error(unsupport);
2211 // pflush (68030, 68040, 68060)
2213 int m_pflush(WORD inst, WORD siz)
2215 if (activecpu == CPU_68030)
2218 // PFLUSH FC, MASK, < ea >
2226 if (*tok != CONST && *tok != SYMBOL)
2227 return error("function code should be an expression");
2229 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2232 if ((a0exattr & DEFINED) == 0)
2233 return error("function code immediate should be defined");
2236 return error("function code out of range (0-7)");
2238 fc = (uint16_t)a0exval;
2248 fc = (1 << 4) | (*tok++ & 7);
2259 return error(syntax_error);
2263 return error("comma exptected");
2266 return error("mask should be an immediate value");
2268 if (*tok != CONST && *tok != SYMBOL)
2269 return error("mask is supposed to be immediate");
2271 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2274 if ((a0exattr & DEFINED) == 0)
2275 return error("mask immediate value should be defined");
2278 return error("function code out of range (0-7)");
2280 mask = (uint16_t)a0exval << 5;
2286 inst = (1 << 13) | fc | mask | (4 << 10);
2290 else if (*tok == ',')
2292 // PFLUSH FC, MASK, < ea >
2295 if (amode(0) == ERROR)
2299 return error(extra_stuff);
2301 if (am0 == AIND || am0 == ABSW || am0 == ABSL || am0 == ADISP || am0 == ADISP || am0 == AINDEXED || am0 == ABASE || am0 == MEMPOST || am0 == MEMPRE)
2303 inst |= am0 | a0reg;
2305 inst = (1 << 13) | fc | mask | (6 << 10);
2311 return error("unsupported addressing mode");
2315 return error(syntax_error);
2319 else if (activecpu == CPU_68040 || activecpu == CPU_68060)
2323 if (*tok != '(' && tok[2] != ')')
2324 return error(syntax_error);
2326 if (tok[1] < KW_A0 && tok[1] > KW_A7)
2327 return error("expected (An)");
2329 if ((inst & 7) == 7)
2330 // With pflushn/pflush there's no easy way to distinguish between
2331 // the two in 68040 mode. Ideally the opcode bitfields would have
2332 // been hardcoded in 68ktab but there is aliasing between 68030
2333 // and 68040 opcode. So we just set the 3 lower bits to 1 in
2334 // pflushn inside 68ktab and detect it here.
2335 inst = (inst & 0xff8) | 8;
2337 inst |= (tok[1] & 7) | (5 << 8);
2340 return error(extra_stuff);
2345 return error(unsupport);
2352 // pflushan (68040, 68060)
2354 int m_pflushan(WORD inst, WORD siz)
2356 if (activecpu == CPU_68040 || activecpu == CPU_68060)
2366 int m_pflushr(WORD inst, WORD siz)
2370 WORD flg = inst; // Save flag bits
2371 inst &= ~0x3F; // Clobber flag bits in instr
2373 // Install "standard" instr size bits
2379 // OR-in register number
2381 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
2383 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
2389 inst |= am1 | a1reg; // Get ea1 into instr
2390 D_word(inst); // Deposit instr
2392 // Generate ea0 if requested
2396 ea1gen(siz); // Generate ea1
2401 inst |= am0 | a0reg; // Get ea0 into instr
2402 D_word(inst); // Deposit instr
2403 ea0gen(siz); // Generate ea0
2405 // Generate ea1 if requested
2410 D_word(B16(10100000, 00000000));
2416 // ploadr, ploadw (68030)
2418 int m_pload(WORD inst, WORD siz, WORD extension)
2420 // TODO: 68851 support is not added yet.
2421 // None of the ST series of computers had a 68020 + 68851 socket and since
2422 // this is an Atari targetted assembler...
2431 if (a0reg == KW_SFC - KW_SFC)
2433 else if (a0reg == KW_DFC - KW_SFC)
2436 return error("illegal control register specified");
2440 inst = (1 << 3) | a0reg;
2443 if ((a0exattr & DEFINED) == 0)
2444 return error("constant value must be defined");
2447 return error("constant value must be between 0 and 7");
2449 inst = (2 << 3) | (uint16_t)a0exval;
2453 inst |= extension | (1 << 13);
2462 int m_ploadr(WORD inst, WORD siz)
2464 return m_pload(inst, siz, 1 << 9);
2468 int m_ploadw(WORD inst, WORD siz)
2470 return m_pload(inst, siz, 0 << 9);
2475 // pmove (68030/68851)
2477 int m_pmove(WORD inst, WORD siz)
2481 // TODO: 68851 support is not added yet. None of the ST series of
2482 // computers had a 68020 + 68851 socket and since this is an Atari
2483 // targetted assembler.... (same for 68EC030)
2486 inst2 = inst & (1 << 8); // Copy the flush bit over to inst2 in case we're called from m_pmovefd
2487 inst &= ~(1 << 8); // And mask it out
2494 else if (am1 == CREG)
2500 return error("pmove sez: Wut?");
2502 // The instruction is a quad-word (8 byte) operation
2503 // for the CPU root pointer and the supervisor root pointer.
2504 // It is a long-word operation for the translation control register
2505 // and the transparent translation registers(TT0 and TT1).
2506 // It is a word operation for the MMU status register.
2508 if (((reg == (KW_URP - KW_SFC)) || (reg == (KW_SRP - KW_SFC)))
2509 && ((siz != SIZD) && (siz != SIZN)))
2510 return error(siz_error);
2512 if (((reg == (KW_TC - KW_SFC)) || (reg == (KW_TT0 - KW_SFC)) || (reg == (KW_TT1 - KW_SFC)))
2513 && ((siz != SIZL) && (siz != SIZN)))
2514 return error(siz_error);
2516 if ((reg == (KW_MMUSR - KW_SFC)) && ((siz != SIZW) && (siz != SIZN)))
2517 return error(siz_error);
2521 inst |= am1 | a1reg;
2524 else if (am1 == CREG)
2526 inst |= am0 | a0reg;
2530 switch (reg + KW_SFC)
2533 inst2 |= (0 << 10) + (1 << 14); break;
2535 inst2 |= (2 << 10) + (1 << 14); break;
2537 inst2 |= (3 << 10) + (1 << 14); break;
2539 inst2 |= (2 << 10) + (0 << 13); break;
2541 inst2 |= (3 << 10) + (0 << 13); break;
2544 inst2 |= (1 << 9) + (3 << 13);
2546 inst2 |= (0 << 9) + (3 << 13);
2549 return error("unsupported register");
2557 else if (am1 == CREG)
2567 int m_pmovefd(WORD inst, WORD siz)
2571 return m_pmove(inst | (1 << 8), siz);
2578 int m_ptrapcc(WORD inst, WORD siz)
2581 // We stash the 5 condition bits inside the opcode in 68ktab (bits 0-4),
2582 // so we need to extract them first and fill in the clobbered bits.
2583 WORD opcode = inst & 0x1F;
2584 inst = (inst & 0xFFE0) | (0x18);
2593 else if (siz == SIZL)
2600 else if (siz == SIZN)
2612 // ptestr, ptestw (68030, 68040)
2613 // TODO See comment on m_pmove about 68851 support
2614 // TODO quite a good chunk of the 030 code is copied from m_pload, perhaps merge these somehow?
2616 int m_ptest(WORD inst, WORD siz, WORD extension)
2620 if (activecpu != CPU_68030 && activecpu != CPU_68040)
2621 return error(unsupport);
2623 if (activecpu == CPU_68030)
2631 if (a0reg == KW_SFC - KW_SFC)
2633 else if (a0reg == KW_DFC - KW_SFC)
2636 return error("illegal control register specified");
2639 extension |= (1 << 3) | a0reg;
2642 if ((a0exattr & DEFINED) == 0)
2643 return error("constant value must be defined");
2646 return error("constant value must be between 0 and 7");
2648 extension |= (2 << 3) | (uint16_t)a0exval;
2652 // Operand 3 must be an immediate
2656 return error("ptest level must be immediate");
2658 // Let's be a bit inflexible here and demand that this
2659 // is fully defined at this stage. Otherwise we'd have
2660 // to arrange for a bitfield fixup, which would mean
2661 // polluting the bitfields and codebase with special
2662 // cases that might most likely never be used.
2663 // So if anyone gets bit by this: sorry for being a butt!
2664 if (abs_expr(&eval) != OK)
2665 return OK; // We're returning OK because error() has already been called and error count has been increased
2668 return error("ptest level must be between 0 and 7");
2670 extension |= eval << 10;
2672 // Operand 4 is optional and must be an address register
2678 if ((*tok >= KW_A0) && (*tok <= KW_A7))
2680 extension |= (1 << 8) | ((*tok++ & 7) << 4);
2684 return error("fourth parameter must be an address register");
2694 return error("Not implemented yet.");
2699 int m_ptestr(WORD inst, WORD siz)
2701 return m_ptest(inst, siz, (1 << 15) | (0 << 9));
2704 int m_ptestw(WORD inst, WORD siz)
2706 return m_ptest(inst, siz, (1 << 15) | (1 << 9));
2709 //////////////////////////////////////////////////////////////////////////////
2711 // 68020/30/40/60 instructions
2712 // Note: the map of which instructions are allowed on which CPUs came from the
2713 // 68060 manual, section D-1 (page 392 of the PDF). The current implementation
2714 // is missing checks for the EC models which have a simplified FPU.
2716 //////////////////////////////////////////////////////////////////////////////
2719 #define FPU_NOWARN 0
2724 // Generate a FPU opcode
2726 static inline int gen_fpu(WORD inst, WORD siz, WORD opmode, WORD emul)
2728 if (am0 < AM_NONE) // Check first operand for ea or fp - is this right?
2730 inst |= (1 << 9); // Bolt on FPU id
2733 //if (am0 == DREG || am0 == AREG)
2737 inst = 1 << 14; // R/M field (we have ea so have to set this to 1)
2741 case SIZB: inst |= (6 << 10); break;
2742 case SIZW: inst |= (4 << 10); break;
2743 case SIZL: inst |= (0 << 10); break;
2745 case SIZS: inst |= (1 << 10); break;
2746 case SIZD: inst |= (5 << 10); break;
2747 case SIZX: inst |= (2 << 10); break;
2752 warn("This encoding will cause an unimplemented data type exception in the MC68040 to allow emulation in software.");
2756 return error("Something bad happened, possibly, in gen_fpu.");
2760 inst |= (a1reg << 7);
2767 inst |= (1 << 9); // Bolt on FPU id
2771 inst |= (a1reg << 7);
2776 if ((emul & FPU_FPSP) && (activefpu == (FPU_68040 | FPU_68060)))
2777 warn("Instruction is emulated in 68040/060");
2784 // fabs (6888X, 68040FPSP, 68060FPSP)
2786 int m_fabs(WORD inst, WORD siz)
2789 return gen_fpu(inst, siz, B8(00011000), FPU_NOWARN);
2794 // fsabs (68040, 68060)
2796 int m_fsabs(WORD inst, WORD siz)
2799 if (activefpu == FPU_68040)
2800 return gen_fpu(inst, siz, B8(01011000), FPU_NOWARN);
2802 return error("Unsupported in current FPU");
2807 // fdabs (68040, 68060)
2809 int m_fdabs(WORD inst, WORD siz)
2811 if (activefpu == FPU_68040)
2812 return gen_fpu(inst, siz, B8(01011100), FPU_NOWARN);
2814 return error("Unsupported in current FPU");
2819 // facos (6888X, 68040FPSP, 68060FPSP)
2821 int m_facos(WORD inst, WORD siz)
2824 return gen_fpu(inst, siz, B8(00011100), FPU_FPSP);
2829 // fadd (6888X, 68040, 68060)
2831 int m_fadd(WORD inst, WORD siz)
2834 return gen_fpu(inst, siz, B8(00100010), FPU_NOWARN);
2839 // fsadd (68040, 68060)
2841 int m_fsadd(WORD inst, WORD siz)
2843 if (activefpu & (FPU_68040 | FPU_68060))
2844 return gen_fpu(inst, siz, B8(01100010), FPU_NOWARN);
2846 return error("Unsupported in current FPU");
2853 int m_fdadd(WORD inst, WORD siz)
2855 if (activefpu & (FPU_68040 | FPU_68060))
2856 return gen_fpu(inst, siz, B8(01100110), FPU_NOWARN);
2858 return error("Unsupported in current FPU");
2863 // fasin (6888X, 68040FPSP, 68060FPSP)
2865 int m_fasin(WORD inst, WORD siz)
2868 return gen_fpu(inst, siz, B8(00001100), FPU_FPSP);
2873 // fatan (6888X, 68040FPSP, 68060FPSP)
2875 int m_fatan(WORD inst, WORD siz)
2878 return gen_fpu(inst, siz, B8(00001010), FPU_FPSP);
2883 // fatanh (6888X, 68040FPSP, 68060FPSP)
2885 int m_fatanh(WORD inst, WORD siz)
2888 return gen_fpu(inst, siz, B8(00001101), FPU_FPSP);
2893 // fcmp (6888X, 68040, 68060)
2895 int m_fcmp(WORD inst, WORD siz)
2898 return gen_fpu(inst, siz, B8(00111000), FPU_FPSP);
2903 // fcos (6888X, 68040FPSP, 68060FPSP)
2905 int m_fcos(WORD inst, WORD siz)
2908 return gen_fpu(inst, siz, B8(00011101), FPU_FPSP);
2913 // fcosh (6888X, 68040FPSP, 68060FPSP)
2915 int m_fcosh(WORD inst, WORD siz)
2918 return gen_fpu(inst, siz, B8(00011001), FPU_FPSP);
2923 // fdbcc (6888X, 68040, 68060FPSP)
2925 int m_fdbcc(WORD inst, WORD siz)
2928 WORD opcode = inst & 0x3F; // Grab conditional bitfield
2938 if (a1exattr & DEFINED)
2940 if ((a1exattr & TDB) != cursect)
2941 return error(rel_error);
2943 uint32_t v = (uint32_t)a1exval - sloc;
2945 if ((v + 0x8000) > 0x10000)
2946 return error(range_error);
2952 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
2956 if (activefpu == FPU_68060)
2957 warn("Instruction is emulated in 68060");
2964 // fdiv (6888X, 68040, 68060)
2966 int m_fdiv(WORD inst, WORD siz)
2969 return gen_fpu(inst, siz, B8(00100000), FPU_NOWARN);
2974 // fsdiv (68040, 68060)
2976 int m_fsdiv(WORD inst, WORD siz)
2978 if (activefpu & (FPU_68040 | FPU_68060))
2979 return gen_fpu(inst, siz, B8(01100000), FPU_NOWARN);
2981 return error("Unsupported in current FPU");
2986 // fddiv (68040, 68060)
2988 int m_fddiv(WORD inst, WORD siz)
2990 if (activefpu & (FPU_68040 | FPU_68060))
2991 return gen_fpu(inst, siz, B8(01100100), FPU_NOWARN);
2993 return error("Unsupported in current FPU");
2998 // fetox (6888X, 68040FPSP, 68060FPSP)
3000 int m_fetox(WORD inst, WORD siz)
3003 return gen_fpu(inst, siz, B8(00010000), FPU_FPSP);
3008 // fetoxm1 (6888X, 68040FPSP, 68060FPSP)
3010 int m_fetoxm1(WORD inst, WORD siz)
3013 return gen_fpu(inst, siz, B8(00001000), FPU_FPSP);
3018 // fgetexp (6888X, 68040FPSP, 68060FPSP)
3020 int m_fgetexp(WORD inst, WORD siz)
3023 return gen_fpu(inst, siz, B8(00011110), FPU_FPSP);
3028 // fgetman (6888X, 68040FPSP, 68060FPSP)
3030 int m_fgetman(WORD inst, WORD siz)
3033 return gen_fpu(inst, siz, B8(00011111), FPU_FPSP);
3038 // fint (6888X, 68040FPSP, 68060)
3040 int m_fint(WORD inst, WORD siz)
3043 // special case - fint fpx = fint fpx,fpx
3046 if (activefpu == FPU_68040)
3047 warn("Instruction is emulated in 68040");
3049 return gen_fpu(inst, siz, B8(00000001), FPU_NOWARN);
3054 // fintrz (6888X, 68040FPSP, 68060)
3056 int m_fintrz(WORD inst, WORD siz)
3059 // special case - fintrz fpx = fintrz fpx,fpx
3062 if (activefpu == FPU_68040)
3063 warn("Instruction is emulated in 68040");
3065 return gen_fpu(inst, siz, B8(00000011), FPU_NOWARN);
3070 // flog10 (6888X, 68040FPSP, 68060FPSP)
3072 int m_flog10(WORD inst, WORD siz)
3075 return gen_fpu(inst, siz, B8(00010101), FPU_FPSP);
3080 // flog2 (6888X, 68040FPSP, 68060FPSP)
3082 int m_flog2(WORD inst, WORD siz)
3085 return gen_fpu(inst, siz, B8(00010110), FPU_FPSP);
3090 // flogn (6888X, 68040FPSP, 68060FPSP)
3092 int m_flogn(WORD inst, WORD siz)
3095 return gen_fpu(inst, siz, B8(00010100), FPU_FPSP);
3100 // flognp1 (6888X, 68040FPSP, 68060FPSP)
3102 int m_flognp1(WORD inst, WORD siz)
3105 return gen_fpu(inst, siz, B8(00000110), FPU_FPSP);
3110 // fmod (6888X, 68040FPSP, 68060FPSP)
3112 int m_fmod(WORD inst, WORD siz)
3115 return gen_fpu(inst, siz, B8(00100001), FPU_FPSP);
3120 // fmove (6888X, 68040, 68060)
3122 int m_fmove(WORD inst, WORD siz)
3127 if ((am0 == FREG) && (am1 < AM_USP))
3131 inst |= am1 | a1reg;
3140 case SIZB: inst |= (6 << 10); break;
3141 case SIZW: inst |= (4 << 10); break;
3142 case SIZL: inst |= (0 << 10); break;
3144 case SIZS: inst |= (1 << 10); break;
3145 case SIZD: inst |= (5 << 10); break;
3146 case SIZX: inst |= (2 << 10); break;
3147 case SIZP: inst |= (3 << 10);
3148 // In P size we have 2 cases: {#k} where k is immediate
3149 // and {Dn} where Dn=Data register
3154 inst |= bfval1 << 4;
3159 if (bfval1 > 63 && bfval1 < -64)
3160 return error("K-factor must be between -64 and 63");
3162 inst |= bfval1 & 127;
3167 return error("Something bad happened, possibly.");
3171 // Destination specifier
3172 inst |= (a0reg << 7);
3180 else if ((am0 < AM_USP) && (am1 == FREG))
3185 inst |= am0 | a0reg;
3194 case SIZB: inst |= (6 << 10); break;
3195 case SIZW: inst |= (4 << 10); break;
3196 case SIZL: inst |= (0 << 10); break;
3198 case SIZS: inst |= (1 << 10); break;
3199 case SIZD: inst |= (5 << 10); break;
3200 case SIZX: inst |= (2 << 10); break;
3201 case SIZP: inst |= (3 << 10); break;
3203 return error("Something bad happened, possibly.");
3207 // Destination specifier
3208 inst |= (a1reg << 7);
3216 else if ((am0 == FREG) && (am1 == FREG))
3218 // register-to-register
3219 // Essentially ea to register with R/0=0
3228 if (siz != SIZX && siz != SIZN)
3229 return error("Invalid size");
3232 inst |= (a0reg << 10);
3234 // Destination register
3235 inst |= (a1reg << 7);
3245 // fmove (6888X, 68040, 68060)
3247 int m_fmovescr(WORD inst, WORD siz)
3251 // Move Floating-Point System Control Register (FPCR)
3255 if ((am0 == FPSCR) && (am1 < AM_USP))
3257 inst |= am1 | a1reg;
3259 inst = (1 << 13) + (1 << 15);
3265 else if ((am1 == FPSCR) && (am0 < AM_USP))
3267 inst |= am0 | a0reg;
3269 inst = (0 << 13) + (1 << 15);
3276 return error("m_fmovescr says: wut?");
3280 // fsmove/fdmove (68040, 68060)
3282 int m_fsmove(WORD inst, WORD siz)
3284 if (!(activefpu & (FPU_68040 | FPU_68060)))
3285 return error("Unsupported in current FPU");
3287 return gen_fpu(inst, siz, B8(01100100), FPU_FPSP);
3291 int m_fdmove(WORD inst, WORD siz)
3293 if (!(activefpu & (FPU_68040 | FPU_68060)))
3294 return error("Unsupported in current FPU");
3296 return gen_fpu(inst, siz, B8(01100100), FPU_FPSP);
3301 // fmovecr (6888X, 68040FPSP, 68060FPSP)
3303 int m_fmovecr(WORD inst, WORD siz)
3313 if (activefpu == FPU_68040)
3314 warn("Instruction is emulated in 68040/060");
3321 // fmovem (6888X, 68040, 68060FPSP)
3323 int m_fmovem(WORD inst, WORD siz)
3330 if (siz == SIZX || siz == SIZN)
3332 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
3334 // fmovem.x <rlist>,ea
3335 if (fpu_reglist_left(®mask) < 0)
3339 return error("missing comma");
3344 inst |= am0 | a0reg;
3346 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3347 return error("invalid addressing mode");
3350 inst = (1 << 15) | (1 << 14) | (1 << 13) | (0 << 11) | regmask;
3355 else if ((*tok >= KW_D0) && (*tok <= KW_D7))
3358 datareg = (*tok++ & 7) << 10;
3361 return error("missing comma");
3366 inst |= am0 | a0reg;
3368 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3369 return error("invalid addressing mode");
3371 // Quote from the 060 manual:
3372 // "[..] when the processor attempts an FMOVEM.X instruction using a dynamic register list."
3373 if (activefpu == FPU_68060)
3374 warn("Instruction is emulated in 68060");
3377 inst = (1 << 15) | (1 << 14) | (1 << 13) | (1 << 11) | (datareg << 4);
3388 inst |= am0 | a0reg;
3391 return error("missing comma");
3393 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
3395 // fmovem.x ea,<rlist>
3396 if (fpu_reglist_right(®mask) < 0)
3400 inst = (1 << 15) | (1 << 14) | (0 << 13) | (2 << 11) | regmask;
3408 datareg = (*tok++ & 7) << 10;
3410 // Quote from the 060 manual:
3411 // "[..] when the processor attempts an FMOVEM.X instruction using a dynamic register list."
3412 if (activefpu == FPU_68060)
3413 warn("Instruction is emulated in 68060");
3416 inst = (1 << 15) | (1 << 14) | (0 << 13) | (3 << 11) | (datareg << 4);
3423 else if (siz == SIZL)
3425 if ((*tok == KW_FPCR) || (*tok == KW_FPSR) || (*tok == KW_FPIAR))
3427 // fmovem.l <rlist>,ea
3428 regmask = (1 << 15) | (1 << 13);
3429 int no_control_regs = 0;
3432 if (*tok == KW_FPCR)
3434 regmask |= (1 << 12);
3440 if (*tok == KW_FPSR)
3442 regmask |= (1 << 11);
3448 if (*tok == KW_FPIAR)
3450 regmask |= (1 << 10);
3456 if ((*tok == '/') || (*tok == '-'))
3463 return error("missing comma");
3468 // Quote from the 060 manual:
3469 // "[..] when the processor attempts to execute an FMOVEM.L instruction with
3470 // an immediate addressing mode to more than one floating - point
3471 // control register (FPCR, FPSR, FPIAR)[..]"
3472 if (activefpu == FPU_68060)
3473 if (no_control_regs > 1 && am0 == IMMED)
3474 warn("Instruction is emulated in 68060");
3476 inst |= am0 | a0reg;
3483 // fmovem.l ea,<rlist>
3487 inst |= am0 | a0reg;
3490 return error("missing comma");
3492 regmask = (1 << 15) | (0 << 13);
3495 if (*tok == KW_FPCR)
3497 regmask |= (1 << 12);
3502 if (*tok == KW_FPSR)
3504 regmask |= (1 << 11);
3509 if (*tok == KW_FPIAR)
3511 regmask |= (1 << 10);
3516 if ((*tok == '/') || (*tok == '-'))
3523 return error("extra (unexpected) text found");
3525 inst |= am0 | a0reg;
3532 return error("bad size suffix");
3539 // fmul (6888X, 68040, 68060)
3541 int m_fmul(WORD inst, WORD siz)
3544 return gen_fpu(inst, siz, B8(00100011), FPU_NOWARN);
3549 // fsmul (68040, 68060)
3551 int m_fsmul(WORD inst, WORD siz)
3553 if (activefpu & (FPU_68040 | FPU_68060))
3554 return gen_fpu(inst, siz, B8(01100011), FPU_NOWARN);
3556 return error("Unsupported in current FPU");
3563 int m_fdmul(WORD inst, WORD siz)
3565 if (activefpu & (FPU_68040 | FPU_68060))
3566 return gen_fpu(inst, siz, B8(01100111), FPU_NOWARN);
3568 return error("Unsupported in current FPU");
3573 // fneg (6888X, 68040, 68060)
3575 int m_fneg(WORD inst, WORD siz)
3582 return gen_fpu(inst, siz, B8(00011010), FPU_NOWARN);
3585 return gen_fpu(inst, siz, B8(00011010), FPU_NOWARN);
3590 // fsneg (68040, 68060)
3592 int m_fsneg(WORD inst, WORD siz)
3594 if (activefpu & (FPU_68040 | FPU_68060))
3599 return gen_fpu(inst, siz, B8(01011010), FPU_NOWARN);
3602 return gen_fpu(inst, siz, B8(01011010), FPU_NOWARN);
3605 return error("Unsupported in current FPU");
3610 // fdneg (68040, 68060)
3612 int m_fdneg(WORD inst, WORD siz)
3614 if (activefpu & (FPU_68040 | FPU_68060))
3619 return gen_fpu(inst, siz, B8(01011110), FPU_NOWARN);
3622 return gen_fpu(inst, siz, B8(01011110), FPU_NOWARN);
3625 return error("Unsupported in current FPU");
3630 // fnop (6888X, 68040, 68060)
3632 int m_fnop(WORD inst, WORD siz)
3635 return gen_fpu(inst, siz, B8(00000000), FPU_NOWARN);
3640 // frem (6888X, 68040FPSP, 68060FPSP)
3642 int m_frem(WORD inst, WORD siz)
3645 return gen_fpu(inst, siz, B8(00100101), FPU_FPSP);
3650 // fscale (6888X, 68040FPSP, 68060FPSP)
3652 int m_fscale(WORD inst, WORD siz)
3655 return gen_fpu(inst, siz, B8(00100110), FPU_FPSP);
3660 // FScc (6888X, 68040, 68060), cpScc (68851, 68030), PScc (68851)
3661 // TODO: Add check for PScc to ensure 68020+68851 active
3662 // TODO: Add check for cpScc to ensure 68020+68851, 68030
3664 int m_fscc(WORD inst, WORD siz)
3668 // We stash the 5 condition bits inside the opcode in 68ktab (bits 4-0),
3669 // so we need to extract them first and fill in the clobbered bits.
3670 WORD opcode = inst & 0x1F;
3672 inst |= am0 | a0reg;
3676 if (activefpu == FPU_68060)
3677 warn("Instruction is emulated in 68060");
3683 // fsgldiv (6888X, 68040FPSP, 68060FPSP)
3685 int m_fsgldiv(WORD inst, WORD siz)
3688 return gen_fpu(inst, siz, B8(00100100), FPU_FPSP);
3693 // fsglmul (6888X, 68040, 68060FPSP)
3695 int m_fsglmul(WORD inst, WORD siz)
3698 return gen_fpu(inst, siz, B8(00100111), FPU_FPSP);
3703 // fsin (6888X, 68040FPSP, 68060FPSP)
3705 int m_fsin(WORD inst, WORD siz)
3708 return gen_fpu(inst, siz, B8(00001110), FPU_FPSP);
3713 // fsincos (6888X, 68040FPSP, 68060FPSP)
3715 int m_fsincos(WORD inst, WORD siz)
3719 // Swap a1reg, a2reg as a2reg should be stored in the bitfield gen_fpu
3726 if (gen_fpu(inst, siz, B8(00110000), FPU_FPSP) == OK)
3737 // fsinh (6888X, 68040FPSP, 68060FPSP)
3739 int m_fsinh(WORD inst, WORD siz)
3742 return gen_fpu(inst, siz, B8(00000010), FPU_FPSP);
3747 // fsqrt (6888X, 68040, 68060)
3749 int m_fsqrt(WORD inst, WORD siz)
3752 return gen_fpu(inst, siz, B8(00000100), FPU_NOWARN);
3757 // fsfsqrt (68040, 68060)
3759 int m_fsfsqrt(WORD inst, WORD siz)
3761 if (activefpu & (FPU_68040 | FPU_68060))
3762 return gen_fpu(inst, siz, B8(01000001), FPU_NOWARN);
3764 return error("Unsupported in current FPU");
3769 // fdfsqrt (68040, 68060)
3771 int m_fdfsqrt(WORD inst, WORD siz)
3773 if (activefpu & (FPU_68040 | FPU_68060))
3774 return gen_fpu(inst, siz, B8(01000101), FPU_NOWARN);
3776 return error("Unsupported in current FPU");
3781 // fsub (6888X, 68040, 68060)
3783 int m_fsub(WORD inst, WORD siz)
3786 return gen_fpu(inst, siz, B8(00101000), FPU_NOWARN);
3791 // fsfsub (68040, 68060)
3793 int m_fsfsub(WORD inst, WORD siz)
3795 if (activefpu & (FPU_68040 | FPU_68060))
3796 return gen_fpu(inst, siz, B8(01101000), FPU_NOWARN);
3798 return error("Unsupported in current FPU");
3803 // fdfsub (68040, 68060)
3805 int m_fdsub(WORD inst, WORD siz)
3807 if (activefpu & (FPU_68040 | FPU_68060))
3808 return gen_fpu(inst, siz, B8(01101100), FPU_NOWARN);
3810 return error("Unsupported in current FPU");
3815 // ftan (6888X, 68040FPSP, 68060FPSP)
3817 int m_ftan(WORD inst, WORD siz)
3820 return gen_fpu(inst, siz, B8(00001111), FPU_FPSP);
3825 // ftanh (6888X, 68040FPSP, 68060FPSP)
3827 int m_ftanh(WORD inst, WORD siz)
3830 return gen_fpu(inst, siz, B8(00001001), FPU_FPSP);
3835 // ftentox (6888X, 68040FPSP, 68060FPSP)
3837 int m_ftentox(WORD inst, WORD siz)
3840 return gen_fpu(inst, siz, B8(00010010), FPU_FPSP);
3845 // FTRAPcc (6888X, 68040, 68060FPSP)
3847 int m_ftrapcc(WORD inst, WORD siz)
3851 // We stash the 5 condition bits inside the opcode in 68ktab (bits 3-7),
3852 // so we need to extract them first and fill in the clobbered bits.
3853 WORD opcode = (inst >> 3) & 0x1F;
3854 inst = (inst & 0xFF07) | (0xF << 3);
3863 else if (siz == SIZL)
3870 else if (siz == SIZN)
3878 if (activefpu == FPU_68060)
3879 warn("Instruction is emulated in 68060");
3886 // ftst (6888X, 68040, 68060)
3888 int m_ftst(WORD inst, WORD siz)
3891 return gen_fpu(inst, siz, B8(00111010), FPU_NOWARN);
3896 // ftwotox (6888X, 68040FPSP, 68060FPSP)
3898 int m_ftwotox(WORD inst, WORD siz)
3901 return gen_fpu(inst, siz, B8(00010001), FPU_FPSP);
3905 /////////////////////////////////
3907 // 68060 specific instructions //
3909 /////////////////////////////////
3915 int m_lpstop(WORD inst, WORD siz)
3918 D_word(B16(00000001, 11000000));
3920 if (a0exattr & DEFINED)
3926 AddFixup(FU_WORD, sloc, a0expr);
3937 int m_plpa(WORD inst, WORD siz)
3940 inst |= a0reg; // Install register