2 // RMAC - Reboot's Macro Assembler for all Atari computers
3 // MACH.C - Code Generation
4 // Copyright (C) 199x Landon Dyer, 2011-2019 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);
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_fbcc(WORD inst, WORD siz);
96 int m_facos(WORD inst, WORD siz);
97 int m_fadd(WORD inst, WORD siz);
98 int m_fasin(WORD inst, WORD siz);
99 int m_fatan(WORD inst, WORD siz);
100 int m_fatanh(WORD inst, WORD siz);
101 int m_fcmp(WORD inst, WORD siz);
102 int m_fcos(WORD inst, WORD siz);
103 int m_fcosh(WORD inst, WORD siz);
104 int m_fdabs(WORD inst, WORD siz);
105 int m_fdadd(WORD inst, WORD siz);
106 int m_fdbcc(WORD inst, WORD siz);
107 int m_fddiv(WORD inst, WORD siz);
108 int m_fdfsqrt(WORD inst, WORD siz);
109 int m_fdiv(WORD inst, WORD siz);
110 int m_fdmove(WORD inst, WORD siz);
111 int m_fdmul(WORD inst, WORD siz);
112 int m_fdneg(WORD inst, WORD siz);
113 int m_fdsub(WORD inst, WORD siz);
114 int m_fetox(WORD inst, WORD siz);
115 int m_fetoxm1(WORD inst, WORD siz);
116 int m_fgetexp(WORD inst, WORD siz);
117 int m_fgetman(WORD inst, WORD siz);
118 int m_fint(WORD inst, WORD siz);
119 int m_fintrz(WORD inst, WORD siz);
120 int m_flog10(WORD inst, WORD siz);
121 int m_flog2(WORD inst, WORD siz);
122 int m_flogn(WORD inst, WORD siz);
123 int m_flognp1(WORD inst, WORD siz);
124 int m_fmod(WORD inst, WORD siz);
125 int m_fmove(WORD inst, WORD siz);
126 int m_fmovescr(WORD inst, WORD siz);
127 int m_fmovecr(WORD inst, WORD siz);
128 int m_fmovem(WORD inst, WORD siz);
129 int m_fmul(WORD inst, WORD siz);
130 int m_fneg(WORD inst, WORD siz);
131 int m_fnop(WORD inst, WORD siz);
132 int m_frem(WORD inst, WORD siz);
133 int m_frestore(WORD inst, WORD siz);
134 int m_fsabs(WORD inst, WORD siz);
135 int m_fsadd(WORD inst, WORD siz);
136 int m_fscc(WORD inst, WORD siz);
137 int m_fscale(WORD inst, WORD siz);
138 int m_fsdiv(WORD inst, WORD siz);
139 int m_fsfsqrt(WORD inst, WORD siz);
140 int m_fsfsub(WORD inst, WORD siz);
141 int m_fsgldiv(WORD inst, WORD siz);
142 int m_fsglmul(WORD inst, WORD siz);
143 int m_fsin(WORD inst, WORD siz);
144 int m_fsincos(WORD inst, WORD siz);
145 int m_fsinh(WORD inst, WORD siz);
146 int m_fsmove(WORD inst, WORD siz);
147 int m_fsmul(WORD inst, WORD siz);
148 int m_fsneg(WORD inst, WORD siz);
149 int m_fsqrt(WORD inst, WORD siz);
150 int m_fsub(WORD inst, WORD siz);
151 int m_ftan(WORD inst, WORD siz);
152 int m_ftanh(WORD inst, WORD siz);
153 int m_ftentox(WORD inst, WORD siz);
154 int m_ftst(WORD inst, WORD siz);
155 int m_ftwotox(WORD inst, WORD siz);
156 int m_ftrapcc(WORD inst, WORD siz);
158 // Common error messages
159 char range_error[] = "expression out of range";
160 char abs_error[] = "illegal absolute expression";
161 char seg_error[] = "bad (section) expression";
162 char rel_error[] = "illegal relative address";
163 char siz_error[] = "bad size specified";
164 char undef_error[] = "undefined expression";
165 char fwd_error[] = "forward or undefined expression";
166 char unsupport[] = "unsupported for selected CPU";
168 // Include code tables
170 { 0xFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000, 0, m_badmode }, // 0
172 { 0, 0L, 0L, 0x0000, 0, m_unimp } // Last entry
175 // Register number << 9
177 0, 1 << 9, 2 << 9, 3 << 9, 4 << 9, 5 << 9, 6 << 9, 7 << 9
180 // SIZB==>00, SIZW==>01, SIZL==>10, SIZN==>01 << 6
184 1<<6, (WORD)-1, // SIZW, n/a
185 2<<6, (WORD)-1, (WORD)-1, (WORD)-1, // SIZL, n/a, n/a, n/a
189 // Byte/word/long size for MOVE instrs
193 0x3000, (WORD)-1, // Word
194 0x2000, (WORD)-1, (WORD)-1, (WORD)-1, // Long
195 0x3000 // Word (SIZN)
198 // Word/long size (0=.w, 1=.l) in bit 8
202 0, (WORD)-1, // SIZW, n/a
203 1<<8, (WORD)-1, (WORD)-1, (WORD)-1, // SIZL, n/a, n/a, n/a
207 // Byte/Word/long size (0=.w, 1=.l) in bit 9
211 1<<9, (WORD)-1, // Word
212 1<<10, (WORD)-1, (WORD)-1, (WORD)-1, // Long
216 // Addressing mode in bits 6..11 (register/mode fields are reversed)
218 00000, 01000, 02000, 03000, 04000, 05000, 06000, 07000,
219 00100, 01100, 02100, 03100, 04100, 05100, 06100, 07100,
220 00200, 01200, 02200, 03200, 04200, 05200, 06200, 07200,
221 00300, 01300, 02300, 03300, 04300, 05300, 06300, 07300,
222 00400, 01400, 02400, 03400, 04400, 05400, 06400, 07400,
223 00500, 01500, 02500, 03500, 04500, 05500, 06500, 07500,
224 00600, 01600, 02600, 03600, 04600, 05600, 06600, 07600,
225 00700, 01700, 02700, 03700, 04700, 05700, 06700, 07700
228 // Control registers lookup table
230 // MC68010/MC68020/MC68030/MC68040/CPU32
231 0x000, // Source Function Code(SFC)
232 0x001, // Destination Function Code(DFC)
233 0x800, // User Stack Pointer(USP)
234 0x801, // Vector Base Register(VBR)
235 // MC68020 / MC68030 / MC68040
236 0x002, // Cache Control Register(CACR)
237 0x802, // Cache Address Register(CAAR) (020/030 only)
238 0x803, // Master Stack Pointer(MSP)
239 0x804, // Interrupt Stack Pointer(ISP)
240 // MC68040 / MC68LC040
241 0x003, // MMU Translation Control Register(TC)
242 0x004, // Instruction Transparent Translation Register 0 (ITT0)
243 0x005, // Instruction Transparent Translation Register 1 (ITT1)
244 0x006, // Data Transparent Translation Register 0 (DTT0)
245 0x007, // Data Transparent Translation Register 1 (DTT1)
246 0x805, // MMU Status Register(MMUSR)
247 0x806, // User Root Pointer(URP)
248 0x807, // Supervisor Root Pointer(SRP)
250 0x004, // Instruction Access Control Register 0 (IACR0)
251 0x005, // Instruction Access Control Register 1 (IACR1)
252 0x006, // Data Access Control Register 0 (DACR1)
253 0x007, // Data Access Control Register 1 (DACR1)
255 0xFFF // CPU Root Pointer (CRP) - There's no movec with CRP in it, this is just a guard entry
260 int m_unimp(WORD unused1, WORD unused2)
262 return (int)error("unimplemented mnemonic");
266 //int m_badmode(void)
267 int m_badmode(WORD unused1, WORD unused2)
269 return (int)error("inappropriate addressing mode");
273 int m_self(WORD inst, WORD usused)
281 // Do one EA in bits 0..5
283 // Bits in `inst' have the following meaning:
285 // Bit zero specifies which ea (ea0 or ea1) to generate in the lower six bits
288 // If bit one is set, the OTHER ea (the one that wasn't generated by bit zero)
289 // is generated after the instruction. Regardless of bit 0's value, ea0 is
290 // always deposited in memory before ea1.
292 // If bit two is set, standard size bits are set in the instr in bits 6 and 7.
294 // If bit four is set, bit three specifies which eaXreg to place in bits 9..11
297 int m_ea(WORD inst, WORD siz)
299 WORD flg = inst; // Save flag bits
300 inst &= ~0x3F; // Clobber flag bits in instr
302 // Install "standard" instr size bits
308 // OR-in register number
310 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
312 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
318 inst |= am1 | a1reg; // Get ea1 into instr
319 D_word(inst); // Deposit instr
321 // Generate ea0 if requested
325 ea1gen(siz); // Generate ea1
330 inst |= am0 | a0reg; // Get ea0 into instr
331 D_word(inst); // Deposit instr
332 ea0gen(siz); // Generate ea0
334 // Generate ea1 if requested
344 // Check if lea x(an),an can be optimised to addq.w #x,an--otherwise fall back
347 int m_lea(WORD inst, WORD siz)
349 if (CHECK_OPTS(OPT_LEA_ADDQ)
350 && ((am0 == ADISP) && (a0reg == a1reg) && (a0exattr & DEFINED))
351 && ((a0exval > 0) && (a0exval <= 8)))
353 inst = B16(01010000, 01001000) | (((uint16_t)a0exval & 7) << 9) | (a0reg);
355 warn("lea size(An),An converted to addq #size,An");
359 return m_ea(inst, siz);
363 int m_ea030(WORD inst, WORD siz)
366 WORD flg = inst; // Save flag bits
367 inst &= ~0x3F; // Clobber flag bits in instr
369 // Install "standard" instr size bits
375 // OR-in register number
378 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
382 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
389 inst |= am1 | a1reg; // Get ea1 into instr
390 D_word(inst); // Deposit instr
392 // Generate ea0 if requested
396 ea1gen(siz); // Generate ea1
402 // We get here if we're doing 020+ addressing and an address
403 // register is used. For example, something like "tst a0". A bit of
404 // a corner case, so kludge it
406 else if (am0 == PCDISP)
407 // Another corner case (possibly!), so kludge ahoy
408 inst |= am0; // Get ea0 into instr
409 else if (am0 == IMMED && am1 == MEMPOST)
411 // Added for addi/andi/cmpi/eori/ori/subi #xx,(bd,An,Dm)
412 inst |= a1reg | AINDEXED;
414 else if (am0 == IMMED)
415 inst |= am0 | a0reg; // Get ea0 into instr
416 else if (am0 == AM_CCR)
418 else if (am0 == AIND)
421 inst |= a0reg; // Get ea0 into instr
422 D_word(inst); // Deposit instr
423 ea0gen(siz); // Generate ea0
425 // Generate ea1 if requested
435 // Dx,Dy nnnnXXXnssnnnYYY If bit 0 of `inst' is set, install size bits in bits
438 int m_abcd(WORD inst, WORD siz)
447 inst |= a0reg | reg_9[a1reg];
457 int m_adda(WORD inst, WORD siz)
459 if (a0exattr & DEFINED)
461 if (CHECK_OPTS(OPT_ADDA_ADDQ))
462 if (a0exval > 1 && a0exval <= 8)
463 // Immediate is between 1 and 8 so let's convert to addq
464 return m_addq(B16(01010000, 00000000), siz);
465 if (CHECK_OPTS(OPT_ADDA_LEA))
468 // Immediate is larger than 8 so let's convert to lea
469 am0 = ADISP; // Change addressing mode
470 a0reg = a1reg; // In ADISP a0reg is used instead of a1reg!
471 return m_lea(B16(01000001, 11011000), SIZW);
475 inst |= am0 | a0reg | lwsiz_8[siz] | reg_9[a1reg];
477 ea0gen(siz); // Generate EA
484 // If bit 0 of `inst' is 1, install size bits in bits 6..7 of instr.
485 // If bit 1 of `inst' is 1, install a1reg in bits 9..11 of instr.
487 int m_reg(WORD inst, WORD siz)
494 // Install other register (9..11)
495 inst |= reg_9[a1reg];
497 inst &= ~7; // Clear off crufty bits
498 inst |= a0reg; // Install first register
508 int m_imm(WORD inst, WORD siz)
520 int m_imm8(WORD inst, WORD siz)
533 int m_shr(WORD inst, WORD siz)
535 inst |= reg_9[a0reg] | a1reg | siz_6[siz];
545 int m_shi(WORD inst, WORD siz)
547 inst |= a1reg | siz_6[siz];
549 if (a0exattr & DEFINED)
552 return error(range_error);
554 inst |= (a0exval & 7) << 9;
559 AddFixup(FU_QUICK, sloc, a0expr);
568 // {bset, btst, bchg, bclr} -- #immed,ea -- Dn,ea
570 int m_bitop(WORD inst, WORD siz)
572 // Enforce instruction sizes
574 { // X,Dn must be .n or .l
575 if (siz & (SIZB | SIZW))
576 return error(siz_error);
578 else if (siz & (SIZW | SIZL)) // X,ea must be .n or .b
579 return error(siz_error);
581 // Construct instr and EAs
587 ea0gen(SIZB); // Immediate bit number
591 inst |= reg_9[a0reg];
602 int m_dbra(WORD inst, WORD siz)
608 if (a1exattr & DEFINED)
610 if ((a1exattr & TDB) != cursect)
611 return error(rel_error);
613 uint32_t v = (uint32_t)a1exval - sloc;
615 if (v + 0x8000 > 0x10000)
616 return error(range_error);
622 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
633 int m_exg(WORD inst, WORD siz)
639 if (am0 == DREG && am1 == DREG)
641 else if (am0 == AREG && am1 == AREG)
647 m = a1reg; // Get AREG into a1reg
655 inst |= m | reg_9[a0reg] | a1reg;
665 int m_link(WORD inst, WORD siz)
669 // Is this an error condition???
674 inst &= ~((3 << 9) | (1 << 6) | (1 << 4));
686 WORD extra_addressing[16]=
688 0x30, // 0100 (bd,An,Xn)
689 0x30, // 0101 ([bd,An],Xn,od)
690 0x30, // 0102 ([bc,An,Xn],od)
691 0x30, // 0103 (bd,PC,Xn)
692 0x30, // 0104 ([bd,PC],Xn,od)
693 0x30, // 0105 ([bc,PC,Xn],od)
708 // Handle MOVE <C_ALL> <C_ALTDATA>
709 // MOVE <C_ALL> <M_AREG>
711 // Optimize MOVE.L #<smalldata>,D0 to a MOVEQ
713 int m_move(WORD inst, WORD size)
715 // Cast the passed in value to an int
718 // Try to optimize to MOVEQ
719 // N.B.: We can get away with casting the uint64_t to a 32-bit value
720 // because it checks for a SIZL (i.e., a 32-bit value).
721 if (CHECK_OPTS(OPT_MOVEL_MOVEQ)
722 && (siz == SIZL) && (am0 == IMMED) && (am1 == DREG)
723 && ((a0exattr & (TDB | DEFINED)) == DEFINED)
724 && ((uint32_t)a0exval + 0x80 < 0x100))
726 m_moveq((WORD)0x7000, (WORD)0);
729 warn("move.l #size,dx converted to moveq");
733 if ((am0 < ABASE) && (am1 < ABASE)) // 68000 modes
735 inst |= siz_12[siz] | am_6[am1] | reg_9[a1reg] | am0 | a0reg;
743 ea1gen((WORD)siz | 0x8000); // Tell ea1gen we're move ea,ea
747 inst |= siz_12[siz] | reg_9[a1reg] | extra_addressing[am0 - ABASE];
764 // Handle MOVE <C_ALL030> <C_ALTDATA>
765 // MOVE <C_ALL030> <M_AREG>
767 int m_move30(WORD inst, WORD size)
770 inst |= siz_12[siz] | reg_9[a1reg & 7] | a0reg | extra_addressing[am0 - ABASE];
785 // move USP,An -- move An,USP
787 int m_usp(WORD inst, WORD siz)
792 inst |= a1reg; // USP, An
794 inst |= a0reg; // An, USP
805 int m_moveq(WORD inst, WORD siz)
809 // Arrange for future fixup
810 if (!(a0exattr & DEFINED))
812 AddFixup(FU_BYTE | FU_SEXT, sloc + 1, a0expr);
815 else if ((uint32_t)a0exval + 0x100 >= 0x200)
816 return error(range_error);
818 inst |= reg_9[a1reg] | (a0exval & 0xFF);
826 // movep Dn, disp(An) -- movep disp(An), Dn
828 int m_movep(WORD inst, WORD siz)
830 // Tell ea0gen to lay off the 0(a0) optimisations on this one
838 inst |= reg_9[a0reg] | a1reg;
848 inst |= reg_9[a1reg] | a0reg;
865 int m_br(WORD inst, WORD siz)
867 if (a0exattr & DEFINED)
869 if ((a0exattr & TDB) != cursect)
871 //printf("m_br(): a0exattr = %X, cursect = %X, a0exval = %X, sloc = %X\n", a0exattr, cursect, a0exval, sloc);
872 return error(rel_error);
875 uint32_t v = (uint32_t)a0exval - (sloc + 2);
877 // Optimize branch instr. size
880 if (CHECK_OPTS(OPT_BSR_BCC_S) && (v != 0) && ((v + 0x80) < 0x100))
887 warn("Bcc.w/BSR.w converted to .s");
894 if ((v + 0x8000) > 0x10000)
895 return error(range_error);
903 if (siz == SIZB || siz == SIZS)
905 if ((v + 0x80) >= 0x100)
906 return error(range_error);
913 if ((v + 0x8000) >= 0x10000)
914 return error(range_error);
922 else if (siz == SIZN)
925 if (siz == SIZB || siz == SIZS)
928 AddFixup(FU_BBRA | FU_PCREL | FU_SEXT, sloc, a0expr);
936 AddFixup(FU_WORD | FU_PCREL | FU_LBRA | FU_ISBRA, sloc, a0expr);
947 int m_addq(WORD inst, WORD siz)
949 inst |= siz_6[siz] | am1 | a1reg;
951 if (a0exattr & DEFINED)
953 if ((a0exval > 8) || (a0exval == 0)) // Range in 1..8
954 return error(range_error);
956 inst |= (a0exval & 7) << 9;
961 AddFixup(FU_QUICK, sloc, a0expr);
974 int m_trap(WORD inst, WORD siz)
978 if (a0exattr & DEFINED)
981 return error(abs_error);
984 return error(range_error);
990 return error(undef_error);
997 // movem <rlist>,ea -- movem ea,<rlist>
999 int m_movem(WORD inst, WORD siz)
1007 return error("bad size suffix");
1014 // Handle #<expr>, ea
1017 if (abs_expr(&eval) != OK)
1020 if (eval >= 0x10000L)
1021 return error(range_error);
1027 if ((*tok >= KW_D0) && (*tok <= KW_A7))
1030 if (reglist(&rmask) < 0)
1035 return error("missing comma");
1040 inst |= am0 | a0reg;
1042 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
1043 return error("invalid addressing mode");
1045 // If APREDEC, reverse register mask
1051 for(i=0x8000; i; i>>=1, w>>=1)
1052 rmask = (WORD)((rmask << 1) | (w & 1));
1061 inst |= 0x0400 | am0 | a0reg;
1064 return error("missing comma");
1067 return error("missing register list");
1074 if (abs_expr(&eval) != OK)
1077 if (eval >= 0x10000)
1078 return error(range_error);
1082 else if (reglist(&rmask) < 0)
1085 if (!(amsktab[am0] & (C_CTRL | M_APOSTINC)))
1086 return error("invalid addressing mode");
1098 // CLR.x An ==> SUBA.x An,An
1100 int m_clra(WORD inst, WORD siz)
1102 inst |= a0reg | reg_9[a0reg] | lwsiz_8[siz];
1110 // CLR.L Dn ==> CLR.L An or MOVEQ #0,Dx
1112 int m_clrd(WORD inst, WORD siz)
1114 if (!CHECK_OPTS(OPT_CLR_DX))
1117 inst = (a0reg << 9) | B16(01110000, 00000000);
1125 ////////////////////////////////////////
1127 // 68020/30/40/60 instructions
1129 ////////////////////////////////////////
1134 int m_br30(WORD inst, WORD siz)
1136 if (a0exattr & DEFINED)
1138 if ((a0exattr & TDB) != cursect)
1139 return error(rel_error);
1141 uint32_t v = (uint32_t)a0exval - (sloc + 2);
1150 AddFixup(FU_LONG | FU_PCREL | FU_SEXT, sloc, a0expr);
1158 // bfchg, bfclr, bfexts, bfextu, bfffo, bfins, bfset
1159 // (68020, 68030, 68040)
1161 int m_bfop(WORD inst, WORD siz)
1163 if ((bfval1 > 31) || (bfval1 < 0))
1164 return error("bfxxx offset: immediate value must be between 0 and 31");
1166 // First instruction word - just the opcode and first EA
1167 // Note: both am1 is ORed because solely of bfins - maybe it's a good idea
1168 // to make a dedicated function for it?
1175 if (bfval2 > 31 || bfval2 < 0)
1176 return error("bfxxx width: immediate value must be between 0 and 31");
1178 // For Dw both immediate and register number are stuffed
1179 // into the same field O_o
1180 bfparam2 = (bfval2 << 0);
1184 bfparam1 = (bfval1 << 6);
1186 bfparam1 = bfval1 << 12;
1188 //D_word((inst | am0 | a0reg | am1 | a1reg));
1189 if (inst == B16(11101111, 11000000))
1191 // bfins special case
1192 D_word((inst | am1 | a1reg));
1196 D_word((inst | am0 | a0reg));
1199 ea0gen(siz); // Generate EA
1201 // Second instruction word - Dest register (if exists), Do, Offset, Dw, Width
1202 if (inst == B16(11101111, 11000000))
1204 // bfins special case
1205 inst = bfparam1 | bfparam2;
1208 inst |= a0reg << 12;
1214 inst = bfparam1 | bfparam2;
1220 inst |= a1reg << 12;
1230 // bkpt (68EC000, 68010, 68020, 68030, 68040, CPU32)
1232 int m_bkpt(WORD inst, WORD siz)
1236 if (a0exattr & DEFINED)
1239 return error(abs_error);
1242 return error(range_error);
1248 return error(undef_error);
1257 int m_callm(WORD inst, WORD siz)
1264 if (a0exattr & DEFINED)
1267 return error(abs_error);
1270 return error(range_error);
1272 inst = (uint16_t)a0exval;
1276 return error(undef_error);
1286 // cas (68020, 68030, 68040)
1288 int m_cas(WORD inst, WORD siz)
1294 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1295 return error(unsupport);
1310 return error("bad size suffix");
1315 if ((*tok < KW_D0) && (*tok > KW_D7))
1316 return error("CAS accepts only data registers");
1318 inst2 = (*tok++) & 7;
1321 return error("missing comma");
1324 if ((*tok < KW_D0) && (*tok > KW_D7))
1325 return error("CAS accepts only data registers");
1327 inst2 |= ((*tok++) & 7) << 6;
1330 return error("missing comma");
1333 if ((modes = amode(1)) < 0)
1337 return error("too many ea fields");
1340 return error("extra (unexpected) text found");
1342 // Reject invalid ea modes
1343 amsk = amsktab[am0];
1345 if ((amsk & (M_AIND | M_APOSTINC | M_APREDEC | M_ADISP | M_AINDEXED | M_ABSW | M_ABSL | M_ABASE | M_MEMPOST | M_MEMPRE)) == 0)
1346 return error("unsupported addressing mode");
1348 inst |= am0 | a0reg;
1358 // cas2 (68020, 68030, 68040)
1360 int m_cas2(WORD inst, WORD siz)
1364 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1365 return error(unsupport);
1380 return error("bad size suffix");
1385 if ((*tok < KW_D0) && (*tok > KW_D7))
1386 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1388 inst2 = (*tok++) & 7;
1391 return error("missing colon");
1394 if ((*tok < KW_D0) && (*tok > KW_D7))
1395 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1397 inst3 = (*tok++) & 7;
1400 return error("missing comma");
1403 if ((*tok < KW_D0) && (*tok > KW_D7))
1404 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1406 inst2 |= ((*tok++) & 7) << 6;
1409 return error("missing colon");
1412 if ((*tok < KW_D0) && (*tok > KW_D7))
1413 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1415 inst3 |= ((*tok++) & 7) << 6;
1418 return error("missing comma");
1422 return error("missing (");
1423 if ((*tok >= KW_D0) && (*tok <= KW_D7))
1424 inst2 |= (((*tok++) & 7) << 12) | (0 << 15);
1425 else if ((*tok >= KW_A0) && (*tok <= KW_A7))
1426 inst2 |= (((*tok++) & 7) << 12) | (1 << 15);
1428 return error("CAS accepts either data or address registers for Rn1:Rn2 pair");
1431 return error("missing (");
1434 return error("missing colon");
1438 return error("missing (");
1439 if ((*tok >= KW_D0) && (*tok <= KW_D7))
1440 inst3 |= (((*tok++) & 7) << 12) | (0 << 15);
1441 else if ((*tok >= KW_A0) && (*tok <= KW_A7))
1442 inst3 |= (((*tok++) & 7) << 12) | (1 << 15);
1444 return error("CAS accepts either data or address registers for Rn1:Rn2 pair");
1447 return error("missing (");
1450 return error("extra (unexpected) text found");
1461 // cmp2 (68020, 68030, 68040, CPU32)
1463 int m_cmp2(WORD inst, WORD siz)
1465 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1466 return error(unsupport);
1468 switch (siz & 0x000F)
1482 WORD flg = inst; // Save flag bits
1483 inst &= ~0x3F; // Clobber flag bits in instr
1485 // Install "standard" instr size bits
1491 // OR-in register number
1493 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1495 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1501 inst |= am1 | a1reg; // Get ea1 into instr
1502 D_word(inst); // Deposit instr
1504 // Generate ea0 if requested
1508 ea1gen(siz); // Generate ea1
1513 inst |= am0 | a0reg; // Get ea0 into instr
1514 D_word(inst); // Deposit instr
1515 ea0gen(siz); // Generate ea0
1517 // Generate ea1 if requested
1522 // If we're called from chk2 then bit 11 of size will be set. This is just
1523 // a dumb mechanism to pass this, required by the extension word. (You might
1524 // have noticed the siz & 15 thing above!)
1525 inst = (a1reg << 12) | (siz & (1 << 11));
1537 // chk2 (68020, 68030, 68040, CPU32)
1539 int m_chk2(WORD inst, WORD siz)
1541 return m_cmp2(inst, siz | (1 << 11));
1546 // cpbcc(68020, 68030, 68040 (FBcc), 68060 (FBcc)), pbcc (68851)
1548 int m_fpbr(WORD inst, WORD siz)
1551 if (a0exattr & DEFINED)
1553 if ((a0exattr & TDB) != cursect)
1554 return error(rel_error);
1556 uint32_t v = (uint32_t)a0exval - (sloc + 2);
1558 // Optimize branch instr. size
1561 if ((v != 0) && ((v + 0x8000) < 0x10000))
1571 if ((v + 0x8000) >= 0x10000)
1572 return error(range_error);
1580 else if (siz == SIZN)
1587 AddFixup(FU_LONG | FU_PCREL | FU_SEXT, sloc, a0expr);
1595 AddFixup(FU_WORD | FU_PCREL | FU_SEXT, sloc, a0expr);
1604 // cpbcc(68020, 68030, 68040 (FBcc), 68060 (FBcc))
1606 int m_cpbcc(WORD inst, WORD siz)
1608 if (!(activecpu & (CPU_68020 | CPU_68030)))
1609 return error(unsupport);
1611 return m_fpbr(inst, siz);
1616 // fbcc(6808X, 68040, 68060)
1618 int m_fbcc(WORD inst, WORD siz)
1621 return m_fpbr(inst, siz);
1626 // pbcc(68851 but let's assume 68020 only)
1628 int m_pbcc(WORD inst, WORD siz)
1631 return m_fpbr(inst, siz);
1636 // cpdbcc(68020, 68030)
1638 int m_cpdbr(WORD inst, WORD siz)
1643 WORD condition = inst & 0x1F; // Grab condition sneakily placed in the lower 5 bits of inst
1644 inst &= 0xFFE0; // And then mask them out - you ain't seen me, roit?
1646 inst |= (1 << 9); // Bolt on FPU id
1653 if (a1exattr & DEFINED)
1655 if ((a1exattr & TDB) != cursect)
1656 return error(rel_error);
1658 v = (uint32_t)a1exval - sloc;
1660 if (v + 0x8000 > 0x10000)
1661 return error(range_error);
1667 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
1677 // muls.l / divs.l / divu.l / mulu.l (68020+)
1679 int m_muls(WORD inst, WORD siz)
1681 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1682 return error(unsupport);
1684 WORD flg = inst; // Save flag bits
1685 inst &= ~0x33F; // Clobber flag and extension bits in instr
1687 // Install "standard" instr size bits
1693 // OR-in register number
1695 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1697 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1700 // Regarding extension word: bit 11 is signed/unsigned selector
1701 // bit 10 is 32/64 bit selector
1702 // Both of these are packed in bits 9 and 8 of the instruction
1703 // field in 68ktab. Extra compilcations arise from the fact we
1704 // have to distinguish between divu/s.l Dn,Dm (which is encoded
1705 // as divu/s.l Dn,Dm:Dm) and divu/s.l Dn,Dm:Dx - the first is
1706 // 32 bit while the second 64 bit
1711 inst |= am1 | a1reg; // Get ea1 into instr
1712 D_word(inst); // Deposit instr
1716 inst = a1reg + (a2reg << 12) + ((flg & 0x200) << 2);
1718 inst = a1reg + (a2reg << 12) + ((flg & 0x300) << 2);
1722 // Generate ea0 if requested
1726 ea1gen(siz); // Generate ea1
1733 inst |= am0 | a0reg; // Get ea0 into instr
1734 D_word(inst); // Deposit instr
1738 inst = a1reg + (a2reg << 12) + ((flg & 0x200) << 2);
1740 inst = a1reg + (a2reg << 12) + ((flg & 0x300) << 2);
1744 ea0gen(siz); // Generate ea0
1746 // Generate ea1 if requested
1756 // move16 (ax)+,(ay)+
1758 int m_move16a(WORD inst, WORD siz)
1760 if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1761 return error(unsupport);
1765 inst = (1 << 15) + (a1reg << 12);
1773 // move16 with absolute address
1775 int m_move16b(WORD inst, WORD siz)
1777 if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1778 return error(unsupport);
1784 if (am0 == APOSTINC)
1787 return error("Wasn't this suppose to call m_move16a???");
1790 // move16 (ax)+,(xxx).L
1795 else if (am0 == ABSL)
1799 // move16 (xxx).L,(ax)+
1805 // move16 (xxx).L,(ax)
1810 else if (am0 == AIND)
1812 // move16 (ax),(xxx).L
1825 // pack/unpack (68020/68030/68040)
1827 int m_pack(WORD inst, WORD siz)
1832 return error("bad size suffix");
1834 if (*tok >= KW_D0 && *tok <= KW_D7)
1836 // Dx,Dy,#<adjustment>
1837 inst |= (0 << 3); // R/M
1838 inst |= (*tok++ & 7);
1840 if (*tok != ',' && tok[2] != ',')
1841 return error("missing comma");
1843 if (tok[1] < KW_D0 && tok[1] > KW_D7)
1844 return error(syntax_error);
1846 inst |= ((tok[1] & 7)<<9);
1849 // Fall through for adjustment (common in both valid cases)
1851 else if (*tok == '-')
1853 // -(Ax),-(Ay),#<adjustment>
1854 inst |= (1 << 3); // R/M
1855 tok++; // eat the minus
1857 if ((*tok != '(') && (tok[2]!=')') && (tok[3]!=',') && (tok[4] != '-') && (tok[5] != '(') && (tok[7] != ')') && (tok[8] != ','))
1858 return error(syntax_error);
1860 if (tok[1] < KW_A0 && tok[1] > KW_A7)
1861 return error(syntax_error);
1863 if (tok[5] < KW_A0 && tok[6] > KW_A7)
1864 return error(syntax_error);
1866 inst |= ((tok[1] & 7) << 0);
1867 inst |= ((tok[6] & 7) << 9);
1870 // Fall through for adjustment (common in both valid cases)
1873 return error("invalid syntax");
1875 if ((*tok != CONST) && (*tok != SYMBOL) && (*tok != '-'))
1876 return error(syntax_error);
1878 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
1881 if ((a0exattr & DEFINED) == 0)
1882 return error(undef_error);
1884 if (a0exval + 0x8000 > 0x10000)
1888 return error(extra_stuff);
1890 D_word((a0exval & 0xFFFF));
1899 int m_rtm(WORD inst, WORD siz)
1907 else if (am0 == AREG)
1909 inst |= (1 << 3) + a0reg;
1912 return error("rtm only allows data or address registers.");
1923 int m_rtd(WORD inst, WORD siz)
1927 if (a0exattr & DEFINED)
1930 return error(abs_error);
1932 if ((a0exval + 0x8000) <= 0x7FFF)
1933 return error(range_error);
1939 return error(undef_error);
1948 int m_trapcc(WORD inst, WORD siz)
1956 else if (am0 == IMMED)
1960 if (a0exval < 0x10000)
1967 return error("Immediate value too big");
1977 return error("Invalid parameter for trapcc");
1984 // cinvl/p/a (68040/68060)
1986 int m_cinv(WORD inst, WORD siz)
1991 inst |= (0 << 6) | (a1reg);
1995 inst |= (2 << 6) | (a1reg);
1998 inst |= (1 << 6) | (a1reg);
2001 inst |= (3 << 6) | (a1reg);
2010 int m_fpusavrest(WORD inst, WORD siz)
2012 inst |= am0 | a0reg;
2021 // cpSAVE/cpRESTORE (68020, 68030)
2023 int m_cprest(WORD inst, WORD siz)
2025 if (activecpu & !(CPU_68020 | CPU_68030))
2026 return error(unsupport);
2028 return m_fpusavrest(inst, siz);
2034 // FSAVE/FRESTORE (68040, 68060)
2036 int m_frestore(WORD inst, WORD siz)
2038 if ((!(activecpu & (CPU_68040 | CPU_68060))) ||
2039 (activefpu&(FPU_68881 | FPU_68882)))
2040 return error(unsupport);
2042 return m_fpusavrest(inst, siz);
2047 // movec (68010, 68020, 68030, 68040, 68060, CPU32)
2049 int m_movec(WORD inst, WORD siz)
2053 if (am0 == DREG || am0 == AREG)
2061 inst = (0 << 15) + (a0reg << 12) + CREGlut[a1reg];
2066 inst = (1 << 15) + (a0reg << 12) + CREGlut[a1reg];
2077 inst = (0 << 15) + (a1reg << 12) + CREGlut[a0reg];
2082 inst = (1 << 15) + (a1reg << 12) + CREGlut[a0reg];
2092 // moves (68010, 68020, 68030, 68040, CPU32)
2094 int m_moves(WORD inst, WORD siz)
2096 if (activecpu & !(CPU_68020 | CPU_68030 | CPU_68040))
2097 return error(unsupport);
2101 else if (siz == SIZL)
2108 inst |= am1 | a1reg;
2110 inst = (a0reg << 12) | (1 << 11) | (0 << 15);
2113 else if (am0 == AREG)
2115 inst |= am1 | a1reg;
2117 inst = (a0reg << 12) | (1 << 11) | (1 << 15);
2124 inst |= am0 | a0reg;
2126 inst = (a1reg << 12) | (0 << 11) | (0 << 15);
2131 inst |= am0 | a0reg;
2133 inst = (a1reg << 12) | (0 << 11) | (1 << 15);
2143 // pflusha (68030, 68040)
2145 int m_pflusha(WORD inst, WORD siz)
2147 if (activecpu == CPU_68030)
2150 inst = (1 << 13) | (1 << 10) | (0 << 5) | 0;
2154 else if (activecpu == CPU_68040)
2156 inst = B16(11110101, 00011000);
2161 return error(unsupport);
2168 // pflush (68030, 68040, 68060)
2170 int m_pflush(WORD inst, WORD siz)
2172 if (activecpu == CPU_68030)
2175 // PFLUSH FC, MASK, < ea >
2183 if (*tok != CONST && *tok != SYMBOL)
2184 return error("function code should be an expression");
2186 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2189 if ((a0exattr & DEFINED) == 0)
2190 return error("function code immediate should be defined");
2193 return error("function code out of range (0-7)");
2195 fc = (uint16_t)a0exval;
2205 fc = (1 << 4) | (*tok++ & 7);
2216 return error(syntax_error);
2220 return error("comma exptected");
2223 return error("mask should be an immediate value");
2225 if (*tok != CONST && *tok != SYMBOL)
2226 return error("mask is supposed to be immediate");
2228 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2231 if ((a0exattr & DEFINED) == 0)
2232 return error("mask immediate value should be defined");
2235 return error("function code out of range (0-7)");
2237 mask = (uint16_t)a0exval << 5;
2243 inst = (1 << 13) | fc | mask | (4 << 10);
2247 else if (*tok == ',')
2249 // PFLUSH FC, MASK, < ea >
2252 if (amode(0) == ERROR)
2256 return error(extra_stuff);
2258 if (am0 == AIND || am0 == ABSW || am0 == ABSL || am0 == ADISP || am0 == ADISP || am0 == AINDEXED || am0 == ABASE || am0 == MEMPOST || am0 == MEMPRE)
2260 inst |= am0 | a0reg;
2262 inst = (1 << 13) | fc | mask | (6 << 10);
2268 return error("unsupported addressing mode");
2272 return error(syntax_error);
2276 else if (activecpu == CPU_68040 || activecpu == CPU_68060)
2280 if (*tok != '(' && tok[2] != ')')
2281 return error(syntax_error);
2283 if (tok[1] < KW_A0 && tok[1] > KW_A7)
2284 return error("expected (An)");
2286 if ((inst & 7) == 7)
2287 // With pflushn/pflush there's no easy way to distinguish between
2288 // the two in 68040 mode. Ideally the opcode bitfields would have
2289 // been hardcoded in 68ktab but there is aliasing between 68030
2290 // and 68040 opcode. So we just set the 3 lower bits to 1 in
2291 // pflushn inside 68ktab and detect it here.
2292 inst = (inst & 0xff8) | 8;
2294 inst |= (tok[1] & 7) | (5 << 8);
2297 return error(extra_stuff);
2302 return error(unsupport);
2309 // pflushan (68040, 68060)
2311 int m_pflushan(WORD inst, WORD siz)
2313 if (activecpu == CPU_68040 || activecpu == CPU_68060)
2323 int m_pflushr(WORD inst, WORD siz)
2327 WORD flg = inst; // Save flag bits
2328 inst &= ~0x3F; // Clobber flag bits in instr
2330 // Install "standard" instr size bits
2336 // OR-in register number
2338 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
2340 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
2346 inst |= am1 | a1reg; // Get ea1 into instr
2347 D_word(inst); // Deposit instr
2349 // Generate ea0 if requested
2353 ea1gen(siz); // Generate ea1
2358 inst |= am0 | a0reg; // Get ea0 into instr
2359 D_word(inst); // Deposit instr
2360 ea0gen(siz); // Generate ea0
2362 // Generate ea1 if requested
2367 D_word(B16(10100000, 00000000));
2373 // ploadr, ploadw (68030)
2375 int m_pload(WORD inst, WORD siz, WORD extension)
2377 // TODO: 68851 support is not added yet.
2378 // None of the ST series of computers had a 68020 + 68851 socket and since
2379 // this is an Atari targetted assembler...
2388 if (a0reg == KW_SFC - KW_SFC)
2390 else if (a0reg == KW_DFC - KW_SFC)
2393 return error("illegal control register specified");
2397 inst = (1 << 3) | a0reg;
2400 if ((a0exattr & DEFINED) == 0)
2401 return error("constant value must be defined");
2403 inst = (2 << 3) | (uint16_t)a0exval;
2407 inst |= extension | (1 << 13);
2416 int m_ploadr(WORD inst, WORD siz)
2418 return m_pload(inst, siz, 1 << 9);
2422 int m_ploadw(WORD inst, WORD siz)
2424 return m_pload(inst, siz, 0 << 9);
2429 // pmove (68030/68851)
2431 int m_pmove(WORD inst, WORD siz)
2435 // TODO: 68851 support is not added yet. None of the ST series of
2436 // computers had a 68020 + 68851 socket and since this is an Atari
2437 // targetted assembler.... (same for 68EC030)
2440 inst2 = inst & (1 << 8); // Copy the flush bit over to inst2 in case we're called from m_pmovefd
2441 inst &= ~(1 << 8); // And mask it out
2448 else if (am1 == CREG)
2454 return error("pmove sez: Wut?");
2456 // The instruction is a quad-word (8 byte) operation
2457 // for the CPU root pointer and the supervisor root pointer.
2458 // It is a long-word operation for the translation control register
2459 // and the transparent translation registers(TT0 and TT1).
2460 // It is a word operation for the MMU status register.
2462 if (((reg == (KW_URP - KW_SFC)) || (reg == (KW_SRP - KW_SFC)))
2463 && ((siz != SIZD) && (siz != SIZN)))
2464 return error(siz_error);
2466 if (((reg == (KW_TC - KW_SFC)) || (reg == (KW_TT0 - KW_SFC)) || (reg == (KW_TT1 - KW_SFC)))
2467 && ((siz != SIZL) && (siz != SIZN)))
2468 return error(siz_error);
2470 if ((reg == (KW_MMUSR - KW_SFC)) && ((siz != SIZW) && (siz != SIZN)))
2471 return error(siz_error);
2475 inst |= am1 | a1reg;
2478 else if (am1 == CREG)
2480 inst |= am0 | a0reg;
2484 switch (reg + KW_SFC)
2487 inst2 |= (0 << 10) + (1 << 14); break;
2489 inst2 |= (2 << 10) + (1 << 14); break;
2491 inst2 |= (3 << 10) + (1 << 14); break;
2493 inst2 |= (2 << 10) + (0 << 13); break;
2495 inst2 |= (3 << 10) + (0 << 13); break;
2498 inst2 |= (1 << 9) + (3 << 13);
2500 inst2 |= (0 << 9) + (3 << 13);
2503 return error("unsupported register");
2511 else if (am1 == CREG)
2521 int m_pmovefd(WORD inst, WORD siz)
2525 return m_pmove(inst | (1 << 8), siz);
2532 int m_ptrapcc(WORD inst, WORD siz)
2535 // We stash the 5 condition bits inside the opcode in 68ktab (bits 0-4),
2536 // so we need to extract them first and fill in the clobbered bits.
2537 WORD opcode = inst & 0x1F;
2538 inst = (inst & 0xFFE0) | (0x18);
2547 else if (siz == SIZL)
2554 else if (siz == SIZN)
2566 // ptestr, ptestw (68030)
2568 int m_ptest(WORD inst, WORD siz)
2572 if (activecpu == CPU_68030)
2573 return error("Not implemented yet.");
2574 else if (activecpu == CPU_68040)
2575 return error("Not implemented yet.");
2580 //////////////////////////////////////////////////////////////////////////////
2582 // 68020/30/40/60 instructions
2583 // Note: the map of which instructions are allowed on which CPUs came from the
2584 // 68060 manual, section D-1 (page 392 of the PDF). The current implementation
2585 // is missing checks for the EC models which have a simplified FPU.
2587 //////////////////////////////////////////////////////////////////////////////
2590 #define FPU_NOWARN 0
2595 // Generate a FPU opcode
2597 static inline int gen_fpu(WORD inst, WORD siz, WORD opmode, WORD emul)
2599 if (am0 < AM_NONE) // Check first operand for ea or fp - is this right?
2601 inst |= (1 << 9); // Bolt on FPU id
2604 //if (am0 == DREG || am0 == AREG)
2608 inst = 1 << 14; // R/M field (we have ea so have to set this to 1)
2612 case SIZB: inst |= (6 << 10); break;
2613 case SIZW: inst |= (4 << 10); break;
2614 case SIZL: inst |= (0 << 10); break;
2616 case SIZS: inst |= (1 << 10); break;
2617 case SIZD: inst |= (5 << 10); break;
2618 case SIZX: inst |= (2 << 10); break;
2623 warn("This encoding will cause an unimplemented data type exception in the MC68040 to allow emulation in software.");
2627 return error("Something bad happened, possibly, in gen_fpu.");
2631 inst |= (a1reg << 7);
2638 inst |= (1 << 9); // Bolt on FPU id
2642 inst |= (a1reg << 7);
2647 if ((emul & FPU_FPSP) && (activefpu == (FPU_68040 | FPU_68060)))
2648 warn("Instruction is emulated in 68040/060");
2655 // fabs (6888X, 68040FPSP, 68060FPSP)
2657 int m_fabs(WORD inst, WORD siz)
2660 return gen_fpu(inst, siz, B8(00011000), FPU_NOWARN);
2665 // fsabs (68040, 68060)
2667 int m_fsabs(WORD inst, WORD siz)
2670 if (activefpu == FPU_68040)
2671 return gen_fpu(inst, siz, B8(01011000), FPU_NOWARN);
2673 return error("Unsupported in current FPU");
2678 // fdabs (68040, 68060)
2680 int m_fdabs(WORD inst, WORD siz)
2682 if (activefpu == FPU_68040)
2683 return gen_fpu(inst, siz, B8(01011100), FPU_NOWARN);
2685 return error("Unsupported in current FPU");
2690 // facos (6888X, 68040FPSP, 68060FPSP)
2692 int m_facos(WORD inst, WORD siz)
2695 return gen_fpu(inst, siz, B8(00011100), FPU_FPSP);
2700 // fadd (6888X, 68040, 68060)
2702 int m_fadd(WORD inst, WORD siz)
2705 return gen_fpu(inst, siz, B8(00100010), FPU_NOWARN);
2710 // fsadd (68040, 68060)
2712 int m_fsadd(WORD inst, WORD siz)
2714 if (activefpu & (FPU_68040 | FPU_68060))
2715 return gen_fpu(inst, siz, B8(01100010), FPU_NOWARN);
2717 return error("Unsupported in current FPU");
2724 int m_fdadd(WORD inst, WORD siz)
2726 if (activefpu & (FPU_68040 | FPU_68060))
2727 return gen_fpu(inst, siz, B8(01100110), FPU_NOWARN);
2729 return error("Unsupported in current FPU");
2734 // fasin (6888X, 68040FPSP, 68060FPSP)
2736 int m_fasin(WORD inst, WORD siz)
2739 return gen_fpu(inst, siz, B8(00001100), FPU_FPSP);
2744 // fatan (6888X, 68040FPSP, 68060FPSP)
2746 int m_fatan(WORD inst, WORD siz)
2749 return gen_fpu(inst, siz, B8(00001010), FPU_FPSP);
2754 // fatanh (6888X, 68040FPSP, 68060FPSP)
2756 int m_fatanh(WORD inst, WORD siz)
2759 return gen_fpu(inst, siz, B8(00001101), FPU_FPSP);
2764 // fcmp (6888X, 68040, 68060)
2766 int m_fcmp(WORD inst, WORD siz)
2769 return gen_fpu(inst, siz, B8(00111000), FPU_FPSP);
2774 // fcos (6888X, 68040FPSP, 68060FPSP)
2776 int m_fcos(WORD inst, WORD siz)
2779 return gen_fpu(inst, siz, B8(00011101), FPU_FPSP);
2784 // fcosh (6888X, 68040FPSP, 68060FPSP)
2786 int m_fcosh(WORD inst, WORD siz)
2789 return gen_fpu(inst, siz, B8(00011001), FPU_FPSP);
2794 // fdbcc (6888X, 68040, 68060FPSP)
2796 int m_fdbcc(WORD inst, WORD siz)
2799 WORD opcode = inst & 0x3F; // Grab conditional bitfield
2809 if (a1exattr & DEFINED)
2811 if ((a1exattr & TDB) != cursect)
2812 return error(rel_error);
2814 uint32_t v = (uint32_t)a1exval - sloc;
2816 if ((v + 0x8000) > 0x10000)
2817 return error(range_error);
2823 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
2827 if (activefpu == FPU_68060)
2828 warn("Instruction is emulated in 68060");
2835 // fdiv (6888X, 68040, 68060)
2837 int m_fdiv(WORD inst, WORD siz)
2840 return gen_fpu(inst, siz, B8(00100000), FPU_NOWARN);
2845 // fsdiv (68040, 68060)
2847 int m_fsdiv(WORD inst, WORD siz)
2849 if (activefpu & (FPU_68040 | FPU_68060))
2850 return gen_fpu(inst, siz, B8(01100000), FPU_NOWARN);
2852 return error("Unsupported in current FPU");
2857 // fddiv (68040, 68060)
2859 int m_fddiv(WORD inst, WORD siz)
2861 if (activefpu & (FPU_68040 | FPU_68060))
2862 return gen_fpu(inst, siz, B8(01100100), FPU_NOWARN);
2864 return error("Unsupported in current FPU");
2869 // fetox (6888X, 68040FPSP, 68060FPSP)
2871 int m_fetox(WORD inst, WORD siz)
2874 return gen_fpu(inst, siz, B8(00010000), FPU_FPSP);
2879 // fetoxm1 (6888X, 68040FPSP, 68060FPSP)
2881 int m_fetoxm1(WORD inst, WORD siz)
2884 return gen_fpu(inst, siz, B8(00001000), FPU_FPSP);
2889 // fgetexp (6888X, 68040FPSP, 68060FPSP)
2891 int m_fgetexp(WORD inst, WORD siz)
2894 return gen_fpu(inst, siz, B8(00011110), FPU_FPSP);
2899 // fgetman (6888X, 68040FPSP, 68060FPSP)
2901 int m_fgetman(WORD inst, WORD siz)
2904 return gen_fpu(inst, siz, B8(00011111), FPU_FPSP);
2909 // fint (6888X, 68040FPSP, 68060)
2911 int m_fint(WORD inst, WORD siz)
2914 // special case - fint fpx = fint fpx,fpx
2917 if (activefpu == FPU_68040)
2918 warn("Instruction is emulated in 68040");
2920 return gen_fpu(inst, siz, B8(00000001), FPU_NOWARN);
2925 // fintrz (6888X, 68040FPSP, 68060)
2927 int m_fintrz(WORD inst, WORD siz)
2930 // special case - fintrz fpx = fintrz fpx,fpx
2933 if (activefpu == FPU_68040)
2934 warn("Instruction is emulated in 68040");
2936 return gen_fpu(inst, siz, B8(00000011), FPU_NOWARN);
2941 // flog10 (6888X, 68040FPSP, 68060FPSP)
2943 int m_flog10(WORD inst, WORD siz)
2946 return gen_fpu(inst, siz, B8(00010101), FPU_FPSP);
2951 // flog2 (6888X, 68040FPSP, 68060FPSP)
2953 int m_flog2(WORD inst, WORD siz)
2956 return gen_fpu(inst, siz, B8(00010110), FPU_FPSP);
2961 // flogn (6888X, 68040FPSP, 68060FPSP)
2963 int m_flogn(WORD inst, WORD siz)
2966 return gen_fpu(inst, siz, B8(00010100), FPU_FPSP);
2971 // flognp1 (6888X, 68040FPSP, 68060FPSP)
2973 int m_flognp1(WORD inst, WORD siz)
2976 return gen_fpu(inst, siz, B8(00000110), FPU_FPSP);
2981 // fmod (6888X, 68040FPSP, 68060FPSP)
2983 int m_fmod(WORD inst, WORD siz)
2986 return gen_fpu(inst, siz, B8(00100001), FPU_FPSP);
2991 // fmove (6888X, 68040, 68060)
2993 int m_fmove(WORD inst, WORD siz)
2998 if ((am0 == FREG) && (am1 < AM_USP))
3002 inst |= am1 | a1reg;
3011 case SIZB: inst |= (6 << 10); break;
3012 case SIZW: inst |= (4 << 10); break;
3013 case SIZL: inst |= (0 << 10); break;
3015 case SIZS: inst |= (1 << 10); break;
3016 case SIZD: inst |= (5 << 10); break;
3017 case SIZX: inst |= (2 << 10); break;
3018 case SIZP: inst |= (3 << 10);
3019 // In P size we have 2 cases: {#k} where k is immediate
3020 // and {Dn} where Dn=Data register
3025 inst |= bfval1 << 4;
3030 if (bfval1 > 63 && bfval1 < -64)
3031 return error("K-factor must be between -64 and 63");
3033 inst |= bfval1 & 127;
3038 return error("Something bad happened, possibly.");
3042 // Destination specifier
3043 inst |= (a0reg << 7);
3051 else if ((am0 < AM_USP) && (am1 == FREG))
3056 inst |= am0 | a0reg;
3065 case SIZB: inst |= (6 << 10); break;
3066 case SIZW: inst |= (4 << 10); break;
3067 case SIZL: inst |= (0 << 10); break;
3069 case SIZS: inst |= (1 << 10); break;
3070 case SIZD: inst |= (5 << 10); break;
3071 case SIZX: inst |= (2 << 10); break;
3072 case SIZP: inst |= (3 << 10); break;
3074 return error("Something bad happened, possibly.");
3078 // Destination specifier
3079 inst |= (a1reg << 7);
3087 else if ((am0 == FREG) && (am1 == FREG))
3089 // register-to-register
3090 // Essentially ea to register with R/0=0
3099 if (siz != SIZX && siz != SIZN)
3100 return error("Invalid size");
3103 inst |= (a0reg << 10);
3105 // Destination register
3106 inst |= (a1reg << 7);
3116 // fmove (6888X, 68040, 68060)
3118 int m_fmovescr(WORD inst, WORD siz)
3122 // Move Floating-Point System Control Register (FPCR)
3126 if ((am0 == FPSCR) && (am1 < AM_USP))
3128 inst |= am1 | a1reg;
3130 inst = (1 << 13) + (1 << 15);
3136 else if ((am1 == FPSCR) && (am0 < AM_USP))
3138 inst |= am0 | a0reg;
3140 inst = (0 << 13) + (1 << 15);
3147 return error("m_fmovescr says: wut?");
3151 // fsmove/fdmove (68040, 68060)
3153 int m_fsmove(WORD inst, WORD siz)
3155 if (!(activefpu & (FPU_68040 | FPU_68060)))
3156 return error("Unsupported in current FPU");
3158 return error("Not implemented yet.");
3161 if (activefpu == FPU_68040)
3162 return gen_fpu(inst, siz, B8(01100100), FPU_P_EMUL);
3164 return error("Unsupported in current FPU");
3169 int m_fdmove(WORD inst, WORD siz)
3171 if (!(activefpu & (FPU_68040 | FPU_68060)))
3172 return error("Unsupported in current FPU");
3174 return error("Not implemented yet.");
3177 if (activefpu == FPU_68040)
3178 return gen_fpu(inst, siz, B8(01100100), FPU_P_EMUL);
3180 return error("Unsupported in current FPU");
3186 // fmovecr (6888X, 68040FPSP, 68060FPSP)
3188 int m_fmovecr(WORD inst, WORD siz)
3198 if (activefpu == FPU_68040)
3199 warn("Instruction is emulated in 68040/060");
3206 // fmovem (6888X, 68040, 68060FPSP)
3208 int m_fmovem(WORD inst, WORD siz)
3215 if (siz == SIZX || siz == SIZN)
3217 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
3219 // fmovem.x <rlist>,ea
3220 if (fpu_reglist_left(®mask) < 0)
3224 return error("missing comma");
3229 inst |= am0 | a0reg;
3231 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3232 return error("invalid addressing mode");
3235 inst = (1 << 15) | (1 << 14) | (1 << 13) | (0 << 11) | regmask;
3240 else if ((*tok >= KW_D0) && (*tok <= KW_D7))
3243 datareg = (*tok++ & 7) << 10;
3246 return error("missing comma");
3251 inst |= am0 | a0reg;
3253 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3254 return error("invalid addressing mode");
3256 // Quote from the 060 manual:
3257 // "[..] when the processor attempts an FMOVEM.X instruction using a dynamic register list."
3258 if (activefpu == FPU_68060)
3259 warn("Instruction is emulated in 68060");
3262 inst = (1 << 15) | (1 << 14) | (1 << 13) | (1 << 11) | (datareg << 4);
3273 inst |= am0 | a0reg;
3276 return error("missing comma");
3278 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
3280 // fmovem.x ea,<rlist>
3281 if (fpu_reglist_right(®mask) < 0)
3285 inst = (1 << 15) | (1 << 14) | (0 << 13) | (2 << 11) | regmask;
3293 datareg = (*tok++ & 7) << 10;
3295 // Quote from the 060 manual:
3296 // "[..] when the processor attempts an FMOVEM.X instruction using a dynamic register list."
3297 if (activefpu == FPU_68060)
3298 warn("Instruction is emulated in 68060");
3301 inst = (1 << 15) | (1 << 14) | (0 << 13) | (3 << 11) | (datareg << 4);
3308 else if (siz == SIZL)
3310 if ((*tok == KW_FPCR) || (*tok == KW_FPSR) || (*tok == KW_FPIAR))
3312 // fmovem.l <rlist>,ea
3313 regmask = (1 << 15) | (1 << 13);
3314 int no_control_regs = 0;
3317 if (*tok == KW_FPCR)
3319 regmask |= (1 << 12);
3325 if (*tok == KW_FPSR)
3327 regmask |= (1 << 11);
3333 if (*tok == KW_FPIAR)
3335 regmask |= (1 << 10);
3341 if ((*tok == '/') || (*tok == '-'))
3348 return error("missing comma");
3353 // Quote from the 060 manual:
3354 // "[..] when the processor attempts to execute an FMOVEM.L instruction with
3355 // an immediate addressing mode to more than one floating - point
3356 // control register (FPCR, FPSR, FPIAR)[..]"
3357 if (activefpu == FPU_68060)
3358 if (no_control_regs > 1 && am0 == IMMED)
3359 warn("Instruction is emulated in 68060");
3361 inst |= am0 | a0reg;
3368 // fmovem.l ea,<rlist>
3372 inst |= am0 | a0reg;
3375 return error("missing comma");
3377 regmask = (1 << 15) | (0 << 13);
3380 if (*tok == KW_FPCR)
3382 regmask |= (1 << 12);
3387 if (*tok == KW_FPSR)
3389 regmask |= (1 << 11);
3394 if (*tok == KW_FPIAR)
3396 regmask |= (1 << 10);
3401 if ((*tok == '/') || (*tok == '-'))
3408 return error("extra (unexpected) text found");
3410 inst |= am0 | a0reg;
3417 return error("bad size suffix");
3424 // fmul (6888X, 68040, 68060)
3426 int m_fmul(WORD inst, WORD siz)
3429 return gen_fpu(inst, siz, B8(00100011), FPU_NOWARN);
3434 // fsmul (68040, 68060)
3436 int m_fsmul(WORD inst, WORD siz)
3438 if (activefpu & (FPU_68040 | FPU_68060))
3439 return gen_fpu(inst, siz, B8(01100011), FPU_NOWARN);
3441 return error("Unsupported in current FPU");
3448 int m_fdmul(WORD inst, WORD siz)
3450 if (activefpu & (FPU_68040 | FPU_68060))
3451 return gen_fpu(inst, siz, B8(01100111), FPU_NOWARN);
3453 return error("Unsupported in current FPU");
3458 // fneg (6888X, 68040, 68060)
3460 int m_fneg(WORD inst, WORD siz)
3467 return gen_fpu(inst, siz, B8(00011010), FPU_NOWARN);
3470 return gen_fpu(inst, siz, B8(00011010), FPU_NOWARN);
3475 // fsneg (68040, 68060)
3477 int m_fsneg(WORD inst, WORD siz)
3479 if (activefpu & (FPU_68040 | FPU_68060))
3484 return gen_fpu(inst, siz, B8(01011010), FPU_NOWARN);
3487 return gen_fpu(inst, siz, B8(01011010), FPU_NOWARN);
3490 return error("Unsupported in current FPU");
3495 // fdneg (68040, 68060)
3497 int m_fdneg(WORD inst, WORD siz)
3499 if (activefpu & (FPU_68040 | FPU_68060))
3504 return gen_fpu(inst, siz, B8(01011110), FPU_NOWARN);
3507 return gen_fpu(inst, siz, B8(01011110), FPU_NOWARN);
3510 return error("Unsupported in current FPU");
3515 // fnop (6888X, 68040, 68060)
3517 int m_fnop(WORD inst, WORD siz)
3520 return gen_fpu(inst, siz, B8(00000000), FPU_NOWARN);
3525 // frem (6888X, 68040FPSP, 68060FPSP)
3527 int m_frem(WORD inst, WORD siz)
3530 return gen_fpu(inst, siz, B8(00100101), FPU_FPSP);
3535 // fscale (6888X, 68040FPSP, 68060FPSP)
3537 int m_fscale(WORD inst, WORD siz)
3540 return gen_fpu(inst, siz, B8(00100110), FPU_FPSP);
3545 // FScc (6888X, 68040, 68060), cpScc (68851, 68030), PScc (68851)
3546 // TODO: Add check for PScc to ensure 68020+68851 active
3547 // TODO: Add check for cpScc to ensure 68020+68851, 68030
3549 int m_fscc(WORD inst, WORD siz)
3553 // We stash the 5 condition bits inside the opcode in 68ktab (bits 4-0),
3554 // so we need to extract them first and fill in the clobbered bits.
3555 WORD opcode = inst & 0x1F;
3557 inst |= am0 | a0reg;
3561 if (activefpu == FPU_68060)
3562 warn("Instruction is emulated in 68060");
3568 // fsgldiv (6888X, 68040FPSP, 68060FPSP)
3570 int m_fsgldiv(WORD inst, WORD siz)
3573 return gen_fpu(inst, siz, B8(00100100), FPU_FPSP);
3578 // fsglmul (6888X, 68040, 68060FPSP)
3580 int m_fsglmul(WORD inst, WORD siz)
3583 return gen_fpu(inst, siz, B8(00100111), FPU_FPSP);
3588 // fsin (6888X, 68040FPSP, 68060FPSP)
3590 int m_fsin(WORD inst, WORD siz)
3593 return gen_fpu(inst, siz, B8(00001110), FPU_FPSP);
3598 // fsincos (6888X, 68040FPSP, 68060FPSP)
3600 int m_fsincos(WORD inst, WORD siz)
3604 // Swap a1reg, a2reg as a2reg should be stored in the bitfield gen_fpu
3611 if (gen_fpu(inst, siz, B8(00110000), FPU_FPSP) == OK)
3622 // fsinh (6888X, 68040FPSP, 68060FPSP)
3624 int m_fsinh(WORD inst, WORD siz)
3627 return gen_fpu(inst, siz, B8(00000010), FPU_FPSP);
3632 // fsqrt (6888X, 68040, 68060)
3634 int m_fsqrt(WORD inst, WORD siz)
3637 return gen_fpu(inst, siz, B8(00000100), FPU_NOWARN);
3642 // fsfsqrt (68040, 68060)
3644 int m_fsfsqrt(WORD inst, WORD siz)
3646 if (activefpu & (FPU_68040 | FPU_68060))
3647 return gen_fpu(inst, siz, B8(01000001), FPU_NOWARN);
3649 return error("Unsupported in current FPU");
3654 // fdfsqrt (68040, 68060)
3656 int m_fdfsqrt(WORD inst, WORD siz)
3658 if (activefpu & (FPU_68040 | FPU_68060))
3659 return gen_fpu(inst, siz, B8(01000101), FPU_NOWARN);
3661 return error("Unsupported in current FPU");
3666 // fsub (6888X, 68040, 68060)
3668 int m_fsub(WORD inst, WORD siz)
3671 return gen_fpu(inst, siz, B8(00101000), FPU_NOWARN);
3676 // fsfsub (68040, 68060)
3678 int m_fsfsub(WORD inst, WORD siz)
3680 if (activefpu & (FPU_68040 | FPU_68060))
3681 return gen_fpu(inst, siz, B8(01101000), FPU_NOWARN);
3683 return error("Unsupported in current FPU");
3688 // fdfsub (68040, 68060)
3690 int m_fdsub(WORD inst, WORD siz)
3692 if (activefpu & (FPU_68040 | FPU_68060))
3693 return gen_fpu(inst, siz, B8(01101100), FPU_NOWARN);
3695 return error("Unsupported in current FPU");
3700 // ftan (6888X, 68040FPSP, 68060FPSP)
3702 int m_ftan(WORD inst, WORD siz)
3705 return gen_fpu(inst, siz, B8(00001111), FPU_FPSP);
3710 // ftanh (6888X, 68040FPSP, 68060FPSP)
3712 int m_ftanh(WORD inst, WORD siz)
3715 return gen_fpu(inst, siz, B8(00001001), FPU_FPSP);
3720 // ftentox (6888X, 68040FPSP, 68060FPSP)
3722 int m_ftentox(WORD inst, WORD siz)
3725 return gen_fpu(inst, siz, B8(00010010), FPU_FPSP);
3730 // FTRAPcc (6888X, 68040, 68060FPSP)
3732 int m_ftrapcc(WORD inst, WORD siz)
3736 // We stash the 5 condition bits inside the opcode in 68ktab (bits 3-7),
3737 // so we need to extract them first and fill in the clobbered bits.
3738 WORD opcode = (inst >> 3) & 0x1F;
3739 inst = (inst & 0xFF07) | (0xF << 3);
3748 else if (siz == SIZL)
3755 else if (siz == SIZN)
3763 if (activefpu == FPU_68060)
3764 warn("Instruction is emulated in 68060");
3771 // ftst (6888X, 68040, 68060)
3773 int m_ftst(WORD inst, WORD siz)
3776 return gen_fpu(inst, siz, B8(00111010), FPU_NOWARN);
3781 // ftwotox (6888X, 68040FPSP, 68060FPSP)
3783 int m_ftwotox(WORD inst, WORD siz)
3786 return gen_fpu(inst, siz, B8(00010001), FPU_FPSP);
3790 /////////////////////////////////
3792 // 68060 specific instructions //
3794 /////////////////////////////////
3800 int m_lpstop(WORD inst, WORD siz)
3803 D_word(B16(00000001, 11000000));
3805 if (a0exattr & DEFINED)
3811 AddFixup(FU_WORD, sloc, a0expr);
3822 int m_plpa(WORD inst, WORD siz)
3825 inst |= a0reg; // Install register