2 // RMAC - Reboot's Macro Assembler for all Atari computers
3 // MACH.C - Code Generation
4 // Copyright (C) 199x Landon Dyer, 2011-2017 Reboot and Friends
5 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
6 // Source utilised with the kind permission of Landon Dyer
24 int movep = 0; // Global flag to indicate we're generating a movep instruction
26 // Function prototypes
27 int m_unimp(WORD, WORD), m_badmode(WORD, WORD);
28 int m_self(WORD, WORD);
29 int m_abcd(WORD, WORD);
30 int m_reg(WORD, WORD);
31 int m_imm(WORD, WORD);
32 int m_imm8(WORD, WORD);
33 int m_shi(WORD, WORD);
34 int m_shr(WORD, WORD);
35 int m_bitop(WORD, WORD);
36 int m_exg(WORD, WORD);
38 int m_lea(WORD, WORD);
40 int m_dbra(WORD, WORD);
41 int m_link(WORD, WORD);
42 int m_adda(WORD, WORD);
43 int m_addq(WORD, WORD);
44 int m_move(WORD, WORD);
45 int m_moveq(WORD, WORD);
46 int m_usp(WORD, WORD);
47 int m_movep(WORD, WORD);
48 int m_trap(WORD, WORD);
49 int m_movem(WORD, WORD);
50 int m_clra(WORD, WORD);
51 int m_clrd(WORD, WORD);
53 int m_move30(WORD, WORD); // 68020/30/40/60
54 int m_br30(WORD inst, WORD siz);
55 int m_ea030(WORD inst, WORD siz);
56 int m_bfop(WORD inst, WORD siz);
57 int m_callm(WORD inst, WORD siz);
58 int m_cas(WORD inst, WORD siz);
59 int m_cas2(WORD inst, WORD siz);
60 int m_chk2(WORD inst, WORD siz);
61 int m_cmp2(WORD inst, WORD siz);
62 int m_bkpt(WORD inst, WORD siz);
63 int m_cpbr(WORD inst, WORD siz);
64 int m_cpdbr(WORD inst, WORD siz);
65 int m_muls(WORD inst, WORD siz);
66 int m_move16a(WORD inst, WORD siz);
67 int m_move16b(WORD inst, WORD siz);
68 int m_pack(WORD inst, WORD siz);
69 int m_rtm(WORD inst, WORD siz);
70 int m_rtd(WORD inst, WORD siz);
71 int m_trapcc(WORD inst, WORD siz);
72 int m_cinv(WORD inst, WORD siz);
73 int m_cprest(WORD inst, WORD siz);
74 int m_movec(WORD inst, WORD siz);
75 int m_moves(WORD inst, WORD siz);
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);
89 int m_ptrapcc(WORD inst, WORD siz);
90 int m_ploadr(WORD inst, WORD siz);
91 int m_ploadw(WORD inst, WORD siz);
94 int m_fabs(WORD inst, WORD siz);
95 int m_facos(WORD inst, WORD siz);
96 int m_fadd(WORD inst, WORD siz);
97 int m_fasin(WORD inst, WORD siz);
98 int m_fatan(WORD inst, WORD siz);
99 int m_fatanh(WORD inst, WORD siz);
100 int m_fcmp(WORD inst, WORD siz);
101 int m_fcos(WORD inst, WORD siz);
102 int m_fcosh(WORD inst, WORD siz);
103 int m_fdabs(WORD inst, WORD siz);
104 int m_fdadd(WORD inst, WORD siz);
105 int m_fdbcc(WORD inst, WORD siz);
106 int m_fddiv(WORD inst, WORD siz);
107 int m_fdfsqrt(WORD inst, WORD siz);
108 int m_fdiv(WORD inst, WORD siz);
109 int m_fdmove(WORD inst, WORD siz);
110 int m_fdmul(WORD inst, WORD siz);
111 int m_fdneg(WORD inst, WORD siz);
112 int m_fdsub(WORD inst, WORD siz);
113 int m_fetox(WORD inst, WORD siz);
114 int m_fetoxm1(WORD inst, WORD siz);
115 int m_fgetexp(WORD inst, WORD siz);
116 int m_fgetman(WORD inst, WORD siz);
117 int m_fint(WORD inst, WORD siz);
118 int m_fintrz(WORD inst, WORD siz);
119 int m_flog10(WORD inst, WORD siz);
120 int m_flog2(WORD inst, WORD siz);
121 int m_flogn(WORD inst, WORD siz);
122 int m_flognp1(WORD inst, WORD siz);
123 int m_fmod(WORD inst, WORD siz);
124 int m_fmove(WORD inst, WORD siz);
125 int m_fmovescr(WORD inst, WORD siz);
126 int m_fmovecr(WORD inst, WORD siz);
127 int m_fmovem(WORD inst, WORD siz);
128 int m_fmul(WORD inst, WORD siz);
129 int m_fneg(WORD inst, WORD siz);
130 int m_fnop(WORD inst, WORD siz);
131 int m_frem(WORD inst, WORD siz);
132 int m_frestore(WORD inst, WORD siz);
133 int m_fsabs(WORD inst, WORD siz);
134 int m_fsadd(WORD inst, WORD siz);
135 int m_fscc(WORD inst, WORD siz);
136 int m_fscale(WORD inst, WORD siz);
137 int m_fsdiv(WORD inst, WORD siz);
138 int m_fsfsqrt(WORD inst, WORD siz);
139 int m_fsfsub(WORD inst, WORD siz);
140 int m_fsgldiv(WORD inst, WORD siz);
141 int m_fsglmul(WORD inst, WORD siz);
142 int m_fsin(WORD inst, WORD siz);
143 int m_fsincos(WORD inst, WORD siz);
144 int m_fsinh(WORD inst, WORD siz);
145 int m_fsmove(WORD inst, WORD siz);
146 int m_fsmul(WORD inst, WORD siz);
147 int m_fsneg(WORD inst, WORD siz);
148 int m_fsqrt(WORD inst, WORD siz);
149 int m_fsub(WORD inst, WORD siz);
150 int m_ftan(WORD inst, WORD siz);
151 int m_ftanh(WORD inst, WORD siz);
152 int m_ftentox(WORD inst, WORD siz);
153 int m_ftst(WORD inst, WORD siz);
154 int m_ftwotox(WORD inst, WORD siz);
155 int m_ftrapcc(WORD inst, WORD siz);
157 // Common error messages
158 char range_error[] = "expression out of range";
159 char abs_error[] = "illegal absolute expression";
160 char seg_error[] = "bad (section) expression";
161 char rel_error[] = "illegal relative address";
162 char siz_error[] = "bad size specified";
163 char undef_error[] = "undefined expression";
164 char fwd_error[] = "forward or undefined expression";
165 char unsupport[] = "unsupported for selected CPU";
167 // Include code tables
169 { 0xFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000, 0, m_badmode }, // 0
171 { 0, 0L, 0L, 0x0000, 0, m_unimp } // Last entry
174 // Register number << 9
176 0, 1 << 9, 2 << 9, 3 << 9, 4 << 9, 5 << 9, 6 << 9, 7 << 9
179 // SIZB==>00, SIZW==>01, SIZL==>10, SIZN==>01 << 6
183 1<<6, (WORD)-1, // SIZW, n/a
184 2<<6, (WORD)-1, (WORD)-1, (WORD)-1, // SIZL, n/a, n/a, n/a
188 // Byte/word/long size for MOVE instrs
192 0x3000, (WORD)-1, // Word
193 0x2000, (WORD)-1, (WORD)-1, (WORD)-1, // Long
194 0x3000 // Word (SIZN)
197 // Word/long size (0=.w, 1=.l) in bit 8
201 0, (WORD)-1, // SIZW, n/a
202 1<<8, (WORD)-1, (WORD)-1, (WORD)-1, // SIZL, n/a, n/a, n/a
206 // Byte/Word/long size (0=.w, 1=.l) in bit 9
210 1<<9, (WORD)-1, // Word
211 1<<10, (WORD)-1, (WORD)-1, (WORD)-1, // Long
215 // Addressing mode in bits 6..11 (register/mode fields are reversed)
217 00000, 01000, 02000, 03000, 04000, 05000, 06000, 07000,
218 00100, 01100, 02100, 03100, 04100, 05100, 06100, 07100,
219 00200, 01200, 02200, 03200, 04200, 05200, 06200, 07200,
220 00300, 01300, 02300, 03300, 04300, 05300, 06300, 07300,
221 00400, 01400, 02400, 03400, 04400, 05400, 06400, 07400,
222 00500, 01500, 02500, 03500, 04500, 05500, 06500, 07500,
223 00600, 01600, 02600, 03600, 04600, 05600, 06600, 07600,
224 00700, 01700, 02700, 03700, 04700, 05700, 06700, 07700
227 // Control registers lookup table
229 // MC68010/MC68020/MC68030/MC68040/CPU32
230 0x000, // Source Function Code(SFC)
231 0x001, // Destination Function Code(DFC)
232 0x800, // User Stack Pointer(USP)
233 0x801, // Vector Base Register(VBR)
234 // MC68020 / MC68030 / MC68040
235 0x002, // Cache Control Register(CACR)
236 0x802, // Cache Address Register(CAAR) (020/030 only)
237 0x803, // Master Stack Pointer(MSP)
238 0x804, // Interrupt Stack Pointer(ISP)
239 // MC68040 / MC68LC040
240 0x003, // MMU Translation Control Register(TC)
241 0x004, // Instruction Transparent Translation Register 0 (ITT0)
242 0x005, // Instruction Transparent Translation Register 1 (ITT1)
243 0x006, // Data Transparent Translation Register 0 (DTT0)
244 0x007, // Data Transparent Translation Register 1 (DTT1)
245 0x805, // MMU Status Register(MMUSR)
246 0x806, // User Root Pointer(URP)
247 0x807, // Supervisor Root Pointer(SRP)
249 0x004, // Instruction Access Control Register 0 (IACR0)
250 0x005, // Instruction Access Control Register 1 (IACR1)
251 0x006, // Data Access Control Register 0 (DACR1)
252 0x007, // Data Access Control Register 1 (DACR1)
254 0xFFF // CPU Root Pointer (CRP) - There's no movec with CRP in it, this is just a guard entry
259 int m_unimp(WORD unused1, WORD unused2)
261 return (int)error("unimplemented mnemonic");
265 //int m_badmode(void)
266 int m_badmode(WORD unused1, WORD unused2)
268 return (int)error("inappropriate addressing mode");
272 int m_self(WORD inst, WORD usused)
280 // Do one EA in bits 0..5
282 // Bits in `inst' have the following meaning:
284 // Bit zero specifies which ea (ea0 or ea1) to generate in the lower six bits
287 // If bit one is set, the OTHER ea (the one that wasn't generated by bit zero)
288 // is generated after the instruction. Regardless of bit 0's value, ea0 is
289 // always deposited in memory before ea1.
291 // If bit two is set, standard size bits are set in the instr in bits 6 and 7.
293 // If bit four is set, bit three specifies which eaXreg to place in bits 9..11
296 int m_ea(WORD inst, WORD siz)
298 WORD flg = inst; // Save flag bits
299 inst &= ~0x3F; // Clobber flag bits in instr
301 // Install "standard" instr size bits
307 // OR-in register number
309 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
311 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
317 inst |= am1 | a1reg; // Get ea1 into instr
318 D_word(inst); // Deposit instr
320 // Generate ea0 if requested
324 ea1gen(siz); // Generate ea1
329 inst |= am0 | a0reg; // Get ea0 into instr
330 D_word(inst); // Deposit instr
331 ea0gen(siz); // Generate ea0
333 // Generate ea1 if requested
343 // Check if lea x(an),an can be optimised to addq.w #x,an--otherwise fall back
346 int m_lea(WORD inst, WORD siz)
348 if (CHECK_OPTS(OPT_LEA_ADDQ)
349 && ((am0 == ADISP) && (a0reg == a1reg) && (a0exattr & DEFINED))
350 && ((a0exval > 0) && (a0exval <= 8)))
352 inst = B16(01010000, 01001000) | (((uint16_t)a0exval & 7) << 9) | (a0reg);
354 warn("lea size(An),An converted to addq #size,An");
358 return m_ea(inst, siz);
362 int m_ea030(WORD inst, WORD siz)
365 WORD flg = inst; // Save flag bits
366 inst &= ~0x3F; // Clobber flag bits in instr
368 // Install "standard" instr size bits
374 // OR-in register number
377 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
381 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
388 inst |= am1 | a1reg; // Get ea1 into instr
389 D_word(inst); // Deposit instr
391 // Generate ea0 if requested
395 ea1gen(siz); // Generate ea1
401 // We get here if we're doing 020+ addressing and an address
402 // register is used. For example, something like "tst a0". A bit of
403 // a corner case, so kludge it
405 else if (am0 == PCDISP)
406 // Another corner case (possibly!), so kludge ahoy
407 inst |= am0; // Get ea0 into instr
408 else if (am0 == IMMED && am1 == MEMPOST)
410 // Added for addi/andi/cmpi/eori/ori/subi #xx,(bd,An,Dm)
411 inst |= a1reg | AINDEXED;
413 else if (am0 == IMMED)
414 inst |= am0 | a0reg; // Get ea0 into instr
415 else if (am0 == AM_CCR)
417 else if (am0 == AIND)
420 inst |= a0reg; // Get ea0 into instr
421 D_word(inst); // Deposit instr
422 ea0gen(siz); // Generate ea0
424 // Generate ea1 if requested
434 // Dx,Dy nnnnXXXnssnnnYYY If bit 0 of `inst' is set, install size bits in bits
437 int m_abcd(WORD inst, WORD siz)
446 inst |= a0reg | reg_9[a1reg];
456 int m_adda(WORD inst, WORD siz)
458 if (a0exattr & DEFINED)
460 if (CHECK_OPTS(OPT_ADDA_ADDQ))
461 if (a0exval > 1 && a0exval <= 8)
462 // Immediate is between 1 and 8 so let's convert to addq
463 return m_addq(B16(01010000, 00000000), siz);
464 if (CHECK_OPTS(OPT_ADDA_LEA))
467 // Immediate is larger than 8 so let's convert to lea
468 am0 = ADISP; // Change addressing mode
469 a0reg = a1reg; // In ADISP a0reg is used instead of a1reg!
470 return m_lea(B16(01000001, 11011000), SIZW);
474 inst |= am0 | a0reg | lwsiz_8[siz] | reg_9[a1reg];
476 ea0gen(siz); // Generate EA
483 // If bit 0 of `inst' is 1, install size bits in bits 6..7 of instr.
484 // If bit 1 of `inst' is 1, install a1reg in bits 9..11 of instr.
486 int m_reg(WORD inst, WORD siz)
493 // Install other register (9..11)
494 inst |= reg_9[a1reg];
496 inst &= ~7; // Clear off crufty bits
497 inst |= a0reg; // Install first register
507 int m_imm(WORD inst, WORD siz)
519 int m_imm8(WORD inst, WORD siz)
532 int m_shr(WORD inst, WORD siz)
534 inst |= reg_9[a0reg] | a1reg | siz_6[siz];
544 int m_shi(WORD inst, WORD siz)
546 inst |= a1reg | siz_6[siz];
548 if (a0exattr & DEFINED)
551 return error(range_error);
553 inst |= (a0exval & 7) << 9;
558 AddFixup(FU_QUICK, sloc, a0expr);
567 // {bset, btst, bchg, bclr} -- #immed,ea -- Dn,ea
569 int m_bitop(WORD inst, WORD siz)
571 // Enforce instruction sizes
573 { // X,Dn must be .n or .l
574 if (siz & (SIZB | SIZW))
575 return error(siz_error);
577 else if (siz & (SIZW | SIZL)) // X,ea must be .n or .b
578 return error(siz_error);
580 // Construct instr and EAs
586 ea0gen(SIZB); // Immediate bit number
590 inst |= reg_9[a0reg];
601 int m_dbra(WORD inst, WORD siz)
607 if (a1exattr & DEFINED)
609 if ((a1exattr & TDB) != cursect)
610 return error(rel_error);
612 uint32_t v = (uint32_t)a1exval - sloc;
614 if (v + 0x8000 > 0x10000)
615 return error(range_error);
621 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
632 int m_exg(WORD inst, WORD siz)
638 if (am0 == DREG && am1 == DREG)
640 else if (am0 == AREG && am1 == AREG)
646 m = a1reg; // Get AREG into a1reg
654 inst |= m | reg_9[a0reg] | a1reg;
664 int m_link(WORD inst, WORD siz)
668 // Is this an error condition???
673 inst &= ~((3 << 9) | (1 << 6) | (1 << 4));
685 WORD extra_addressing[16]=
687 0x30, // 0100 (bd,An,Xn)
688 0x30, // 0101 ([bd,An],Xn,od)
689 0x30, // 0102 ([bc,An,Xn],od)
690 0x30, // 0103 (bd,PC,Xn)
691 0x30, // 0104 ([bd,PC],Xn,od)
692 0x30, // 0105 ([bc,PC,Xn],od)
707 // Handle MOVE <C_ALL> <C_ALTDATA>
708 // MOVE <C_ALL> <M_AREG>
710 // Optimize MOVE.L #<smalldata>,D0 to a MOVEQ
712 int m_move(WORD inst, WORD size)
714 // Cast the passed in value to an int
717 // Try to optimize to MOVEQ
718 // N.B.: We can get away with casting the uint64_t to a 32-bit value
719 // because it checks for a SIZL (i.e., a 32-bit value).
720 if (CHECK_OPTS(OPT_MOVEL_MOVEQ)
721 && (siz == SIZL) && (am0 == IMMED) && (am1 == DREG)
722 && ((a0exattr & (TDB | DEFINED)) == DEFINED)
723 && ((uint32_t)a0exval + 0x80 < 0x100))
725 m_moveq((WORD)0x7000, (WORD)0);
728 warn("move.l #size,dx converted to moveq");
732 if ((am0 < ABASE) && (am1 < ABASE)) // 68000 modes
734 inst |= siz_12[siz] | am_6[am1] | reg_9[a1reg] | am0 | a0reg;
742 ea1gen((WORD)siz | 0x8000); // Tell ea1gen we're move ea,ea
746 inst |= siz_12[siz] | reg_9[a1reg] | extra_addressing[am0 - ABASE];
763 // Handle MOVE <C_ALL030> <C_ALTDATA>
764 // MOVE <C_ALL030> <M_AREG>
766 int m_move30(WORD inst, WORD size)
769 inst |= siz_12[siz] | reg_9[a1reg & 7] | a0reg | extra_addressing[am0 - ABASE];
784 // move USP,An -- move An,USP
786 int m_usp(WORD inst, WORD siz)
791 inst |= a1reg; // USP, An
793 inst |= a0reg; // An, USP
804 int m_moveq(WORD inst, WORD siz)
808 // Arrange for future fixup
809 if (!(a0exattr & DEFINED))
811 AddFixup(FU_BYTE | FU_SEXT, sloc + 1, a0expr);
814 else if ((uint32_t)a0exval + 0x100 >= 0x200)
815 return error(range_error);
817 inst |= reg_9[a1reg] | (a0exval & 0xFF);
825 // movep Dn, disp(An) -- movep disp(An), Dn
827 int m_movep(WORD inst, WORD siz)
829 // Tell ea0gen to lay off the 0(a0) optimisations on this one
837 inst |= reg_9[a0reg] | a1reg;
847 inst |= reg_9[a1reg] | a0reg;
864 int m_br(WORD inst, WORD siz)
866 if (a0exattr & DEFINED)
868 if ((a0exattr & TDB) != cursect)
870 //printf("m_br(): a0exattr = %X, cursect = %X, a0exval = %X, sloc = %X\n", a0exattr, cursect, a0exval, sloc);
871 return error(rel_error);
874 uint32_t v = (uint32_t)a0exval - (sloc + 2);
876 // Optimize branch instr. size
879 if (CHECK_OPTS(OPT_BSR_BCC_S) && (v != 0) && ((v + 0x80) < 0x100))
886 warn("Bcc.w/BSR.w converted to .s");
893 if ((v + 0x8000) > 0x10000)
894 return error(range_error);
902 if (siz == SIZB || siz == SIZS)
904 if ((v + 0x80) >= 0x100)
905 return error(range_error);
912 if ((v + 0x8000) >= 0x10000)
913 return error(range_error);
921 else if (siz == SIZN)
924 if (siz == SIZB || siz == SIZS)
927 AddFixup(FU_BBRA | FU_PCREL | FU_SEXT, sloc, a0expr);
935 AddFixup(FU_WORD | FU_PCREL | FU_LBRA | FU_ISBRA, sloc, a0expr);
946 int m_addq(WORD inst, WORD siz)
948 inst |= siz_6[siz] | am1 | a1reg;
950 if (a0exattr & DEFINED)
952 if ((a0exval > 8) || (a0exval == 0)) // Range in 1..8
953 return error(range_error);
955 inst |= (a0exval & 7) << 9;
960 AddFixup(FU_QUICK, sloc, a0expr);
973 int m_trap(WORD inst, WORD siz)
977 if (a0exattr & DEFINED)
980 return error(abs_error);
983 return error(range_error);
989 return error(undef_error);
996 // movem <rlist>,ea -- movem ea,<rlist>
998 int m_movem(WORD inst, WORD siz)
1006 return error("bad size suffix");
1013 // Handle #<expr>, ea
1016 if (abs_expr(&eval) != OK)
1019 if (eval >= 0x10000L)
1020 return error(range_error);
1026 if ((*tok >= KW_D0) && (*tok <= KW_A7))
1029 if (reglist(&rmask) < 0)
1034 return error("missing comma");
1039 inst |= am0 | a0reg;
1041 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
1042 return error("invalid addressing mode");
1044 // If APREDEC, reverse register mask
1050 for(i=0x8000; i; i>>=1, w>>=1)
1051 rmask = (WORD)((rmask << 1) | (w & 1));
1060 inst |= 0x0400 | am0 | a0reg;
1063 return error("missing comma");
1066 return error("missing register list");
1073 if (abs_expr(&eval) != OK)
1076 if (eval >= 0x10000)
1077 return error(range_error);
1081 else if (reglist(&rmask) < 0)
1084 if (!(amsktab[am0] & (C_CTRL | M_APOSTINC)))
1085 return error("invalid addressing mode");
1097 // CLR.x An ==> SUBA.x An,An
1099 int m_clra(WORD inst, WORD siz)
1101 inst |= a0reg | reg_9[a0reg] | lwsiz_8[siz];
1109 // CLR.L Dn ==> CLR.L An or MOVEQ #0,Dx
1111 int m_clrd(WORD inst, WORD siz)
1113 if (!CHECK_OPTS(OPT_CLR_DX))
1116 inst = (a0reg << 9) | B16(01110000, 00000000);
1124 ////////////////////////////////////////
1126 // 68020/30/40/60 instructions
1128 ////////////////////////////////////////
1133 int m_br30(WORD inst, WORD siz)
1135 if (a0exattr & DEFINED)
1137 if ((a0exattr & TDB) != cursect)
1138 return error(rel_error);
1140 uint32_t v = (uint32_t)a0exval - (sloc + 2);
1149 AddFixup(FU_LONG | FU_PCREL | FU_SEXT, sloc, a0expr);
1157 // bfchg, bfclr, bfexts, bfextu, bfffo, bfins, bfset
1158 // (68020, 68030, 68040)
1160 int m_bfop(WORD inst, WORD siz)
1162 if ((bfval1 > 31) || (bfval1 < 0))
1163 return error("bfxxx offset: immediate value must be between 0 and 31");
1165 // First instruction word - just the opcode and first EA
1166 // Note: both am1 is ORed because solely of bfins - maybe it's a good idea
1167 // to make a dedicated function for it?
1174 if (bfval2 > 31 || bfval2 < 0)
1175 return error("bfxxx width: immediate value must be between 0 and 31");
1177 // For Dw both immediate and register number are stuffed
1178 // into the same field O_o
1179 bfparam2 = (bfval2 << 0);
1183 bfparam1 = (bfval1 << 6);
1185 bfparam1 = bfval1 << 12;
1187 //D_word((inst | am0 | a0reg | am1 | a1reg));
1188 if (inst == B16(11101111, 11000000))
1189 // bfins special case
1190 D_word((inst | am1 | a1reg));
1192 D_word((inst | am0 | a0reg));
1194 ea0gen(siz); // Generate EA
1196 // Second instruction word - Dest register (if exists), Do, Offset, Dw, Width
1197 if (inst == B16(11101111, 11000000))
1199 // bfins special case
1200 inst = bfparam1 | bfparam2;
1203 inst |= a0reg << 12;
1209 inst = bfparam1 | bfparam2;
1215 inst |= a1reg << 12;
1225 // bkpt (68EC000, 68010, 68020, 68030, 68040, CPU32)
1227 int m_bkpt(WORD inst, WORD siz)
1231 if (a0exattr & DEFINED)
1234 return error(abs_error);
1237 return error(range_error);
1243 return error(undef_error);
1252 int m_callm(WORD inst, WORD siz)
1259 if (a0exattr & DEFINED)
1262 return error(abs_error);
1265 return error(range_error);
1267 inst = (uint16_t)a0exval;
1271 return error(undef_error);
1281 // cas (68020, 68030, 68040)
1283 int m_cas(WORD inst, WORD siz)
1289 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1290 return error(unsupport);
1305 return error("bad size suffix");
1310 if ((*tok < KW_D0) && (*tok > KW_D7))
1311 return error("CAS accepts only data registers");
1313 inst2 = (*tok++) & 7;
1316 return error("missing comma");
1319 if ((*tok < KW_D0) && (*tok > KW_D7))
1320 return error("CAS accepts only data registers");
1322 inst2 |= ((*tok++) & 7) << 6;
1325 return error("missing comma");
1328 if ((modes = amode(1)) < 0)
1332 return error("too many ea fields");
1335 return error("extra (unexpected) text found");
1337 // Reject invalid ea modes
1338 amsk = amsktab[am0];
1340 if ((amsk & (M_AIND | M_APOSTINC | M_APREDEC | M_ADISP | M_AINDEXED | M_ABSW | M_ABSL | M_ABASE | M_MEMPOST | M_MEMPRE)) == 0)
1341 return error("unsupported addressing mode");
1343 inst |= am0 | a0reg;
1353 // cas2 (68020, 68030, 68040)
1355 int m_cas2(WORD inst, WORD siz)
1359 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1360 return error(unsupport);
1375 return error("bad size suffix");
1380 if ((*tok < KW_D0) && (*tok > KW_D7))
1381 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1383 inst2 = (*tok++) & 7;
1386 return error("missing colon");
1389 if ((*tok < KW_D0) && (*tok > KW_D7))
1390 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1392 inst3 = (*tok++) & 7;
1395 return error("missing comma");
1398 if ((*tok < KW_D0) && (*tok > KW_D7))
1399 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1401 inst2 |= ((*tok++) & 7) << 6;
1404 return error("missing colon");
1407 if ((*tok < KW_D0) && (*tok > KW_D7))
1408 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1410 inst3 |= ((*tok++) & 7) << 6;
1413 return error("missing comma");
1417 return error("missing (");
1418 if ((*tok >= KW_D0) && (*tok <= KW_D7))
1419 inst2 |= (((*tok++) & 7) << 12) | (0 << 15);
1420 else if ((*tok >= KW_A0) && (*tok <= KW_A7))
1421 inst2 |= (((*tok++) & 7) << 12) | (1 << 15);
1423 return error("CAS accepts either data or address registers for Rn1:Rn2 pair");
1426 return error("missing (");
1429 return error("missing colon");
1433 return error("missing (");
1434 if ((*tok >= KW_D0) && (*tok <= KW_D7))
1435 inst3 |= (((*tok++) & 7) << 12) | (0 << 15);
1436 else if ((*tok >= KW_A0) && (*tok <= KW_A7))
1437 inst3 |= (((*tok++) & 7) << 12) | (1 << 15);
1439 return error("CAS accepts either data or address registers for Rn1:Rn2 pair");
1442 return error("missing (");
1445 return error("extra (unexpected) text found");
1456 // cmp2 (68020, 68030, 68040, CPU32)
1458 int m_cmp2(WORD inst, WORD siz)
1460 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1461 return error(unsupport);
1463 switch (siz & 0x000F)
1477 WORD flg = inst; // Save flag bits
1478 inst &= ~0x3F; // Clobber flag bits in instr
1480 // Install "standard" instr size bits
1486 // OR-in register number
1488 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1490 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1496 inst |= am1 | a1reg; // Get ea1 into instr
1497 D_word(inst); // Deposit instr
1499 // Generate ea0 if requested
1503 ea1gen(siz); // Generate ea1
1508 inst |= am0 | a0reg; // Get ea0 into instr
1509 D_word(inst); // Deposit instr
1510 ea0gen(siz); // Generate ea0
1512 // Generate ea1 if requested
1517 // If we're called from chk2 then bit 11 of size will be set. This is just
1518 // a dumb mechanism to pass this, required by the extension word. (You might
1519 // have noticed the siz & 15 thing above!)
1520 inst = (a1reg << 12) | (siz & (1 << 11));
1532 // chk2 (68020, 68030, 68040, CPU32)
1534 int m_chk2(WORD inst, WORD siz)
1536 return m_cmp2(inst, siz | (1 << 11));
1541 // cpbcc(68020, 68030, 68040 (FBcc), 68060 (FBcc))
1542 // TODO: Better checks for different instructions?
1544 int m_cpbr(WORD inst, WORD siz)
1546 if ((activecpu & (CPU_68020 | CPU_68030)) && (!activefpu == 0))
1547 return error(unsupport);
1549 if (a0exattr & DEFINED)
1551 if ((a0exattr & TDB) != cursect)
1552 return error(rel_error);
1554 uint32_t v = (uint32_t)a0exval - (sloc + 2);
1556 // Optimize branch instr. size
1559 if ((v != 0) && ((v + 0x8000) < 0x10000))
1569 if ((v + 0x8000) >= 0x10000)
1570 return error(range_error);
1578 else if (siz == SIZN)
1585 AddFixup(FU_LONG | FU_PCREL | FU_SEXT, sloc, a0expr);
1593 AddFixup(FU_WORD | FU_PCREL | FU_SEXT, sloc, a0expr);
1602 // cpdbcc(68020, 68030)
1604 int m_cpdbr(WORD inst, WORD siz)
1609 WORD condition = inst & 0x1F; // Grab condition sneakily placed in the lower 5 bits of inst
1610 inst &= 0xFFE0; // And then mask them out - you ain't seen me, roit?
1612 inst |= (1 << 9); // Bolt on FPU id
1619 if (a1exattr & DEFINED)
1621 if ((a1exattr & TDB) != cursect)
1622 return error(rel_error);
1624 v = (uint32_t)a1exval - sloc;
1626 if (v + 0x8000 > 0x10000)
1627 return error(range_error);
1633 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
1643 // muls.l / divs.l / divu.l / mulu.l (68020+)
1645 int m_muls(WORD inst, WORD siz)
1647 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1648 return error(unsupport);
1650 WORD flg = inst; // Save flag bits
1651 inst &= ~0x33F; // Clobber flag and extension bits in instr
1653 // Install "standard" instr size bits
1659 // OR-in register number
1661 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1663 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1666 // Regarding extension word: bit 11 is signed/unsigned selector
1667 // bit 10 is 32/64 bit selector
1668 // Both of these are packed in bits 9 and 8 of the instruction
1669 // field in 68ktab. Extra compilcations arise from the fact we
1670 // have to distinguish between divu/s.l Dn,Dm (which is encoded
1671 // as divu/s.l Dn,Dm:Dm) and divu/s.l Dn,Dm:Dx - the first is
1672 // 32 bit while the second 64 bit
1677 inst |= am1 | a1reg; // Get ea1 into instr
1678 D_word(inst); // Deposit instr
1682 inst = a1reg + (a2reg << 12) + ((flg & 0x200) << 2);
1684 inst = a1reg + (a2reg << 12) + ((flg & 0x300) << 2);
1688 // Generate ea0 if requested
1692 ea1gen(siz); // Generate ea1
1699 inst |= am0 | a0reg; // Get ea0 into instr
1700 D_word(inst); // Deposit instr
1704 inst = a1reg + (a2reg << 12) + ((flg & 0x200) << 2);
1706 inst = a1reg + (a2reg << 12) + ((flg & 0x300) << 2);
1710 ea0gen(siz); // Generate ea0
1712 // Generate ea1 if requested
1722 // move16 (ax)+,(ay)+
1724 int m_move16a(WORD inst, WORD siz)
1726 if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1727 return error(unsupport);
1731 inst = (1 << 15) + (a1reg << 12);
1739 // move16 with absolute address
1741 int m_move16b(WORD inst, WORD siz)
1743 if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1744 return error(unsupport);
1750 if (am0 == APOSTINC)
1753 return error("Wasn't this suppose to call m_move16a???");
1756 // move16 (ax)+,(xxx).L
1761 else if (am0 == ABSL)
1765 // move16 (xxx).L,(ax)+
1771 // move16 (xxx).L,(ax)
1776 else if (am0 == AIND)
1778 // move16 (ax),(xxx).L
1791 // pack/unpack (68020/68030/68040)
1793 int m_pack(WORD inst, WORD siz)
1798 return error("bad size suffix");
1800 if (*tok >= KW_D0 && *tok <= KW_D7)
1802 // Dx,Dy,#<adjustment>
1803 inst |= (0 << 3); // R/M
1804 inst |= (*tok++ & 7);
1806 if (*tok != ',' && tok[2] != ',')
1807 return error("missing comma");
1809 if (tok[1] < KW_D0 && tok[1] > KW_D7)
1810 return error(syntax_error);
1812 inst |= ((tok[1] & 7)<<9);
1815 // Fall through for adjustment (common in both valid cases)
1817 else if (*tok == '-')
1819 // -(Ax),-(Ay),#<adjustment>
1820 inst |= (1 << 3); // R/M
1821 tok++; // eat the minus
1823 if ((*tok != '(') && (tok[2]!=')') && (tok[3]!=',') && (tok[4] != '-') && (tok[5] != '(') && (tok[7] != ')') && (tok[8] != ','))
1824 return error(syntax_error);
1826 if (tok[1] < KW_A0 && tok[1] > KW_A7)
1827 return error(syntax_error);
1829 if (tok[5] < KW_A0 && tok[6] > KW_A7)
1830 return error(syntax_error);
1832 inst |= ((tok[1] & 7) << 0);
1833 inst |= ((tok[6] & 7) << 9);
1836 // Fall through for adjustment (common in both valid cases)
1839 return error("invalid syntax");
1841 if ((*tok != CONST) && (*tok != SYMBOL) && (*tok != '-'))
1842 return error(syntax_error);
1844 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
1847 if ((a0exattr & DEFINED) == 0)
1848 return error(undef_error);
1850 if (a0exval + 0x8000 > 0x10000)
1854 return error(extra_stuff);
1856 D_word((a0exval & 0xFFFF));
1865 int m_rtm(WORD inst, WORD siz)
1873 else if (am0 == AREG)
1875 inst |= (1 << 3) + a0reg;
1878 return error("rtm only allows data or address registers.");
1889 int m_rtd(WORD inst, WORD siz)
1893 if (a0exattr & DEFINED)
1896 return error(abs_error);
1898 if ((a0exval + 0x8000) <= 0x7FFF)
1899 return error(range_error);
1905 return error(undef_error);
1914 int m_trapcc(WORD inst, WORD siz)
1922 else if (am0 == IMMED)
1926 if (a0exval < 0x10000)
1933 return error("Immediate value too big");
1943 return error("Invalid parameter for trapcc");
1950 // cinvl/p/a (68040/68060)
1952 int m_cinv(WORD inst, WORD siz)
1957 inst |= (0 << 6) | (a1reg);
1961 inst |= (2 << 6) | (a1reg);
1964 inst |= (1 << 6) | (a1reg);
1967 inst |= (3 << 6) | (a1reg);
1976 int m_fpusavrest(WORD inst, WORD siz)
1978 inst |= am0 | a0reg;
1987 // cpSAVE/cpRESTORE (68020, 68030)
1989 int m_cprest(WORD inst, WORD siz)
1991 if (activecpu & !(CPU_68020 | CPU_68030))
1992 return error(unsupport);
1994 return m_fpusavrest(inst, siz);
2000 // FSAVE/FRESTORE (68040, 68060)
2002 int m_frestore(WORD inst, WORD siz)
2004 if ((!(activecpu & (CPU_68040 | CPU_68060))) ||
2005 (activefpu&(FPU_68881 | FPU_68882)))
2006 return error(unsupport);
2008 return m_fpusavrest(inst, siz);
2013 // movec (68010, 68020, 68030, 68040, 68060, CPU32)
2015 int m_movec(WORD inst, WORD siz)
2019 if (am0 == DREG || am0 == AREG)
2027 inst = (0 << 15) + (a0reg << 12) + CREGlut[a1reg];
2032 inst = (1 << 15) + (a0reg << 12) + CREGlut[a1reg];
2043 inst = (0 << 15) + (a1reg << 12) + CREGlut[a0reg];
2048 inst = (1 << 15) + (a1reg << 12) + CREGlut[a0reg];
2058 // moves (68010, 68020, 68030, 68040, CPU32)
2060 int m_moves(WORD inst, WORD siz)
2062 if (activecpu & !(CPU_68020 | CPU_68030 | CPU_68040))
2063 return error(unsupport);
2067 else if (siz == SIZL)
2074 inst |= am1 | a1reg;
2076 inst = (a0reg << 12) | (1 << 11) | (0 << 15);
2079 else if (am0 == AREG)
2081 inst |= am1 | a1reg;
2083 inst = (a0reg << 12) | (1 << 11) | (1 << 15);
2090 inst |= am0 | a0reg;
2092 inst = (a1reg << 12) | (0 << 11) | (0 << 15);
2097 inst |= am0 | a0reg;
2099 inst = (a1reg << 12) | (0 << 11) | (1 << 15);
2111 int m_pbcc(WORD inst, WORD siz)
2114 return error("Not implemented yet.");
2119 // pflusha (68030, 68040)
2121 int m_pflusha(WORD inst, WORD siz)
2123 if (activecpu == CPU_68030)
2126 inst = (1 << 13) | (1 << 10) | (0 << 5) | 0;
2130 else if (activecpu == CPU_68040)
2132 inst = B16(11110101, 00011000);
2137 return error(unsupport);
2144 // pflush (68030, 68040, 68060)
2146 int m_pflush(WORD inst, WORD siz)
2148 if (activecpu == CPU_68030)
2151 // PFLUSH FC, MASK, < ea >
2159 if (*tok != CONST && *tok != SYMBOL)
2160 return error("function code should be an expression");
2162 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2165 if ((a0exattr & DEFINED) == 0)
2166 return error("function code immediate should be defined");
2169 return error("function code out of range (0-7)");
2171 fc = (uint16_t)a0exval;
2181 fc = (1 << 4) | (*tok++ & 7);
2192 return error(syntax_error);
2196 return error("comma exptected");
2199 return error("mask should be an immediate value");
2201 if (*tok != CONST && *tok != SYMBOL)
2202 return error("mask is supposed to be immediate");
2204 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2207 if ((a0exattr & DEFINED) == 0)
2208 return error("mask immediate value should be defined");
2211 return error("function code out of range (0-7)");
2213 mask = (uint16_t)a0exval << 5;
2219 inst = (1 << 13) | fc | mask | (4 << 10);
2223 else if (*tok == ',')
2225 // PFLUSH FC, MASK, < ea >
2228 if (amode(0) == ERROR)
2232 return error(extra_stuff);
2234 if (am0 == AIND || am0 == ABSW || am0 == ABSL || am0 == ADISP || am0 == ADISP || am0 == AINDEXED || am0 == ABASE || am0 == MEMPOST || am0 == MEMPRE)
2236 inst |= am0 | a0reg;
2238 inst = (1 << 13) | fc | mask | (6 << 10);
2244 return error("unsupported addressing mode");
2248 return error(syntax_error);
2252 else if (activecpu == CPU_68040 || activecpu == CPU_68060)
2256 if (*tok != '(' && tok[2] != ')')
2257 return error(syntax_error);
2259 if (tok[1] < KW_A0 && tok[1] > KW_A7)
2260 return error("expected (An)");
2262 if ((inst & 7) == 7)
2263 // With pflushn/pflush there's no easy way to distinguish between
2264 // the two in 68040 mode. Ideally the opcode bitfields would have
2265 // been hardcoded in 68ktab but there is aliasing between 68030
2266 // and 68040 opcode. So we just set the 3 lower bits to 1 in
2267 // pflushn inside 68ktab and detect it here.
2268 inst = (inst & 0xff8) | 8;
2270 inst |= (tok[1] & 7) | (5 << 8);
2273 return error(extra_stuff);
2278 return error(unsupport);
2285 // pflushan (68040, 68060)
2287 int m_pflushan(WORD inst, WORD siz)
2289 if (activecpu == CPU_68040 || activecpu == CPU_68060)
2299 int m_pflushr(WORD inst, WORD siz)
2303 WORD flg = inst; // Save flag bits
2304 inst &= ~0x3F; // Clobber flag bits in instr
2306 // Install "standard" instr size bits
2312 // OR-in register number
2314 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
2316 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
2322 inst |= am1 | a1reg; // Get ea1 into instr
2323 D_word(inst); // Deposit instr
2325 // Generate ea0 if requested
2329 ea1gen(siz); // Generate ea1
2334 inst |= am0 | a0reg; // Get ea0 into instr
2335 D_word(inst); // Deposit instr
2336 ea0gen(siz); // Generate ea0
2338 // Generate ea1 if requested
2343 D_word(B16(10100000, 00000000));
2349 // ploadr, ploadw (68030)
2351 int m_pload(WORD inst, WORD siz, WORD extension)
2353 // TODO: 68851 support is not added yet.
2354 // None of the ST series of computers had a 68020 + 68851 socket and since
2355 // this is an Atari targetted assembler...
2364 if (a0reg == KW_SFC - KW_SFC)
2366 else if (a0reg == KW_DFC - KW_SFC)
2369 return error("illegal control register specified");
2373 inst = (1 << 3) | a0reg;
2376 if ((a0exattr & DEFINED) == 0)
2377 return error("constant value must be defined");
2379 inst = (2 << 3) | (uint16_t)a0exval;
2383 inst |= extension | (1 << 13);
2392 int m_ploadr(WORD inst, WORD siz)
2394 return m_pload(inst, siz, 1 << 9);
2398 int m_ploadw(WORD inst, WORD siz)
2400 return m_pload(inst, siz, 0 << 9);
2405 // pmove (68030/68851)
2407 int m_pmove(WORD inst, WORD siz)
2411 // TODO: 68851 support is not added yet. None of the ST series of
2412 // computers had a 68020 + 68851 socket and since this is an Atari
2413 // targetted assembler.... (same for 68EC030)
2416 inst2 = inst & (1 << 8); // Copy the flush bit over to inst2 in case we're called from m_pmovefd
2417 inst &= ~(1 << 8); // And mask it out
2424 else if (am1 == CREG)
2430 return error("pmove sez: Wut?");
2432 // The instruction is a quad-word (8 byte) operation
2433 // for the CPU root pointer and the supervisor root pointer.
2434 // It is a long-word operation for the translation control register
2435 // and the transparent translation registers(TT0 and TT1).
2436 // It is a word operation for the MMU status register.
2438 if (((reg == (KW_URP - KW_SFC)) || (reg == (KW_SRP - KW_SFC)))
2439 && ((siz != SIZD) && (siz != SIZN)))
2440 return error(siz_error);
2442 if (((reg == (KW_TC - KW_SFC)) || (reg == (KW_TT0 - KW_SFC)) || (reg == (KW_TT1 - KW_SFC)))
2443 && ((siz != SIZL) && (siz != SIZN)))
2444 return error(siz_error);
2446 if ((reg == (KW_MMUSR - KW_SFC)) && ((siz != SIZW) && (siz != SIZN)))
2447 return error(siz_error);
2451 inst |= am1 | a1reg;
2454 else if (am1 == CREG)
2456 inst |= am0 | a0reg;
2460 switch (reg + KW_SFC)
2463 inst2 |= (0 << 10) + (1 << 14); break;
2465 inst2 |= (2 << 10) + (1 << 14); break;
2467 inst2 |= (3 << 10) + (1 << 14); break;
2469 inst2 |= (2 << 10) + (0 << 13); break;
2471 inst2 |= (3 << 10) + (0 << 13); break;
2474 inst2 |= (1 << 9) + (3 << 13);
2476 inst2 |= (0 << 9) + (3 << 13);
2479 return error("unsupported register");
2487 else if (am1 == CREG)
2497 int m_pmovefd(WORD inst, WORD siz)
2501 return m_pmove(inst | (1 << 8), siz);
2508 int m_ptrapcc(WORD inst, WORD siz)
2511 // We stash the 5 condition bits inside the opcode in 68ktab (bits 0-4),
2512 // so we need to extract them first and fill in the clobbered bits.
2513 WORD opcode = inst & 0x1F;
2514 inst = (inst & 0xFFE0) | (0x18);
2523 else if (siz == SIZL)
2530 else if (siz == SIZN)
2542 // ptestr, ptestw (68030)
2544 int m_ptest(WORD inst, WORD siz)
2548 if (activecpu == CPU_68030)
2549 return error("Not implemented yet.");
2550 else if (activecpu == CPU_68040)
2551 return error("Not implemented yet.");
2556 //////////////////////////////////////////////////////////////////////////////
2558 // 68020/30/40/60 instructions
2559 // Note: the map of which instructions are allowed on which CPUs came from the
2560 // 68060 manual, section D-1 (page 392 of the PDF). The current implementation
2561 // is missing checks for the EC models which have a simplified FPU.
2563 //////////////////////////////////////////////////////////////////////////////
2566 #define FPU_NOWARN 0
2571 // Generate a FPU opcode
2573 static inline int gen_fpu(WORD inst, WORD siz, WORD opmode, WORD emul)
2575 if (am0 < AM_NONE) // Check first operand for ea or fp - is this right?
2577 inst |= (1 << 9); // Bolt on FPU id
2580 //if (am0 == DREG || am0 == AREG)
2584 inst = 1 << 14; // R/M field (we have ea so have to set this to 1)
2588 case SIZB: inst |= (6 << 10); break;
2589 case SIZW: inst |= (4 << 10); break;
2590 case SIZL: inst |= (0 << 10); break;
2592 case SIZS: inst |= (1 << 10); break;
2593 case SIZD: inst |= (5 << 10); break;
2594 case SIZX: inst |= (2 << 10); break;
2599 warn("This encoding will cause an unimplemented data type exception in the MC68040 to allow emulation in software.");
2603 return error("Something bad happened, possibly, in gen_fpu.");
2607 inst |= (a1reg << 7);
2614 inst |= (1 << 9); // Bolt on FPU id
2618 inst |= (a1reg << 7);
2623 if ((emul & FPU_FPSP) && (activefpu == (FPU_68040 | FPU_68060)))
2624 warn("Instruction is emulated in 68040/060");
2631 // fabs (6888X, 68040FPSP, 68060FPSP)
2633 int m_fabs(WORD inst, WORD siz)
2636 return gen_fpu(inst, siz, B8(00011000), FPU_NOWARN);
2641 // fsabs (68040, 68060)
2643 int m_fsabs(WORD inst, WORD siz)
2646 if (activefpu == FPU_68040)
2647 return gen_fpu(inst, siz, B8(01011000), FPU_NOWARN);
2649 return error("Unsupported in current FPU");
2654 // fdabs (68040, 68060)
2656 int m_fdabs(WORD inst, WORD siz)
2658 if (activefpu == FPU_68040)
2659 return gen_fpu(inst, siz, B8(01011100), FPU_NOWARN);
2661 return error("Unsupported in current FPU");
2666 // facos (6888X, 68040FPSP, 68060FPSP)
2668 int m_facos(WORD inst, WORD siz)
2671 return gen_fpu(inst, siz, B8(00011100), FPU_FPSP);
2676 // fadd (6888X, 68040, 68060)
2678 int m_fadd(WORD inst, WORD siz)
2681 return gen_fpu(inst, siz, B8(00100010), FPU_NOWARN);
2686 // fsadd (68040, 68060)
2688 int m_fsadd(WORD inst, WORD siz)
2690 if (activefpu & (FPU_68040 | FPU_68060))
2691 return gen_fpu(inst, siz, B8(01100010), FPU_NOWARN);
2693 return error("Unsupported in current FPU");
2700 int m_fdadd(WORD inst, WORD siz)
2702 if (activefpu & (FPU_68040 | FPU_68060))
2703 return gen_fpu(inst, siz, B8(01100110), FPU_NOWARN);
2705 return error("Unsupported in current FPU");
2710 // fasin (6888X, 68040FPSP, 68060FPSP)
2712 int m_fasin(WORD inst, WORD siz)
2715 return gen_fpu(inst, siz, B8(00001100), FPU_FPSP);
2720 // fatan (6888X, 68040FPSP, 68060FPSP)
2722 int m_fatan(WORD inst, WORD siz)
2725 return gen_fpu(inst, siz, B8(00001010), FPU_FPSP);
2730 // fatanh (6888X, 68040FPSP, 68060FPSP)
2732 int m_fatanh(WORD inst, WORD siz)
2735 return gen_fpu(inst, siz, B8(00001101), FPU_FPSP);
2740 // fcmp (6888X, 68040, 68060)
2742 int m_fcmp(WORD inst, WORD siz)
2745 return gen_fpu(inst, siz, B8(00111000), FPU_FPSP);
2750 // fcos (6888X, 68040FPSP, 68060FPSP)
2752 int m_fcos(WORD inst, WORD siz)
2755 return gen_fpu(inst, siz, B8(00011101), FPU_FPSP);
2760 // fcosh (6888X, 68040FPSP, 68060FPSP)
2762 int m_fcosh(WORD inst, WORD siz)
2765 return gen_fpu(inst, siz, B8(00011001), FPU_FPSP);
2770 // fdbcc (6888X, 68040, 68060FPSP)
2772 int m_fdbcc(WORD inst, WORD siz)
2775 WORD opcode = inst & 0x3F; // Grab conditional bitfield
2785 if (a1exattr & DEFINED)
2787 if ((a1exattr & TDB) != cursect)
2788 return error(rel_error);
2790 uint32_t v = (uint32_t)a1exval - sloc;
2792 if ((v + 0x8000) > 0x10000)
2793 return error(range_error);
2799 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
2803 if (activefpu == FPU_68060)
2804 warn("Instruction is emulated in 68060");
2811 // fdiv (6888X, 68040, 68060)
2813 int m_fdiv(WORD inst, WORD siz)
2816 return gen_fpu(inst, siz, B8(00100000), FPU_NOWARN);
2821 // fsdiv (68040, 68060)
2823 int m_fsdiv(WORD inst, WORD siz)
2825 if (activefpu & (FPU_68040 | FPU_68060))
2826 return gen_fpu(inst, siz, B8(01100000), FPU_NOWARN);
2828 return error("Unsupported in current FPU");
2833 // fddiv (68040, 68060)
2835 int m_fddiv(WORD inst, WORD siz)
2837 if (activefpu & (FPU_68040 | FPU_68060))
2838 return gen_fpu(inst, siz, B8(01100100), FPU_NOWARN);
2840 return error("Unsupported in current FPU");
2845 // fetox (6888X, 68040FPSP, 68060FPSP)
2847 int m_fetox(WORD inst, WORD siz)
2850 return gen_fpu(inst, siz, B8(00010000), FPU_FPSP);
2855 // fetoxm1 (6888X, 68040FPSP, 68060FPSP)
2857 int m_fetoxm1(WORD inst, WORD siz)
2860 return gen_fpu(inst, siz, B8(00001000), FPU_FPSP);
2865 // fgetexp (6888X, 68040FPSP, 68060FPSP)
2867 int m_fgetexp(WORD inst, WORD siz)
2870 return gen_fpu(inst, siz, B8(00011110), FPU_FPSP);
2875 // fgetman (6888X, 68040FPSP, 68060FPSP)
2877 int m_fgetman(WORD inst, WORD siz)
2880 return gen_fpu(inst, siz, B8(00011111), FPU_FPSP);
2885 // fint (6888X, 68040FPSP, 68060)
2887 int m_fint(WORD inst, WORD siz)
2890 // special case - fint fpx = fint fpx,fpx
2893 if (activefpu == FPU_68040)
2894 warn("Instruction is emulated in 68040");
2896 return gen_fpu(inst, siz, B8(00000001), FPU_NOWARN);
2901 // fintrz (6888X, 68040FPSP, 68060)
2903 int m_fintrz(WORD inst, WORD siz)
2906 // special case - fintrz fpx = fintrz fpx,fpx
2909 if (activefpu == FPU_68040)
2910 warn("Instruction is emulated in 68040");
2912 return gen_fpu(inst, siz, B8(00000011), FPU_NOWARN);
2917 // flog10 (6888X, 68040FPSP, 68060FPSP)
2919 int m_flog10(WORD inst, WORD siz)
2922 return gen_fpu(inst, siz, B8(00010101), FPU_FPSP);
2927 // flog2 (6888X, 68040FPSP, 68060FPSP)
2929 int m_flog2(WORD inst, WORD siz)
2932 return gen_fpu(inst, siz, B8(00010110), FPU_FPSP);
2937 // flogn (6888X, 68040FPSP, 68060FPSP)
2939 int m_flogn(WORD inst, WORD siz)
2942 return gen_fpu(inst, siz, B8(00010100), FPU_FPSP);
2947 // flognp1 (68040FPSP, 68060FPSP)
2949 int m_flognp1(WORD inst, WORD siz)
2951 if (activefpu & (FPU_68040 | FPU_68060))
2952 return gen_fpu(inst, siz, B8(00000110), FPU_FPSP);
2954 return error("Unsupported in current FPU");
2959 // fmod (6888X, 68040FPSP, 68060FPSP)
2961 int m_fmod(WORD inst, WORD siz)
2964 return gen_fpu(inst, siz, B8(00100001), FPU_FPSP);
2969 // fmove (6888X, 68040, 68060)
2971 int m_fmove(WORD inst, WORD siz)
2976 if ((am0 == FREG) && (am1 < AM_USP))
2980 inst |= am1 | a1reg;
2989 case SIZB: inst |= (6 << 10); break;
2990 case SIZW: inst |= (4 << 10); break;
2991 case SIZL: inst |= (0 << 10); break;
2993 case SIZS: inst |= (1 << 10); break;
2994 case SIZD: inst |= (5 << 10); break;
2995 case SIZX: inst |= (2 << 10); break;
2996 case SIZP: inst |= (3 << 10);
2997 // In P size we have 2 cases: {#k} where k is immediate
2998 // and {Dn} where Dn=Data register
3003 inst |= bfval1 << 4;
3008 if (bfval1 > 63 && bfval1 < -64)
3009 return error("K-factor must be between -64 and 63");
3011 inst |= bfval1 & 127;
3016 return error("Something bad happened, possibly.");
3020 // Destination specifier
3021 inst |= (a0reg << 7);
3029 else if ((am0 < AM_USP) && (am1 == FREG))
3034 inst |= am0 | a0reg;
3043 case SIZB: inst |= (6 << 10); break;
3044 case SIZW: inst |= (4 << 10); break;
3045 case SIZL: inst |= (0 << 10); break;
3047 case SIZS: inst |= (1 << 10); break;
3048 case SIZD: inst |= (5 << 10); break;
3049 case SIZX: inst |= (2 << 10); break;
3050 case SIZP: inst |= (3 << 10); break;
3052 return error("Something bad happened, possibly.");
3056 // Destination specifier
3057 inst |= (a1reg << 7);
3065 else if ((am0 == FREG) && (am1 == FREG))
3067 // register-to-register
3068 // Essentially ea to register with R/0=0
3077 if (siz != SIZX && siz != SIZN)
3078 return error("Invalid size");
3081 inst |= (a0reg << 10);
3083 // Destination register
3084 inst |= (a1reg << 7);
3094 // fmove (6888X, 68040, 68060)
3096 int m_fmovescr(WORD inst, WORD siz)
3100 // Move Floating-Point System Control Register (FPCR)
3104 if ((am0 == FPSCR) && (am1 < AM_USP))
3106 inst |= am1 | a1reg;
3108 inst = (1 << 13) + (1 << 15);
3114 else if ((am1 == FPSCR) && (am0 < AM_USP))
3116 inst |= am0 | a0reg;
3118 inst = (0 << 13) + (1 << 15);
3125 return error("m_fmovescr says: wut?");
3129 // fsmove/fdmove (68040, 68060)
3131 int m_fsmove(WORD inst, WORD siz)
3133 if (!(activefpu & (FPU_68040 | FPU_68060)))
3134 return error("Unsupported in current FPU");
3136 return error("Not implemented yet.");
3139 if (activefpu == FPU_68040)
3140 return gen_fpu(inst, siz, B8(01100100), FPU_P_EMUL);
3142 return error("Unsupported in current FPU");
3147 int m_fdmove(WORD inst, WORD siz)
3149 if (!(activefpu & (FPU_68040 | FPU_68060)))
3150 return error("Unsupported in current FPU");
3152 return error("Not implemented yet.");
3155 if (activefpu == FPU_68040)
3156 return gen_fpu(inst, siz, B8(01100100), FPU_P_EMUL);
3158 return error("Unsupported in current FPU");
3164 // fmovecr (6888X, 68040FPSP, 68060FPSP)
3166 int m_fmovecr(WORD inst, WORD siz)
3176 if (activefpu == FPU_68040)
3177 warn("Instruction is emulated in 68040/060");
3184 // fmovem (6888X, 68040, 68060FPSP)
3186 int m_fmovem(WORD inst, WORD siz)
3193 if (siz == SIZX || siz == SIZN)
3195 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
3197 // fmovem.x <rlist>,ea
3198 if (fpu_reglist_left(®mask) < 0)
3202 return error("missing comma");
3207 inst |= am0 | a0reg;
3209 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3210 return error("invalid addressing mode");
3213 inst = (1 << 15) | (1 << 14) | (1 << 13) | (0 << 11) | regmask;
3218 else if ((*tok >= KW_D0) && (*tok <= KW_D7))
3221 datareg = (*tok++ & 7) << 10;
3224 return error("missing comma");
3229 inst |= am0 | a0reg;
3231 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3232 return error("invalid addressing mode");
3234 // Quote from the 060 manual:
3235 // "[..] when the processor attempts an FMOVEM.X instruction using a dynamic register list."
3236 if (activefpu == FPU_68060)
3237 warn("Instruction is emulated in 68060");
3240 inst = (1 << 15) | (1 << 14) | (1 << 13) | (1 << 11) | (datareg << 4);
3251 inst |= am0 | a0reg;
3254 return error("missing comma");
3256 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
3258 // fmovem.x ea,<rlist>
3259 if (fpu_reglist_right(®mask) < 0)
3263 inst = (1 << 15) | (1 << 14) | (0 << 13) | (2 << 11) | regmask;
3271 datareg = (*tok++ & 7) << 10;
3273 // Quote from the 060 manual:
3274 // "[..] when the processor attempts an FMOVEM.X instruction using a dynamic register list."
3275 if (activefpu == FPU_68060)
3276 warn("Instruction is emulated in 68060");
3279 inst = (1 << 15) | (1 << 14) | (0 << 13) | (3 << 11) | (datareg << 4);
3286 else if (siz == SIZL)
3288 if ((*tok == KW_FPCR) || (*tok == KW_FPSR) || (*tok == KW_FPIAR))
3290 // fmovem.l <rlist>,ea
3291 regmask = (1 << 15) | (1 << 13);
3292 int no_control_regs = 0;
3295 if (*tok == KW_FPCR)
3297 regmask |= (1 << 12);
3303 if (*tok == KW_FPSR)
3305 regmask |= (1 << 11);
3311 if (*tok == KW_FPIAR)
3313 regmask |= (1 << 10);
3319 if ((*tok == '/') || (*tok == '-'))
3326 return error("missing comma");
3331 // Quote from the 060 manual:
3332 // "[..] when the processor attempts to execute an FMOVEM.L instruction with
3333 // an immediate addressing mode to more than one floating - point
3334 // control register (FPCR, FPSR, FPIAR)[..]"
3335 if (activefpu == FPU_68060)
3336 if (no_control_regs > 1 && am0 == IMMED)
3337 warn("Instruction is emulated in 68060");
3339 inst |= am0 | a0reg;
3346 // fmovem.l ea,<rlist>
3350 inst |= am0 | a0reg;
3353 return error("missing comma");
3355 regmask = (1 << 15) | (0 << 13);
3358 if (*tok == KW_FPCR)
3360 regmask |= (1 << 12);
3365 if (*tok == KW_FPSR)
3367 regmask |= (1 << 11);
3372 if (*tok == KW_FPIAR)
3374 regmask |= (1 << 10);
3379 if ((*tok == '/') || (*tok == '-'))
3386 return error("extra (unexpected) text found");
3388 inst |= am0 | a0reg;
3395 return error("bad size suffix");
3402 // fmul (6888X, 68040, 68060)
3404 int m_fmul(WORD inst, WORD siz)
3407 return gen_fpu(inst, siz, B8(00100011), FPU_NOWARN);
3412 // fsmul (68040, 68060)
3414 int m_fsmul(WORD inst, WORD siz)
3416 if (activefpu & (FPU_68040 | FPU_68060))
3417 return gen_fpu(inst, siz, B8(01100011), FPU_NOWARN);
3419 return error("Unsupported in current FPU");
3426 int m_fdmul(WORD inst, WORD siz)
3428 if (activefpu & (FPU_68040 | FPU_68060))
3429 return gen_fpu(inst, siz, B8(01100111), FPU_NOWARN);
3431 return error("Unsupported in current FPU");
3436 // fneg (6888X, 68040, 68060)
3438 int m_fneg(WORD inst, WORD siz)
3445 return gen_fpu(inst, siz, B8(00011010), FPU_NOWARN);
3448 return gen_fpu(inst, siz, B8(00011010), FPU_NOWARN);
3453 // fsneg (68040, 68060)
3455 int m_fsneg(WORD inst, WORD siz)
3457 if (activefpu & (FPU_68040 | FPU_68060))
3462 return gen_fpu(inst, siz, B8(01011010), FPU_NOWARN);
3465 return gen_fpu(inst, siz, B8(01011010), FPU_NOWARN);
3468 return error("Unsupported in current FPU");
3473 // fdneg (68040, 68060)
3475 int m_fdneg(WORD inst, WORD siz)
3477 if (activefpu & (FPU_68040 | FPU_68060))
3482 return gen_fpu(inst, siz, B8(01011110), FPU_NOWARN);
3485 return gen_fpu(inst, siz, B8(01011110), FPU_NOWARN);
3488 return error("Unsupported in current FPU");
3493 // fnop (6888X, 68040, 68060)
3495 int m_fnop(WORD inst, WORD siz)
3498 return gen_fpu(inst, siz, B8(00000000), FPU_NOWARN);
3503 // frem (6888X, 68040FPSP, 68060FPSP)
3505 int m_frem(WORD inst, WORD siz)
3508 return gen_fpu(inst, siz, B8(00100101), FPU_FPSP);
3513 // fscale (6888X, 68040FPSP, 68060FPSP)
3515 int m_fscale(WORD inst, WORD siz)
3518 return gen_fpu(inst, siz, B8(00100110), FPU_FPSP);
3523 // FScc (6888X, 68040, 68060), cpScc (68851, 68030), PScc (68851)
3524 // TODO: Add check for PScc to ensure 68020+68851 active
3525 // TODO: Add check for cpScc to ensure 68020+68851, 68030
3527 int m_fscc(WORD inst, WORD siz)
3531 // We stash the 5 condition bits inside the opcode in 68ktab (bits 4-0),
3532 // so we need to extract them first and fill in the clobbered bits.
3533 WORD opcode = inst & 0x1F;
3535 inst |= am0 | a0reg;
3539 if (activefpu == FPU_68060)
3540 warn("Instruction is emulated in 68060");
3546 // fsgldiv (6888X, 68040FPSP, 68060FPSP)
3548 int m_fsgldiv(WORD inst, WORD siz)
3551 return gen_fpu(inst, siz, B8(00100100), FPU_FPSP);
3556 // fsglmul (6888X, 68040, 68060FPSP)
3558 int m_fsglmul(WORD inst, WORD siz)
3561 return gen_fpu(inst, siz, B8(00100111), FPU_FPSP);
3566 // fsin (6888X, 68040FPSP, 68060FPSP)
3568 int m_fsin(WORD inst, WORD siz)
3571 return gen_fpu(inst, siz, B8(00001110), FPU_FPSP);
3576 // fsincos (6888X, 68040FPSP, 68060FPSP)
3578 int m_fsincos(WORD inst, WORD siz)
3582 // Swap a1reg, a2reg as a2reg should be stored in the bitfield gen_fpu
3589 if (gen_fpu(inst, siz, B8(00110000), FPU_FPSP) == OK)
3600 // fsinh (6888X, 68040FPSP, 68060FPSP)
3602 int m_fsinh(WORD inst, WORD siz)
3605 return gen_fpu(inst, siz, B8(00000010), FPU_FPSP);
3610 // fsqrt (6888X, 68040, 68060)
3612 int m_fsqrt(WORD inst, WORD siz)
3615 return gen_fpu(inst, siz, B8(00000100), FPU_NOWARN);
3620 // fsfsqrt (68040, 68060)
3622 int m_fsfsqrt(WORD inst, WORD siz)
3624 if (activefpu & (FPU_68040 | FPU_68060))
3625 return gen_fpu(inst, siz, B8(01000001), FPU_NOWARN);
3627 return error("Unsupported in current FPU");
3632 // fdfsqrt (68040, 68060)
3634 int m_fdfsqrt(WORD inst, WORD siz)
3636 if (activefpu & (FPU_68040 | FPU_68060))
3637 return gen_fpu(inst, siz, B8(01000101), FPU_NOWARN);
3639 return error("Unsupported in current FPU");
3644 // fsub (6888X, 68040, 68060)
3646 int m_fsub(WORD inst, WORD siz)
3649 return gen_fpu(inst, siz, B8(00101000), FPU_NOWARN);
3654 // fsfsub (68040, 68060)
3656 int m_fsfsub(WORD inst, WORD siz)
3658 if (activefpu & (FPU_68040 | FPU_68060))
3659 return gen_fpu(inst, siz, B8(01101000), FPU_NOWARN);
3661 return error("Unsupported in current FPU");
3666 // fdfsub (68040, 68060)
3668 int m_fdsub(WORD inst, WORD siz)
3670 if (activefpu & (FPU_68040 | FPU_68060))
3671 return gen_fpu(inst, siz, B8(01101100), FPU_NOWARN);
3673 return error("Unsupported in current FPU");
3678 // ftan (6888X, 68040FPSP, 68060FPSP)
3680 int m_ftan(WORD inst, WORD siz)
3683 return gen_fpu(inst, siz, B8(00001111), FPU_FPSP);
3688 // ftanh (6888X, 68040FPSP, 68060FPSP)
3690 int m_ftanh(WORD inst, WORD siz)
3693 return gen_fpu(inst, siz, B8(00001001), FPU_FPSP);
3698 // ftentox (6888X, 68040FPSP, 68060FPSP)
3700 int m_ftentox(WORD inst, WORD siz)
3703 return gen_fpu(inst, siz, B8(00010010), FPU_FPSP);
3708 // FTRAPcc (6888X, 68040, 68060FPSP)
3710 int m_ftrapcc(WORD inst, WORD siz)
3714 // We stash the 5 condition bits inside the opcode in 68ktab (bits 3-7),
3715 // so we need to extract them first and fill in the clobbered bits.
3716 WORD opcode = (inst >> 3) & 0x1F;
3717 inst = (inst & 0xFF07) | (0xF << 3);
3726 else if (siz == SIZL)
3733 else if (siz == SIZN)
3741 if (activefpu == FPU_68060)
3742 warn("Instruction is emulated in 68060");
3749 // ftst (6888X, 68040, 68060)
3751 int m_ftst(WORD inst, WORD siz)
3754 return gen_fpu(inst, siz, B8(00111010), FPU_NOWARN);
3759 // ftwotox (6888X, 68040FPSP, 68060FPSP)
3761 int m_ftwotox(WORD inst, WORD siz)
3764 return gen_fpu(inst, siz, B8(00010001), FPU_FPSP);
3768 /////////////////////////////////
3770 // 68060 specific instructions //
3772 /////////////////////////////////
3778 int m_lpstop(WORD inst, WORD siz)
3781 D_word(B16(00000001, 11000000));
3783 if (a0exattr&DEFINED)
3787 AddFixup(FU_WORD, sloc, a0expr);
3798 int m_plpa(WORD inst, WORD siz)
3801 inst |= a0reg; // Install register