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), m_bad6mode(WORD, WORD), m_bad6inst(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, int);
45 int m_move(WORD, WORD);
46 int m_moveq(WORD, WORD);
47 int m_usp(WORD, WORD);
48 int m_movep(WORD, WORD);
49 int m_trap(WORD, WORD);
50 int m_movem(WORD, WORD);
51 int m_clra(WORD, WORD);
52 int m_clrd(WORD, WORD);
54 int m_move30(WORD, WORD); // 68020/30/40/60
55 int m_br30(WORD inst, WORD siz);
56 int m_ea030(WORD inst, WORD siz);
57 int m_bfop(WORD inst, WORD siz);
58 int m_callm(WORD inst, WORD siz);
59 int m_cas(WORD inst, WORD siz);
60 int m_cas2(WORD inst, WORD siz);
61 int m_chk2(WORD inst, WORD siz);
62 int m_cmp2(WORD inst, WORD siz);
63 int m_bkpt(WORD inst, WORD siz);
64 int m_cpbr(WORD inst, WORD siz);
65 int m_cpdbr(WORD inst, WORD siz);
66 int m_divs(WORD inst, WORD siz);
67 int m_muls(WORD inst, WORD siz);
68 int m_divu(WORD inst, WORD siz);
69 int m_mulu(WORD inst, WORD siz);
70 int m_divsl(WORD inst, WORD siz);
71 int m_divul(WORD inst, WORD siz);
72 int m_move16a(WORD inst, WORD siz);
73 int m_move16b(WORD inst, WORD siz);
74 int m_pack(WORD inst, WORD siz);
75 int m_rtm(WORD inst, WORD siz);
76 int m_rtd(WORD inst, WORD siz);
77 int m_trapcc(WORD inst, WORD siz);
78 int m_cinv(WORD inst, WORD siz);
79 int m_cprest(WORD inst, WORD siz);
80 int m_movec(WORD inst, WORD siz);
81 int m_moves(WORD inst, WORD siz);
84 int m_pbcc(WORD inst, WORD siz);
85 int m_pflusha(WORD inst, WORD siz);
86 int m_pflush(WORD inst, WORD siz);
87 int m_pflushr(WORD inst, WORD siz);
88 int m_pload(WORD inst, WORD siz, WORD extension);
89 int m_pmove(WORD inst, WORD siz);
90 int m_pmovefd(WORD inst, WORD siz);
91 int m_ptest(WORD inst, WORD siz);
92 int m_ptrapcc(WORD inst, WORD siz);
93 int m_ploadr(WORD inst, WORD siz);
94 int m_ploadw(WORD inst, WORD siz);
97 int m_fabs(WORD inst, WORD siz);
98 int m_facos(WORD inst, WORD siz);
99 int m_fadd(WORD inst, WORD siz);
100 int m_fasin(WORD inst, WORD siz);
101 int m_fatan(WORD inst, WORD siz);
102 int m_fatanh(WORD inst, WORD siz);
103 int m_fcmp(WORD inst, WORD siz);
104 int m_fcos(WORD inst, WORD siz);
105 int m_fcosh(WORD inst, WORD siz);
106 int m_fdabs(WORD inst, WORD siz);
107 int m_fdadd(WORD inst, WORD siz);
108 int m_fdbcc(WORD inst, WORD siz);
109 int m_fddiv(WORD inst, WORD siz);
110 int m_fdfsqrt(WORD inst, WORD siz);
111 int m_fdiv(WORD inst, WORD siz);
112 int m_fdmove(WORD inst, WORD siz);
113 int m_fdmul(WORD inst, WORD siz);
114 int m_fdneg(WORD inst, WORD siz);
115 int m_fdsub(WORD inst, WORD siz);
116 int m_fetox(WORD inst, WORD siz);
117 int m_fetoxm1(WORD inst, WORD siz);
118 int m_fgetexp(WORD inst, WORD siz);
119 int m_fgetman(WORD inst, WORD siz);
120 int m_fint(WORD inst, WORD siz);
121 int m_fintrz(WORD inst, WORD siz);
122 int m_flog10(WORD inst, WORD siz);
123 int m_flog2(WORD inst, WORD siz);
124 int m_flogn(WORD inst, WORD siz);
125 int m_flognp1(WORD inst, WORD siz);
126 int m_fmod(WORD inst, WORD siz);
127 int m_fmove(WORD inst, WORD siz);
128 int m_fmovescr(WORD inst, WORD siz);
129 int m_fmovecr(WORD inst, WORD siz);
130 int m_fmovem(WORD inst, WORD siz);
131 int m_fmul(WORD inst, WORD siz);
132 int m_fneg(WORD inst, WORD siz);
133 int m_fnop(WORD inst, WORD siz);
134 int m_frem(WORD inst, WORD siz);
135 int m_fsabs(WORD inst, WORD siz);
136 int m_fsadd(WORD inst, WORD siz);
137 int m_fscc(WORD inst, WORD siz);
138 int m_fscale(WORD inst, WORD siz);
139 int m_fsdiv(WORD inst, WORD siz);
140 int m_fsfsqrt(WORD inst, WORD siz);
141 int m_fsfsub(WORD inst, WORD siz);
142 int m_fsgldiv(WORD inst, WORD siz);
143 int m_fsglmul(WORD inst, WORD siz);
144 int m_fsin(WORD inst, WORD siz);
145 int m_fsincos(WORD inst, WORD siz);
146 int m_fsinh(WORD inst, WORD siz);
147 int m_fsmove(WORD inst, WORD siz);
148 int m_fsmul(WORD inst, WORD siz);
149 int m_fsneg(WORD inst, WORD siz);
150 int m_fsqrt(WORD inst, WORD siz);
151 int m_fsub(WORD inst, WORD siz);
152 int m_ftan(WORD inst, WORD siz);
153 int m_ftanh(WORD inst, WORD siz);
154 int m_ftentox(WORD inst, WORD siz);
155 int m_ftst(WORD inst, WORD siz);
156 int m_ftwotox(WORD inst, WORD siz);
157 int m_ftrapcc(WORD inst, WORD siz);
159 // Common error messages
160 char range_error[] = "expression out of range";
161 char abs_error[] = "illegal absolute expression";
162 char seg_error[] = "bad (section) expression";
163 char rel_error[] = "illegal relative address";
164 char siz_error[] = "bad size specified";
165 char undef_error[] = "undefined expression";
166 char fwd_error[] = "forward or undefined expression";
167 char unsupport[] = "unsupported for selected CPU";
169 // Include code tables
171 { 0xFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000, 0, m_badmode }, // 0
173 { 0, 0L, 0L, 0x0000, 0, m_unimp } // Last entry
176 // Register number << 9
178 0, 1 << 9, 2 << 9, 3 << 9, 4 << 9, 5 << 9, 6 << 9, 7 << 9
181 // SIZB==>00, SIZW==>01, SIZL==>10, SIZN==>01 << 6
185 1<<6, (WORD)-1, // SIZW, n/a
186 2<<6, (WORD)-1, (WORD)-1, (WORD)-1, // SIZL, n/a, n/a, n/a
190 // Byte/word/long size for MOVE instrs
194 0x3000, (WORD)-1, // Word
195 0x2000, (WORD)-1, (WORD)-1, (WORD)-1, // Long
196 0x3000 // Word (SIZN)
199 // Word/long size (0=.w, 1=.l) in bit 8
203 0, (WORD)-1, // SIZW, n/a
204 1<<8, (WORD)-1, (WORD)-1, (WORD)-1, // SIZL, n/a, n/a, n/a
208 // Byte/Word/long size (0=.w, 1=.l) in bit 9
212 1<<9, (WORD)-1, // Word
213 1<<10, (WORD)-1, (WORD)-1, (WORD)-1, // Long
217 // Addressing mode in bits 6..11 (register/mode fields are reversed)
219 00000, 01000, 02000, 03000, 04000, 05000, 06000, 07000,
220 00100, 01100, 02100, 03100, 04100, 05100, 06100, 07100,
221 00200, 01200, 02200, 03200, 04200, 05200, 06200, 07200,
222 00300, 01300, 02300, 03300, 04300, 05300, 06300, 07300,
223 00400, 01400, 02400, 03400, 04400, 05400, 06400, 07400,
224 00500, 01500, 02500, 03500, 04500, 05500, 06500, 07500,
225 00600, 01600, 02600, 03600, 04600, 05600, 06600, 07600,
226 00700, 01700, 02700, 03700, 04700, 05700, 06700, 07700
229 // Control registers lookup table
231 // MC68010/MC68020/MC68030/MC68040/CPU32
232 0x000, // Source Function Code(SFC)
233 0x001, // Destination Function Code(DFC)
234 0x800, // User Stack Pointer(USP)
235 0x801, // Vector Base Register(VBR)
236 // MC68020 / MC68030 / MC68040
237 0x002, // Cache Control Register(CACR)
238 0x802, // Cache Address Register(CAAR) (020/030 only)
239 0x803, // Master Stack Pointer(MSP)
240 0x804, // Interrupt Stack Pointer(ISP)
241 // MC68040 / MC68LC040
242 0x003, // MMU Translation Control Register(TC)
243 0x004, // Instruction Transparent Translation Register 0 (ITT0)
244 0x005, // Instruction Transparent Translation Register 1 (ITT1)
245 0x006, // Data Transparent Translation Register 0 (DTT0)
246 0x007, // Data Transparent Translation Register 1 (DTT1)
247 0x805, // MMU Status Register(MMUSR)
248 0x806, // User Root Pointer(URP)
249 0x807, // Supervisor Root Pointer(SRP)
251 0x004, // Instruction Access Control Register 0 (IACR0)
252 0x005, // Instruction Access Control Register 1 (IACR1)
253 0x006, // Data Access Control Register 0 (DACR1)
254 0x007, // Data Access Control Register 1 (DACR1)
256 0xFFF // CPU Root Pointer (CRP) - There's no movec with CRP in it, this is just a guard entry
261 int m_unimp(WORD unused1, WORD unused2)
263 return (int)error("unimplemented mnemonic");
267 //int m_badmode(void)
268 int m_badmode(WORD unused1, WORD unused2)
270 return (int)error("inappropriate addressing mode");
274 int m_self(WORD inst, WORD usused)
282 // Do one EA in bits 0..5
284 // Bits in `inst' have the following meaning:
286 // Bit zero specifies which ea (ea0 or ea1) to generate in the lower six bits
289 // If bit one is set, the OTHER ea (the one that wasn't generated by bit zero)
290 // is generated after the instruction. Regardless of bit 0's value, ea0 is
291 // always deposited in memory before ea1.
293 // If bit two is set, standard size bits are set in the instr in bits 6 and 7.
295 // If bit four is set, bit three specifies which eaXreg to place in bits 9..11
298 int m_ea(WORD inst, WORD siz)
300 WORD flg = inst; // Save flag bits
301 inst &= ~0x3F; // Clobber flag bits in instr
303 // Install "standard" instr size bits
309 // OR-in register number
311 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
313 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
319 inst |= am1 | a1reg; // Get ea1 into instr
320 D_word(inst); // Deposit instr
322 // Generate ea0 if requested
326 ea1gen(siz); // Generate ea1
331 inst |= am0 | a0reg; // Get ea0 into instr
332 D_word(inst); // Deposit instr
333 ea0gen(siz); // Generate ea0
335 // Generate ea1 if requested
345 // Check if lea x(an),an can be optimised to addq.w #x,an--otherwise fall back
348 int m_lea(WORD inst, WORD siz)
350 if (CHECK_OPTS(OPT_LEA_ADDQ)
351 && ((am0 == ADISP) && (a0reg == a1reg) && (a0exattr & DEFINED))
352 && ((a0exval > 0) && (a0exval <= 8)))
354 inst = B16(01010000, 01001000) | (((uint16_t)a0exval & 7) << 9) | (a0reg);
356 warn("lea size(An),An converted to addq #size,An");
360 return m_ea(inst, siz);
364 int m_ea030(WORD inst, WORD siz)
367 WORD flg = inst; // Save flag bits
368 inst &= ~0x3F; // Clobber flag bits in instr
370 // Install "standard" instr size bits
376 // OR-in register number
379 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
383 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
390 inst |= am1 | a1reg; // Get ea1 into instr
391 D_word(inst); // Deposit instr
393 // Generate ea0 if requested
397 ea1gen(siz); // Generate ea1
403 // We get here if we're doing 020+ addressing and an address
404 // register is used. For example, something like "tst a0". A bit of
405 // a corner case, so kludge it
407 else if (am0 == PCDISP)
408 //Another corner case (possibly!), so kludge ahoy
409 inst |= am0; // Get ea0 into instr
410 else if (am0 == IMMED)
411 inst |= am0 | a0reg; // Get ea0 into instr
412 else if (am0 == AM_CCR)
414 else if (am0 == AIND)
417 inst |= a0reg; // Get ea0 into instr
418 D_word(inst); // Deposit instr
419 ea0gen(siz); // Generate ea0
421 // Generate ea1 if requested
431 // Dx,Dy nnnnXXXnssnnnYYY If bit 0 of `inst' is set, install size bits in bits
434 int m_abcd(WORD inst, WORD siz)
443 inst |= a0reg | reg_9[a1reg];
453 int m_adda(WORD inst, WORD siz)
455 if (a0exattr & DEFINED)
457 if (CHECK_OPTS(OPT_ADDA_ADDQ))
458 if (a0exval > 1 && a0exval <= 8)
459 // Immediate is between 1 and 8 so let's convert to addq
460 return m_addq(B16(01010000, 00000000), siz);
461 if (CHECK_OPTS(OPT_ADDA_LEA))
464 // Immediate is larger than 8 so let's convert to lea
465 am0 = ADISP; // Change addressing mode
466 a0reg = a1reg; // In ADISP a0reg is used instead of a1reg!
467 return m_lea(B16(01000001, 11011000), SIZW);
471 inst |= am0 | a0reg | lwsiz_8[siz] | reg_9[a1reg];
473 ea0gen(siz); // Generate EA
480 // If bit 0 of `inst' is 1, install size bits in bits 6..7 of instr.
481 // If bit 1 of `inst' is 1, install a1reg in bits 9..11 of instr.
483 int m_reg(WORD inst, WORD siz)
490 // Install other register (9..11)
491 inst |= reg_9[a1reg];
493 inst &= ~7; // Clear off crufty bits
494 inst |= a0reg; // Install first register
504 int m_imm(WORD inst, WORD siz)
516 int m_imm8(WORD inst, WORD siz)
529 int m_shr(WORD inst, WORD siz)
531 inst |= reg_9[a0reg] | a1reg | siz_6[siz];
541 int m_shi(WORD inst, WORD siz)
543 inst |= a1reg | siz_6[siz];
545 if (a0exattr & DEFINED)
548 return error(range_error);
550 inst |= (a0exval & 7) << 9;
555 AddFixup(FU_QUICK, sloc, a0expr);
564 // {bset, btst, bchg, bclr} -- #immed,ea -- Dn,ea
566 int m_bitop(WORD inst, WORD siz)
568 // Enforce instruction sizes
570 { // X,Dn must be .n or .l
571 if (siz & (SIZB | SIZW))
572 return error(siz_error);
574 else if (siz & (SIZW | SIZL)) // X,ea must be .n or .b
575 return error(siz_error);
577 // Construct instr and EAs
583 ea0gen(SIZB); // Immediate bit number
587 inst |= reg_9[a0reg];
598 int m_dbra(WORD inst, WORD siz)
604 if (a1exattr & DEFINED)
606 if ((a1exattr & TDB) != cursect)
607 return error(rel_error);
609 uint32_t v = a1exval - sloc;
611 if (v + 0x8000 > 0x10000)
612 return error(range_error);
618 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
629 int m_exg(WORD inst, WORD siz)
635 if (am0 == DREG && am1 == DREG)
637 else if (am0 == AREG && am1 == AREG)
643 m = a1reg; // Get AREG into a1reg
651 inst |= m | reg_9[a0reg] | a1reg;
661 int m_link(WORD inst, WORD siz)
665 // Is this an error condition???
670 inst &= ~((3 << 9) | (1 << 6) | (1 << 4));
682 WORD extra_addressing[16]=
684 0, // 0100 (bd,An,Xn)
685 0, // 0101 ([bd,An],Xn,od)
686 0x180, // 0102 ([bc,An,Xn],od) (111 110 110 111)
687 0, // 0103 (bd,PC,Xn)
688 0, // 0104 ([bd,PC],Xn,od)
689 0, // 0105 ([bc,PC,Xn],od)
704 // Handle MOVE <C_ALL> <C_ALTDATA>
705 // MOVE <C_ALL> <M_AREG>
707 // Optimize MOVE.L #<smalldata>,D0 to a MOVEQ
709 int m_move(WORD inst, WORD size)
711 // Cast the passed in value to an int
714 // Try to optimize to MOVEQ
715 // N.B.: We can get away with casting the uint64_t to a 32-bit value
716 // because it checks for a SIZL (i.e., a 32-bit value).
717 if (CHECK_OPTS(OPT_MOVEL_MOVEQ)
718 && (siz == SIZL) && (am0 == IMMED) && (am1 == DREG)
719 && ((a0exattr & (TDB | DEFINED)) == DEFINED)
720 && ((uint32_t)a0exval + 0x80 < 0x100))
722 m_moveq((WORD)0x7000, (WORD)0);
725 warn("move.l #size,dx converted to moveq");
729 if ((am0 < ABASE) && (am1 < ABASE)) // 68000 modes
731 inst |= siz_12[siz] | am_6[am1] | reg_9[a1reg] | am0 | a0reg;
739 ea1gen((WORD)siz | 0x8000); // Tell ea1gen we're move ea,ea
743 inst |= siz_12[siz] | reg_9[a1reg] | extra_addressing[am0 - ABASE];
760 // Handle MOVE <C_ALL030> <C_ALTDATA>
761 // MOVE <C_ALL030> <M_AREG>
763 int m_move30(WORD inst, WORD size)
766 // TODO: is extra_addressing necessary/correct?
767 //inst |= siz_12[siz] | reg_9[a1reg & 7] | a0reg | extra_addressing[am0 - ABASE];
768 inst |= siz_12[siz] | reg_9[a1reg & 7] | a0reg;
783 // move USP,An -- move An,USP
785 int m_usp(WORD inst, WORD siz)
790 inst |= a1reg; // USP, An
792 inst |= a0reg; // An, USP
803 int m_moveq(WORD inst, WORD siz)
807 // Arrange for future fixup
808 if (!(a0exattr & DEFINED))
810 AddFixup(FU_BYTE | FU_SEXT, sloc + 1, a0expr);
813 else if ((uint32_t)a0exval + 0x100 >= 0x200)
814 return error(range_error);
816 inst |= reg_9[a1reg] | (a0exval & 0xFF);
824 // movep Dn, disp(An) -- movep disp(An), Dn
826 int m_movep(WORD inst, WORD siz)
828 // Tell ea0gen to lay off the 0(a0) optimisations on this one
836 inst |= reg_9[a0reg] | a1reg;
846 inst |= reg_9[a1reg] | a0reg;
863 int m_br(WORD inst, WORD siz)
865 if (a0exattr & DEFINED)
867 if ((a0exattr & TDB) != cursect)
869 //printf("m_br(): a0exattr = %X, cursect = %X, a0exval = %X, sloc = %X\n", a0exattr, cursect, a0exval, sloc);
870 return error(rel_error);
873 uint32_t v = (uint32_t)a0exval - (sloc + 2);
875 // Optimize branch instr. size
878 if (CHECK_OPTS(OPT_BSR_BCC_S) && (v != 0) && ((v + 0x80) < 0x100))
885 warn("Bcc.w/BSR.w converted to .s");
892 if ((v + 0x8000) > 0x10000)
893 return error(range_error);
901 if (siz == SIZB || siz == SIZS)
903 if ((v + 0x80) >= 0x100)
904 return error(range_error);
911 if ((v + 0x8000) >= 0x10000)
912 return error(range_error);
920 else if (siz == SIZN)
923 if (siz == SIZB || siz == SIZS)
926 AddFixup(FU_BBRA | FU_PCREL | FU_SEXT, sloc, a0expr);
934 AddFixup(FU_WORD | FU_PCREL | FU_LBRA | FU_ISBRA, sloc, a0expr);
945 int m_addq(WORD inst, WORD siz)
947 inst |= siz_6[siz] | am1 | a1reg;
949 if (a0exattr & DEFINED)
951 if ((a0exval > 8) || (a0exval == 0)) // Range in 1..8
952 return error(range_error);
954 inst |= (a0exval & 7) << 9;
959 AddFixup(FU_QUICK, sloc, a0expr);
972 int m_trap(WORD inst, WORD siz)
976 if (a0exattr & DEFINED)
979 return error(abs_error);
982 return error(range_error);
988 return error(undef_error);
995 // movem <rlist>,ea -- movem ea,<rlist>
997 int m_movem(WORD inst, WORD siz)
1005 return error("bad size suffix");
1012 // Handle #<expr>, ea
1015 if (abs_expr(&eval) != OK)
1018 if (eval >= 0x10000L)
1019 return error(range_error);
1025 if ((*tok >= KW_D0) && (*tok <= KW_A7))
1028 if (reglist(&rmask) < 0)
1033 return error("missing comma");
1038 inst |= am0 | a0reg;
1040 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
1041 return error("invalid addressing mode");
1043 // If APREDEC, reverse register mask
1049 for(i=0x8000; i; i>>=1, w>>=1)
1050 rmask = (WORD)((rmask << 1) | w & 1);
1059 inst |= 0x0400 | am0 | a0reg;
1062 return error("missing comma");
1065 return error("missing register list");
1072 if (abs_expr(&eval) != OK)
1075 if (eval >= 0x10000)
1076 return error(range_error);
1080 else if (reglist(&rmask) < 0)
1083 if (!(amsktab[am0] & (C_CTRL | M_APOSTINC)))
1084 return error("invalid addressing mode");
1096 // CLR.x An ==> SUBA.x An,An
1098 int m_clra(WORD inst, WORD siz)
1100 inst |= a0reg | reg_9[a0reg] | lwsiz_8[siz];
1108 // CLR.L Dn ==> CLR.L An or MOVEQ #0,Dx
1110 int m_clrd(WORD inst, WORD siz)
1112 if (!CHECK_OPTS(OPT_CLR_DX))
1115 inst = (a0reg << 9) | B16(01110000, 00000000);
1123 ////////////////////////////////////////
1125 // 68020/30/40 instructions
1127 ////////////////////////////////////////
1132 int m_br30(WORD inst, WORD siz)
1134 if (a0exattr & DEFINED)
1136 if ((a0exattr & TDB) != cursect)
1137 return error(rel_error);
1139 uint32_t v = (uint32_t)a0exval - (sloc + 2);
1148 AddFixup(FU_LONG | FU_PCREL | FU_SEXT, sloc, a0expr);
1156 // bfchg, bfclr, bfexts, bfextu, bfffo, bfins, bfset
1157 // (68020, 68030, 68040)
1159 int m_bfop(WORD inst, WORD siz)
1161 if ((bfval1 > 31) || (bfval1 < 0))
1162 return error("bfxxx offset: immediate value must be between 0 and 31");
1164 // First instruction word - just the opcode and first EA
1165 // Note: both am1 is ORed because solely of bfins - maybe it's a good idea
1166 // to make a dedicated function for it?
1173 if (bfval2 > 31 || bfval2 < 0)
1174 return error("bfxxx width: immediate value must be between 0 and 31");
1176 // For Dw both immediate and register number are stuffed
1177 // into the same field O_o
1178 bfparam2 = (bfval2 << 0);
1182 bfparam1 = (bfval1 << 6);
1184 bfparam1 = bfval1 << 12;
1186 D_word((inst | am0 | a0reg | am1 | a1reg));
1187 ea0gen(siz); // Generate EA
1189 // Second instruction word - Dest register (if exists), Do, Offset, Dw, Width
1190 inst = bfparam1 | bfparam2;
1196 inst |= a0reg << 12;
1205 // bkpt (68EC000, 68010, 68020, 68030, 68040, CPU32)
1207 int m_bkpt(WORD inst, WORD siz)
1211 if (a0exattr & DEFINED)
1214 return error(abs_error);
1217 return error(range_error);
1223 return error(undef_error);
1232 int m_callm(WORD inst, WORD siz)
1239 if (a0exattr & DEFINED)
1242 return error(abs_error);
1245 return error(range_error);
1247 inst = (uint16_t)a0exval;
1251 return error(undef_error);
1261 // cas (68020, 68030, 68040)
1263 int m_cas(WORD inst, WORD siz)
1269 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1270 return error(unsupport);
1285 return error("bad size suffix");
1290 if ((*tok < KW_D0) && (*tok > KW_D7))
1291 return error("CAS accepts only data registers");
1293 inst2 = (*tok++) & 7;
1296 return error("missing comma");
1299 if ((*tok < KW_D0) && (*tok > KW_D7))
1300 return error("CAS accepts only data registers");
1302 inst2 |= ((*tok++) & 7) << 6;
1305 return error("missing comma");
1308 if ((modes = amode(1)) < 0)
1312 return error("too many ea fields");
1315 return error("extra (unexpected) text found");
1317 // Reject invalid ea modes
1318 amsk = amsktab[am0];
1320 if ((amsk & (M_AIND | M_APOSTINC | M_APREDEC | M_ADISP | M_AINDEXED | M_ABSW | M_ABSL | M_ABASE | M_MEMPOST | M_MEMPRE)) == 0)
1321 return error("unsupported addressing mode");
1323 inst |= am0 | a0reg;
1333 // cas2 (68020, 68030, 68040)
1335 int m_cas2(WORD inst, WORD siz)
1339 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1340 return error(unsupport);
1355 return error("bad size suffix");
1360 if ((*tok < KW_D0) && (*tok > KW_D7))
1361 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1363 inst2 = (*tok++) & 7;
1366 return error("missing colon");
1369 if ((*tok < KW_D0) && (*tok > KW_D7))
1370 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1372 inst3 = (*tok++) & 7;
1375 return error("missing comma");
1378 if ((*tok < KW_D0) && (*tok > KW_D7))
1379 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1381 inst2 |= ((*tok++) & 7) << 6;
1384 return error("missing colon");
1387 if ((*tok < KW_D0) && (*tok > KW_D7))
1388 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1390 inst3 |= ((*tok++) & 7) << 6;
1393 return error("missing comma");
1397 return error("missing (");
1398 if ((*tok >= KW_D0) && (*tok <= KW_D7))
1399 inst2 |= (((*tok++) & 7) << 12) | (0 << 15);
1400 else if ((*tok >= KW_A0) && (*tok <= KW_A7))
1401 inst2 |= (((*tok++) & 7) << 12) | (1 << 15);
1403 return error("CAS accepts either data or address registers for Rn1:Rn2 pair");
1406 return error("missing (");
1409 return error("missing colon");
1413 return error("missing (");
1414 if ((*tok >= KW_D0) && (*tok <= KW_D7))
1415 inst3 |= (((*tok++) & 7) << 12) | (0 << 15);
1416 else if ((*tok >= KW_A0) && (*tok <= KW_A7))
1417 inst3 |= (((*tok++) & 7) << 12) | (1 << 15);
1419 return error("CAS accepts either data or address registers for Rn1:Rn2 pair");
1422 return error("missing (");
1425 return error("extra (unexpected) text found");
1436 // cmp2 (68020, 68030, 68040, CPU32)
1438 int m_cmp2(WORD inst, WORD siz)
1440 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1441 return error(unsupport);
1443 switch (siz & 0x000F)
1457 WORD flg = inst; // Save flag bits
1458 inst &= ~0x3F; // Clobber flag bits in instr
1460 // Install "standard" instr size bits
1466 // OR-in register number
1468 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1470 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1476 inst |= am1 | a1reg; // Get ea1 into instr
1477 D_word(inst); // Deposit instr
1479 // Generate ea0 if requested
1483 ea1gen(siz); // Generate ea1
1488 inst |= am0 | a0reg; // Get ea0 into instr
1489 D_word(inst); // Deposit instr
1490 ea0gen(siz); // Generate ea0
1492 // Generate ea1 if requested
1497 // If we're called from chk2 then bit 11 of size will be set. This is just
1498 // a dumb mechanism to pass this, required by the extension word. (You might
1499 // have noticed the siz & 15 thing above!)
1500 inst = (a1reg << 12) | (siz & (1 << 11));
1512 // chk2 (68020, 68030, 68040, CPU32)
1514 int m_chk2(WORD inst, WORD siz)
1516 return m_cmp2(inst, siz | (1 << 11));
1521 // cpbcc(68020, 68030)
1523 int m_cpbr(WORD inst, WORD siz)
1525 if ((activecpu & (CPU_68020 | CPU_68030)) == 0)
1526 return error(unsupport);
1528 if (a0exattr & DEFINED)
1530 if ((a0exattr & TDB) != cursect)
1531 return error(rel_error);
1533 uint32_t v = (uint32_t)a0exval - (sloc + 2);
1535 // Optimize branch instr. size
1538 if ((v != 0) && ((v + 0x8000) < 0x10000))
1548 if ((v + 0x8000) >= 0x10000)
1549 return error(range_error);
1557 else if (siz == SIZN)
1564 AddFixup(FU_LONG | FU_PCREL | FU_SEXT, sloc, a0expr);
1572 AddFixup(FU_WORD | FU_PCREL | FU_SEXT, sloc, a0expr);
1581 // cpdbcc(68020, 68030)
1583 int m_cpdbr(WORD inst, WORD siz)
1588 WORD condition = inst & 0x1F; // Grab condition sneakily placed in the lower 5 bits of inst
1589 inst &= 0xFFE0; // And then mask them out - you ain't seen me, roit?
1591 inst |= (1 << 9); // Bolt on FPU id
1598 if (a1exattr & DEFINED)
1600 if ((a1exattr & TDB) != cursect)
1601 return error(rel_error);
1603 v = (uint32_t)a1exval - sloc;
1605 if (v + 0x8000 > 0x10000)
1606 return error(range_error);
1612 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
1623 int m_divs(WORD inst, WORD siz)
1625 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1626 return error(unsupport);
1628 WORD flg = inst; // Save flag bits
1629 inst &= ~0x3F; // Clobber flag bits in instr
1631 // Install "standard" instr size bits
1637 // OR-in register number
1639 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1641 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1647 inst |= am1 | a1reg; // Get ea1 into instr
1648 D_word(inst); // Deposit instr
1650 // Generate ea0 if requested
1654 ea1gen(siz); // Generate ea1
1659 inst |= am0 | a0reg; // Get ea0 into instr
1660 D_word(inst); // Deposit instr
1661 ea0gen(siz); // Generate ea0
1663 // Generate ea1 if requested
1668 inst = a1reg + (a2reg << 12) + (1 << 11);
1678 int m_muls(WORD inst, WORD siz)
1680 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1681 return error(unsupport);
1683 WORD flg = inst; // Save flag bits
1684 inst &= ~0x3F; // Clobber flag bits in instr
1686 // Install "standard" instr size bits
1692 // OR-in register number
1694 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1696 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1702 inst |= am1 | a1reg; // Get ea1 into instr
1703 D_word(inst); // Deposit instr
1706 inst = a1reg + (a2reg << 12) + (1 << 11);
1707 inst |= mulmode; // add size bit
1710 // Generate ea0 if requested
1714 ea1gen(siz); // Generate ea1
1719 inst |= am0 | a0reg; // Get ea0 into instr
1720 D_word(inst); // Deposit instr
1722 inst = a1reg + (a2reg << 12) + (1 << 11);
1723 inst |= mulmode; // add size bit
1726 ea0gen(siz); // Generate ea0
1728 // Generate ea1 if requested
1743 int m_divu(WORD inst, WORD siz)
1745 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1746 return error(unsupport);
1748 //WARNING("divu.l d0,d1 is actually divul.l d0,d1:d1!!!")
1750 WORD flg = inst; // Save flag bits
1751 inst &= ~0x3F; // Clobber flag bits in instr
1753 // Install "standard" instr size bits
1759 // OR-in register number
1761 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1763 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1769 inst |= am1 | a1reg; // Get ea1 into instr
1770 D_word(inst); // Deposit instr
1772 // Generate ea0 if requested
1776 ea1gen(siz); // Generate ea1
1781 inst |= am0 | a0reg; // Get ea0 into instr
1782 D_word(inst); // Deposit instr
1783 ea0gen(siz); // Generate ea0
1785 // Generate ea1 if requested
1790 inst = a1reg + (a2reg << 12);
1800 int m_mulu(WORD inst, WORD siz)
1802 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1803 return error(unsupport);
1805 WORD flg = inst; // Save flag bits
1806 inst &= ~0x3F; // Clobber flag bits in instr
1808 // Install "standard" instr size bits
1814 // OR-in register number
1816 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1818 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1824 inst |= am1 | a1reg; // Get ea1 into instr
1825 D_word(inst); // Deposit instr
1827 // Generate ea0 if requested
1831 ea1gen(siz); // Generate ea1
1836 inst |= am0 | a0reg; // Get ea0 into instr
1837 D_word(inst); // Deposit instr
1838 ea0gen(siz); // Generate ea0
1840 // Generate ea1 if requested
1845 inst = a1reg + (a2reg << 12);
1846 inst |= mulmode; // add size bit
1856 int m_divsl(WORD inst, WORD siz)
1858 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1859 return error(unsupport);
1861 WORD flg = inst; // Save flag bits
1862 inst &= ~0x3F; // Clobber flag bits in instr
1864 // Install "standard" instr size bits
1870 // OR-in register number
1872 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1874 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1880 inst |= am1 | a1reg; // Get ea1 into instr
1881 D_word(inst); // Deposit instr
1883 // Generate ea0 if requested
1887 ea1gen(siz); // Generate ea1
1892 inst |= am0 | a0reg; // Get ea0 into instr
1893 D_word(inst); // Deposit instr
1894 ea0gen(siz); // Generate ea0
1896 // Generate ea1 if requested
1901 inst = a1reg + (a2reg << 12) + (1 << 11) + (1 << 10);
1911 int m_divul(WORD inst, WORD siz)
1913 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1914 return error(unsupport);
1916 WORD flg = inst; // Save flag bits
1917 inst &= ~0x3F; // Clobber flag bits in instr
1919 // Install "standard" instr size bits
1925 // OR-in register number
1927 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1929 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1935 inst |= am1 | a1reg; // Get ea1 into instr
1936 D_word(inst); // Deposit instr
1938 // Generate ea0 if requested
1942 ea1gen(siz); // Generate ea1
1947 inst |= am0 | a0reg; // Get ea0 into instr
1948 D_word(inst); // Deposit instr
1949 ea0gen(siz); // Generate ea0
1951 // Generate ea1 if requested
1956 inst = a1reg + (a2reg << 12) + (1 << 10);
1964 // move16 (ax)+,(ay)+
1966 int m_move16a(WORD inst, WORD siz)
1968 if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1969 return error(unsupport);
1973 inst = (1 << 15) + (a1reg << 12);
1981 // move16 with absolute address
1983 int m_move16b(WORD inst, WORD siz)
1985 if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1986 return error(unsupport);
1992 if (am0 == APOSTINC)
1995 return error("Wasn't this suppose to call m_move16a???");
1998 //move16 (ax)+,(xxx).L
2003 else if (am0 == ABSL)
2007 //move16 (xxx).L,(ax)+
2013 //move16 (xxx).L,(ax)
2018 else if (am0 == AIND)
2020 //move16 (ax),(xxx).L
2033 // pack/unpack (68020/68030/68040)
2035 int m_pack(WORD inst, WORD siz)
2040 return error("bad size suffix");
2042 if (*tok >= KW_D0 && *tok <= KW_D7)
2044 // Dx,Dy,#<adjustment>
2045 inst |= (0 << 3); // R/M
2046 inst |= (*tok++ & 7);
2048 if (*tok != ',' && tok[2] != ',')
2049 return error("missing comma");
2051 if (tok[1] < KW_D0 && tok[1] > KW_D7)
2052 return error(syntax_error);
2054 inst |= ((tok[1] & 7)<<9);
2057 // Fall through for adjustment (common in both valid cases)
2059 else if (*tok == '-')
2061 // -(Ax),-(Ay),#<adjustment>
2062 inst |= (1 << 3); // R/M
2063 tok++; // eat the minus
2065 if ((*tok != '(') && (tok[2]!=')') && (tok[3]!=',') && (tok[4] != '-') && (tok[5] != '(') && (tok[7] != ')') && (tok[8] != ','))
2066 return error(syntax_error);
2068 if (tok[1] < KW_A0 && tok[1] > KW_A7)
2069 return error(syntax_error);
2071 if (tok[5] < KW_A0 && tok[6] > KW_A7)
2072 return error(syntax_error);
2074 inst |= ((tok[1] & 7) << 0);
2075 inst |= ((tok[6] & 7) << 9);
2078 // Fall through for adjustment (common in both valid cases)
2081 return error("invalid syntax");
2083 if ((*tok != CONST) && (*tok != SYMBOL) && (*tok != '-'))
2084 return error(syntax_error);
2086 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2089 if ((a0exattr & DEFINED) == 0)
2090 return error(undef_error);
2092 if (a0exval + 0x8000 > 0x10000)
2096 return error(extra_stuff);
2098 D_word((a0exval & 0xFFFF));
2107 int m_rtm(WORD inst, WORD siz)
2115 else if (am0 == AREG)
2117 inst |= (1 << 3) + a0reg;
2120 return error("rtm only allows data or address registers.");
2131 int m_rtd(WORD inst, WORD siz)
2135 if (a0exattr & DEFINED)
2138 return error(abs_error);
2140 if ((a0exval + 0x8000) <= 0x7FFF)
2141 return error(range_error);
2147 return error(undef_error);
2156 int m_trapcc(WORD inst, WORD siz)
2164 else if (am0 == IMMED)
2168 if (a0exval < 0x10000)
2175 return error("Immediate value too big");
2185 return error("Invalid parameter for trapcc");
2192 // cinvl/p/a (68040)
2194 int m_cinv(WORD inst, WORD siz)
2199 inst |= (0 << 6) | (a1reg);
2203 inst |= (2 << 6) | (a1reg);
2206 inst |= (1 << 6) | (a1reg);
2209 inst |= (3 << 6) | (a1reg);
2219 // cpRESTORE (68020, 68030)
2221 int m_cprest(WORD inst, WORD siz)
2223 if (activecpu & !(CPU_68020 | CPU_68030))
2224 return error(unsupport);
2226 inst |= am0 | a0reg;
2235 // movec (68010, 68020, 68030, 68040, CPU32)
2237 int m_movec(WORD inst, WORD siz)
2241 if (am0 == DREG || am0 == AREG)
2249 inst = (0 << 15) + (a0reg << 12) + CREGlut[a1reg];
2254 inst = (1 << 15) + (a0reg << 12) + CREGlut[a1reg];
2265 inst = (0 << 15) + (a1reg << 12) + CREGlut[a0reg];
2270 inst = (1 << 15) + (a1reg << 12) + CREGlut[a0reg];
2280 // moves (68010, 68020, 68030, 68040, CPU32)
2282 int m_moves(WORD inst, WORD siz)
2284 if (activecpu & !(CPU_68020 | CPU_68030 | CPU_68040))
2285 return error(unsupport);
2289 else if (siz == SIZL)
2296 inst |= am1 | a1reg;
2298 inst = (a0reg << 12) | (1 << 11) | (0 << 15);
2301 else if (am0 == AREG)
2303 inst |= am1 | a1reg;
2305 inst = (a0reg << 12) | (1 << 11) | (1 << 15);
2312 inst |= am0 | a0reg;
2314 inst = (a1reg << 12) | (0 << 11) | (0 << 15);
2319 inst |= am0 | a0reg;
2321 inst = (a1reg << 12) | (0 << 11) | (1 << 15);
2333 int m_pbcc(WORD inst, WORD siz)
2336 return error("Not implemented yet.");
2341 // pflusha (68030, 68040)
2343 int m_pflusha(WORD inst, WORD siz)
2345 if (activecpu == CPU_68030)
2348 inst = (1 << 13) | (1 << 10) | (0 << 5) | 0;
2352 else if (activecpu == CPU_68040)
2354 inst = B16(11110101, 00011000);
2359 return error(unsupport);
2366 // pflush (68030, 68040, 68060)
2368 int m_pflush(WORD inst, WORD siz)
2370 if (activecpu == CPU_68030)
2373 // PFLUSH FC, MASK, < ea >
2381 if (*tok != CONST && *tok != SYMBOL)
2382 return error("function code should be an expression");
2384 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2387 if ((a0exattr & DEFINED) == 0)
2388 return error("function code immediate should be defined");
2390 if (a0exval > 7 && a0exval < 0)
2391 return error("function code out of range (0-7)");
2393 fc = (uint16_t)a0exval;
2403 fc = (1 << 4) | (*tok++ & 7);
2414 return error(syntax_error);
2418 return error("comma exptected");
2421 return error("mask should be an immediate value");
2423 if (*tok != CONST && *tok != SYMBOL)
2424 return error("mask is supposed to be immediate");
2426 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2429 if ((a0exattr & DEFINED) == 0)
2430 return error("mask immediate value should be defined");
2432 if (a0exval > 7 && a0exval < 0)
2433 return error("function code out of range (0-7)");
2435 mask = (uint16_t)a0exval << 5;
2441 inst = (1 << 13) | fc | mask | (4 << 10);
2445 else if (*tok == ',')
2447 // PFLUSH FC, MASK, < ea >
2450 if (amode(0) == ERROR)
2454 return error(extra_stuff);
2456 if (am0 == AIND || am0 == ABSW || am0 == ABSL || am0 == ADISP || am0 == ADISP || am0 == AINDEXED || am0 == ABASE || am0 == MEMPOST || am0 == MEMPRE)
2458 inst |= am0 | a0reg;
2460 inst = (1 << 13) | fc | mask | (6 << 10);
2466 return error("unsupported addressing mode");
2470 return error(syntax_error);
2474 else if (activecpu == CPU_68040 || activecpu == CPU_68060)
2478 if (*tok != '(' && tok[2] != ')')
2479 return error(syntax_error);
2481 if (tok[1] < KW_A0 && tok[1] > KW_A7)
2482 return error("expected (An)");
2484 if ((inst & 7) == 7)
2485 // With pflushn/pflush there's no easy way to distinguish between
2486 // the two in 68040 mode. Ideally the opcode bitfields would have
2487 // been hardcoded in 68ktab but there is aliasing between 68030
2488 // and 68040 opcode. So we just set the 3 lower bits to 1 in
2489 // pflushn inside 68ktab and detect it here.
2490 inst = (inst & 0xff8) | 8;
2492 inst |= (tok[1] & 7) | (5 << 8);
2495 return error(extra_stuff);
2500 return error(unsupport);
2509 int m_pflushr(WORD inst, WORD siz)
2513 WORD flg = inst; // Save flag bits
2514 inst &= ~0x3F; // Clobber flag bits in instr
2516 // Install "standard" instr size bits
2522 // OR-in register number
2524 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
2526 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
2532 inst |= am1 | a1reg; // Get ea1 into instr
2533 D_word(inst); // Deposit instr
2535 // Generate ea0 if requested
2539 ea1gen(siz); // Generate ea1
2544 inst |= am0 | a0reg; // Get ea0 into instr
2545 D_word(inst); // Deposit instr
2546 ea0gen(siz); // Generate ea0
2548 // Generate ea1 if requested
2553 D_word(B16(10100000, 00000000));
2559 // ploadr, ploadw (68030)
2561 int m_pload(WORD inst, WORD siz, WORD extension)
2563 // TODO: 68851 support is not added yet.
2564 // None of the ST series of computers had a 68020 + 68851 socket and since
2565 // this is an Atari targetted assembler...
2574 if (a0reg == KW_SFC - KW_SFC)
2576 else if (a0reg == KW_DFC - KW_SFC)
2579 return error("illegal control register specified");
2583 inst = (1 << 3) | a0reg;
2586 if ((a0exattr & DEFINED) == 0)
2587 return error("constant value must be defined");
2589 inst = (2 << 3) | (uint16_t)a0exval;
2593 inst |= extension | (1 << 13);
2602 int m_ploadr(WORD inst, WORD siz)
2604 return m_pload(inst, siz, 1 << 9);
2608 int m_ploadw(WORD inst, WORD siz)
2610 return m_pload(inst, siz, 0 << 9);
2615 // pmove (68030/68851)
2617 int m_pmove(WORD inst, WORD siz)
2621 // TODO: 68851 support is not added yet. None of the ST series of
2622 // computers had a 68020 + 68851 socket and since this is an Atari
2623 // targetted assembler.... (same for 68EC030)
2626 inst2 = inst & (1 << 8); // Copy the flush bit over to inst2 in case we're called from m_pmovefd
2627 inst &= ~(1 << 8); // And mask it out
2634 else if (am1 == CREG)
2640 return error("pmove sez: Wut?");
2642 // The instruction is a quad-word (8 byte) operation
2643 // for the CPU root pointer and the supervisor root pointer.
2644 // It is a long - word operation for the translation control register
2645 // and the transparent translation registers(TT0 and TT1).
2646 // It is a word operation for the MMU status register.
2648 if (((reg == (KW_URP - KW_SFC)) || (reg == (KW_SRP - KW_SFC)))
2649 && ((siz != SIZD) && (siz != SIZN)))
2650 return error(siz_error);
2652 if (((reg == (KW_TC - KW_SFC)) || (reg == (KW_TT0 - KW_SFC)) || (reg == (KW_TT1 - KW_SFC)))
2653 && ((siz != SIZL) && (siz != SIZN)))
2654 return error(siz_error);
2656 if ((reg == (KW_MMUSR - KW_SFC)) && ((siz != SIZW) && (siz != SIZN)))
2657 return error(siz_error);
2661 inst |= am1 | a1reg;
2664 else if (am1 == CREG)
2666 inst |= am0 | a0reg;
2670 switch (reg + KW_SFC)
2673 inst2 |= (0 << 10) + (1 << 14); break;
2675 inst2 |= (2 << 10) + (1 << 14); break;
2677 inst2 |= (3 << 10) + (1 << 14); break;
2679 inst2 |= (2 << 10) + (0 << 13); break;
2681 inst2 |= (3 << 10) + (0 << 13); break;
2684 inst2 |= (1 << 9) + (3 << 13);
2686 inst2 |= (0 << 9) + (3 << 13);
2689 return error("unsupported register");
2697 else if (am1 == CREG)
2707 int m_pmovefd(WORD inst, WORD siz)
2711 return m_pmove(inst | (1 << 8), siz);
2718 int m_ptrapcc(WORD inst, WORD siz)
2721 // We stash the 5 condition bits inside the opcode in 68ktab (bits 0-4),
2722 // so we need to extract them first and fill in the clobbered bits.
2723 WORD opcode = inst & 0x1F;
2724 inst = (inst & 0xFFE0) | (0x18);
2733 else if (siz == SIZL)
2740 else if (siz == SIZN)
2752 // ptestr, ptestw (68030)
2754 int m_ptest(WORD inst, WORD siz)
2758 if (activecpu == CPU_68030)
2759 return error("Not implemented yet.");
2760 else if (activecpu == CPU_68040)
2761 return error("Not implemented yet.");
2767 #define FPU_NOWARN 0
2768 #define FPU_P_EMUL 1
2769 #define FPU_P2_EMU 2
2774 // Generate a FPU opcode
2776 static inline int gen_fpu(WORD inst, WORD siz, WORD opmode, WORD emul)
2778 if (am0 < AM_NONE) // Check first operand for ea or fp - is this right?
2780 inst |= (1 << 9); // Bolt on FPU id
2787 inst = 1 << 14; // R/M field (we have ea so have to set this to 1)
2791 case SIZB: inst |= (6 << 10); break;
2792 case SIZW: inst |= (4 << 10); break;
2793 case SIZL: inst |= (0 << 10); break;
2795 case SIZS: inst |= (1 << 10); break;
2796 case SIZD: inst |= (5 << 10); break;
2797 case SIZX: inst |= (2 << 10); break;
2802 warn("This encoding will cause an unimplemented data type exception in the MC68040 to allow emulation in software.");
2806 return error("Something bad happened, possibly, in gen_fpu.");
2810 inst |= (a1reg << 7);
2817 inst |= (1 << 9); // Bolt on FPU id
2821 inst |= (a1reg << 7);
2826 if ((emul & FPU_FPSP) && (activefpu == FPU_68040))
2827 warn("Instruction is emulated in 68040");
2834 // fabs, fsabs, fdabs (6888X, 68040)
2836 int m_fabs(WORD inst, WORD siz)
2838 return gen_fpu(inst, siz, B8(00011000), FPU_P_EMUL);
2842 int m_fsabs(WORD inst, WORD siz)
2844 if (activefpu == FPU_68040)
2845 return gen_fpu(inst, siz, B8(01011000), FPU_P_EMUL);
2847 return error("Unsupported in current FPU");
2851 int m_fdabs(WORD inst, WORD siz)
2853 if (activefpu == FPU_68040)
2854 return gen_fpu(inst, siz, B8(01011100), FPU_P_EMUL);
2856 return error("Unsupported in current FPU");
2861 // facos (6888X, 68040FPSP)
2863 int m_facos(WORD inst, WORD siz)
2865 return gen_fpu(inst, siz, B8(00011100), FPU_FPSP);
2870 // fadd (6888X, 68040FPSP)
2872 int m_fadd(WORD inst, WORD siz)
2874 return gen_fpu(inst, siz, B8(00100010), FPU_P_EMUL);
2878 int m_fsadd(WORD inst, WORD siz)
2880 if (activefpu == FPU_68040)
2881 return gen_fpu(inst, siz, B8(01100010), FPU_P_EMUL);
2883 return error("Unsupported in current FPU");
2887 int m_fdadd(WORD inst, WORD siz)
2889 if (activefpu == FPU_68040)
2890 return gen_fpu(inst, siz, B8(01100110), FPU_P_EMUL);
2892 return error("Unsupported in current FPU");
2897 // fasin (6888X, 68040FPSP)f
2899 int m_fasin(WORD inst, WORD siz)
2901 return gen_fpu(inst, siz, B8(00001100), FPU_FPSP);
2906 // fatan (6888X, 68040FPSP)
2908 int m_fatan(WORD inst, WORD siz)
2910 return gen_fpu(inst, siz, B8(00001010), FPU_FPSP);
2915 // fatanh (6888X, 68040FPSP)
2917 int m_fatanh(WORD inst, WORD siz)
2919 return gen_fpu(inst, siz, B8(00001101), FPU_FPSP);
2924 // fcmp (6888X, 68040)
2926 int m_fcmp(WORD inst, WORD siz)
2928 return gen_fpu(inst, siz, B8(00111000), FPU_P_EMUL);
2933 // fcos (6888X, 68040FPSP)
2935 int m_fcos(WORD inst, WORD siz)
2937 return gen_fpu(inst, siz, B8(00011101), FPU_FPSP);
2942 // fcosh (6888X, 68040FPSP)
2944 int m_fcosh(WORD inst, WORD siz)
2946 return gen_fpu(inst, siz, B8(00011001), FPU_FPSP);
2951 // fdbcc (6888X, 68040)
2953 int m_fdbcc(WORD inst, WORD siz)
2955 WORD opcode = inst & 0x3F; // Grab conditional bitfield
2965 if (a1exattr & DEFINED)
2967 if ((a1exattr & TDB) != cursect)
2968 return error(rel_error);
2970 uint32_t v = (uint32_t)a1exval - sloc;
2972 if ((v + 0x8000) > 0x10000)
2973 return error(range_error);
2979 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
2988 // fdiv (6888X, 68040)
2990 int m_fdiv(WORD inst, WORD siz)
2992 return gen_fpu(inst, siz, B8(00100000), FPU_P_EMUL);
2996 int m_fsdiv(WORD inst, WORD siz)
2998 if (activefpu == FPU_68040)
2999 return gen_fpu(inst, siz, B8(01100000), FPU_P_EMUL);
3001 return error("Unsupported in current FPU");
3005 int m_fddiv(WORD inst, WORD siz)
3007 if (activefpu == FPU_68040)
3008 return gen_fpu(inst, siz, B8(01100100), FPU_P_EMUL);
3010 return error("Unsupported in current FPU");
3015 // fetox (6888X, 68040FPSP)
3017 int m_fetox(WORD inst, WORD siz)
3019 return gen_fpu(inst, siz, B8(00010000), FPU_FPSP);
3024 // fetoxm1 (6888X, 68040FPSP)
3026 int m_fetoxm1(WORD inst, WORD siz)
3028 return gen_fpu(inst, siz, B8(00001000), FPU_FPSP);
3033 // fgetexp (6888X, 68040FPSP)
3035 int m_fgetexp(WORD inst, WORD siz)
3037 return gen_fpu(inst, siz, B8(00011110), FPU_FPSP);
3042 // fgetman (6888X, 68040FPSP)
3044 int m_fgetman(WORD inst, WORD siz)
3046 return gen_fpu(inst, siz, B8(00011111), FPU_FPSP);
3051 // fint (6888X, 68040FPSP)
3053 int m_fint(WORD inst, WORD siz)
3056 // special case - fint fpx = fint fpx,fpx
3059 return gen_fpu(inst, siz, B8(00000001), FPU_FPSP);
3064 // fintrz (6888X, 68040FPSP)
3066 int m_fintrz(WORD inst, WORD siz)
3069 // special case - fintrz fpx = fintrz fpx,fpx
3072 return gen_fpu(inst, siz, B8(00000011), FPU_FPSP);
3077 // flog10 (6888X, 68040FPSP)
3079 int m_flog10(WORD inst, WORD siz)
3081 return gen_fpu(inst, siz, B8(00010101), FPU_FPSP);
3086 // flog2 (6888X, 68040FPSP)
3088 int m_flog2(WORD inst, WORD siz)
3090 return gen_fpu(inst, siz, B8(00010110), FPU_FPSP);
3095 // flogn (6888X, 68040FPSP)
3097 int m_flogn(WORD inst, WORD siz)
3099 return gen_fpu(inst, siz, B8(00010100), FPU_FPSP);
3104 // flognp1 (6888X, 68040FPSP)
3106 int m_flognp1(WORD inst, WORD siz)
3108 return gen_fpu(inst, siz, B8(00000110), FPU_FPSP);
3113 // fmod (6888X, 68040FPSP)
3115 int m_fmod(WORD inst, WORD siz)
3117 return gen_fpu(inst, siz, B8(00100001), FPU_FPSP);
3122 // fmove (6888X, 68040)
3124 int m_fmove(WORD inst, WORD siz)
3127 if ((am0 == FREG) && (am1 < AM_USP))
3131 inst |= am1 | a1reg;
3140 case SIZB: inst |= (6 << 10); break;
3141 case SIZW: inst |= (4 << 10); break;
3142 case SIZL: inst |= (0 << 10); break;
3144 case SIZS: inst |= (1 << 10); break;
3145 case SIZD: inst |= (5 << 10); break;
3146 case SIZX: inst |= (2 << 10); break;
3147 case SIZP: inst |= (3 << 10);
3148 // In P size we have 2 cases: {#k} where k is immediate
3149 // and {Dn} where Dn=Data register
3154 inst |= bfval1 << 4;
3159 if (bfval1 > 63 && bfval1 < -64)
3160 return error("K-factor must be between -64 and 63");
3162 inst |= bfval1 & 127;
3167 return error("Something bad happened, possibly.");
3171 // Destination specifier
3172 inst |= (a0reg << 7);
3180 else if ((am0 < AM_USP) && (am1 == FREG))
3185 inst |= am0 | a0reg;
3194 case SIZB: inst |= (6 << 10); break;
3195 case SIZW: inst |= (4 << 10); break;
3196 case SIZL: inst |= (0 << 10); break;
3198 case SIZS: inst |= (1 << 10); break;
3199 case SIZD: inst |= (5 << 10); break;
3200 case SIZX: inst |= (2 << 10); break;
3201 case SIZP: inst |= (3 << 10); break;
3203 return error("Something bad happened, possibly.");
3207 // Destination specifier
3208 inst |= (a1reg << 7);
3216 else if ((am0 == FREG) && (am1 == FREG))
3218 // register-to-register
3219 // Essentially ea to register with R/0=0
3229 return error("Invalid size");
3232 inst |= (a0reg << 10);
3234 // Destination register
3235 inst |= (a1reg << 7);
3245 // fmove (6888X, 68040)
3247 int m_fmovescr(WORD inst, WORD siz)
3249 // Move Floating-Point System Control Register (FPCR)
3253 if ((am0 == FPSCR) && (am1 < AM_USP))
3255 inst |= am1 | a1reg;
3257 inst = (1 << 13) + (1 << 15);
3263 else if ((am1 == FPSCR) && (am0 < AM_USP))
3265 inst |= am0 | a0reg;
3267 inst = (0 << 13) + (1 << 15);
3274 return error("m_fmovescr says: wut?");
3278 // fsmove/fdmove (68040)
3280 int m_fsmove(WORD inst, WORD siz)
3282 return error("Not implemented yet.");
3285 if (activefpu == FPU_68040)
3286 return gen_fpu(inst, siz, B8(01100100), FPU_P_EMUL);
3288 return error("Unsupported in current FPU");
3293 int m_fdmove(WORD inst, WORD siz)
3295 return error("Not implemented yet.");
3298 if (activefpu == FPU_68040)
3299 return gen_fpu(inst, siz, B8(01100100), FPU_P_EMUL);
3301 return error("Unsupported in current FPU");
3307 // fmovecr (6888X, 68040FPSP)
3309 int m_fmovecr(WORD inst, WORD siz)
3317 if (activefpu == FPU_68040)
3318 warn("Instruction is emulated in 68040");
3325 // fmovem (6888X, 68040)
3327 int m_fmovem(WORD inst, WORD siz)
3332 if (siz == SIZX || siz == SIZN)
3334 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
3336 //fmovem.x <rlist>,ea
3337 if (fpu_reglist_left(®mask) < 0)
3341 return error("missing comma");
3346 inst |= am0 | a0reg;
3348 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3349 return error("invalid addressing mode");
3352 inst = (1 << 15) | (1 << 14) | (1 << 13) | (0 << 11) | regmask;
3357 else if ((*tok >= KW_D0) && (*tok <= KW_D7))
3360 datareg = (*tok++ & 7) << 10;
3363 return error("missing comma");
3368 inst |= am0 | a0reg;
3370 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3371 return error("invalid addressing mode");
3374 inst = (1 << 15) | (1 << 14) | (1 << 13) | (1 << 11) | (datareg << 4);
3385 inst |= am0 | a0reg;
3388 return error("missing comma");
3390 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
3392 //fmovem.x ea,<rlist>
3393 if (fpu_reglist_right(®mask) < 0)
3397 inst = (1 << 15) | (1 << 14) | (0 << 13) | (2 << 11) | regmask;
3405 datareg = (*tok++ & 7) << 10;
3407 inst = (1 << 15) | (1 << 14) | (0 << 13) | (3 << 11) | (datareg << 4);
3414 else if (siz == SIZL)
3416 if ((*tok == KW_FPCR) || (*tok == KW_FPSR) || (*tok == KW_FPIAR))
3418 //fmovem.l <rlist>,ea
3419 regmask = (1 << 15) | (1 << 13);
3421 if (*tok == KW_FPCR)
3423 regmask |= (1 << 12);
3428 if (*tok == KW_FPSR)
3430 regmask |= (1 << 11);
3435 if (*tok == KW_FPIAR)
3437 regmask |= (1 << 10);
3442 if ((*tok == '/') || (*tok == '-'))
3449 return error("missing comma");
3454 inst |= am0 | a0reg;
3461 //fmovem.l ea,<rlist>
3465 inst |= am0 | a0reg;
3468 return error("missing comma");
3470 regmask = (1 << 15) | (0 << 13);
3473 if (*tok == KW_FPCR)
3475 regmask |= (1 << 12);
3480 if (*tok == KW_FPSR)
3482 regmask |= (1 << 11);
3487 if (*tok == KW_FPIAR)
3489 regmask |= (1 << 10);
3494 if ((*tok == '/') || (*tok == '-'))
3501 return error("extra (unexpected) text found");
3503 inst |= am0 | a0reg;
3510 return error("bad size suffix");
3517 // fmul (6888X, 68040)
3519 int m_fmul(WORD inst, WORD siz)
3521 return gen_fpu(inst, siz, B8(00100011), FPU_P_EMUL);
3525 int m_fsmul(WORD inst, WORD siz)
3527 if (activefpu == FPU_68040)
3528 return gen_fpu(inst, siz, B8(01100011), FPU_P_EMUL);
3530 return error("Unsupported in current FPU");
3534 int m_fdmul(WORD inst, WORD siz)
3536 if (activefpu == FPU_68040)
3537 return gen_fpu(inst, siz, B8(01100111), FPU_P_EMUL);
3539 return error("Unsupported in current FPU");
3544 // fneg (6888X, 68040)
3546 int m_fneg(WORD inst, WORD siz)
3548 return gen_fpu(inst, siz, B8(00011010), FPU_P_EMUL);
3552 int m_fsneg(WORD inst, WORD siz)
3554 if (activefpu == FPU_68040)
3555 return gen_fpu(inst, siz, B8(01011010), FPU_P_EMUL);
3557 return error("Unsupported in current FPU");
3561 int m_fdneg(WORD inst, WORD siz)
3563 if (activefpu == FPU_68040)
3564 return gen_fpu(inst, siz, B8(01011110), FPU_P_EMUL);
3566 return error("Unsupported in current FPU");
3571 // fnop (6888X, 68040)
3573 int m_fnop(WORD inst, WORD siz)
3575 return gen_fpu(inst, siz, B8(00000000), FPU_P_EMUL);
3580 // frem (6888X, 68040FPSP)
3582 int m_frem(WORD inst, WORD siz)
3584 return gen_fpu(inst, siz, B8(00100101), FPU_FPSP);
3589 // fscale (6888X, 68040FPSP)
3591 int m_fscale(WORD inst, WORD siz)
3593 return gen_fpu(inst, siz, B8(00100110), FPU_FPSP);
3598 // FScc (6888X, 68040), cpScc (68851, 68030), PScc (68851)
3599 // TODO: Add check for PScc to ensure 68020+68851 active
3600 // TODO: Add check for cpScc to ensure 68020+68851, 68030
3602 int m_fscc(WORD inst, WORD siz)
3604 // We stash the 5 condition bits inside the opcode in 68ktab (bits 4-0),
3605 // so we need to extract them first and fill in the clobbered bits.
3606 WORD opcode = inst & 0x1F;
3608 inst |= am0 | a0reg;
3617 // FTRAPcc (6888X, 68040)
3619 int m_ftrapcc(WORD inst, WORD siz)
3621 // We stash the 5 condition bits inside the opcode in 68ktab (bits 3-7),
3622 // so we need to extract them first and fill in the clobbered bits.
3623 WORD opcode = (inst >> 3) & 0x1F;
3624 inst = (inst & 0xFF07) | (0xF << 3);
3633 else if (siz == SIZL)
3640 else if (siz = SIZN)
3653 // fsgldiv (6888X, 68040)
3655 int m_fsgldiv(WORD inst, WORD siz)
3657 return gen_fpu(inst, siz, B8(00100100), FPU_P_EMUL);
3662 // fsglmul (6888X, 68040)
3664 int m_fsglmul(WORD inst, WORD siz)
3666 return gen_fpu(inst, siz, B8(00100111), FPU_P_EMUL);
3671 // fsin (6888X, 68040FPSP)
3673 int m_fsin(WORD inst, WORD siz)
3675 return gen_fpu(inst, siz, B8(00001110), FPU_FPSP);
3680 // fsincos (6888X, 68040FPSP)
3682 int m_fsincos(WORD inst, WORD siz)
3684 // Swap a1reg, a2reg as a2reg should be stored in the bitfield gen_fpu
3691 if (gen_fpu(inst, siz, B8(00110000), FPU_FPSP) == OK)
3702 // fsin (6888X, 68040FPSP)
3704 int m_fsinh(WORD inst, WORD siz)
3706 return gen_fpu(inst, siz, B8(00000010), FPU_FPSP);
3711 // fsqrt (6888X, 68040)
3713 int m_fsqrt(WORD inst, WORD siz)
3715 return gen_fpu(inst, siz, B8(00000100), FPU_P_EMUL);
3719 int m_fsfsqrt(WORD inst, WORD siz)
3721 if (activefpu == FPU_68040)
3722 return gen_fpu(inst, siz, B8(01000001), FPU_P_EMUL);
3724 return error("Unsupported in current FPU");
3728 int m_fdfsqrt(WORD inst, WORD siz)
3730 if (activefpu == FPU_68040)
3731 return gen_fpu(inst, siz, B8(01000101), FPU_P_EMUL);
3733 return error("Unsupported in current FPU");
3738 // fsub (6888X, 68040)
3740 int m_fsub(WORD inst, WORD siz)
3742 return gen_fpu(inst, siz, B8(00101000), FPU_P_EMUL);
3746 int m_fsfsub(WORD inst, WORD siz)
3748 if (activefpu == FPU_68040)
3749 return gen_fpu(inst, siz, B8(01101000), FPU_P_EMUL);
3751 return error("Unsupported in current FPU");
3755 int m_fdsub(WORD inst, WORD siz)
3757 if (activefpu == FPU_68040)
3758 return gen_fpu(inst, siz, B8(01101100), FPU_P_EMUL);
3760 return error("Unsupported in current FPU");
3765 // ftan (6888X, 68040FPSP)
3767 int m_ftan(WORD inst, WORD siz)
3769 return gen_fpu(inst, siz, B8(00001111), FPU_FPSP);
3774 // ftanh (6888X, 68040FPSP)
3776 int m_ftanh(WORD inst, WORD siz)
3778 return gen_fpu(inst, siz, B8(00001001), FPU_FPSP);
3783 // ftentox (6888X, 68040FPSP)
3785 int m_ftentox(WORD inst, WORD siz)
3787 return gen_fpu(inst, siz, B8(00010010), FPU_FPSP);
3792 // ftst (6888X, 68040)
3794 int m_ftst(WORD inst, WORD siz)
3796 return gen_fpu(inst, siz, B8(00111010), FPU_P_EMUL);
3801 // ftwotox (6888X, 68040FPSP)
3803 int m_ftwotox(WORD inst, WORD siz)
3805 return gen_fpu(inst, siz, B8(00010001), FPU_FPSP);