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 inst |= am0 | a0reg | lwsiz_8[siz] | reg_9[a1reg];
457 ea0gen(siz); // Generate EA
464 // If bit 0 of `inst' is 1, install size bits in bits 6..7 of instr.
465 // If bit 1 of `inst' is 1, install a1reg in bits 9..11 of instr.
467 int m_reg(WORD inst, WORD siz)
474 // Install other register (9..11)
475 inst |= reg_9[a1reg];
477 inst &= ~7; // Clear off crufty bits
478 inst |= a0reg; // Install first register
488 int m_imm(WORD inst, WORD siz)
500 int m_imm8(WORD inst, WORD siz)
513 int m_shr(WORD inst, WORD siz)
515 inst |= reg_9[a0reg] | a1reg | siz_6[siz];
525 int m_shi(WORD inst, WORD siz)
527 inst |= a1reg | siz_6[siz];
529 if (a0exattr & DEFINED)
532 return error(range_error);
534 inst |= (a0exval & 7) << 9;
539 AddFixup(FU_QUICK, sloc, a0expr);
548 // {bset, btst, bchg, bclr} -- #immed,ea -- Dn,ea
550 int m_bitop(WORD inst, WORD siz)
552 // Enforce instruction sizes
554 { // X,Dn must be .n or .l
555 if (siz & (SIZB | SIZW))
556 return error(siz_error);
558 else if (siz & (SIZW | SIZL)) // X,ea must be .n or .b
559 return error(siz_error);
561 // Construct instr and EAs
567 ea0gen(SIZB); // Immediate bit number
571 inst |= reg_9[a0reg];
582 int m_dbra(WORD inst, WORD siz)
588 if (a1exattr & DEFINED)
590 if ((a1exattr & TDB) != cursect)
591 return error(rel_error);
593 uint32_t v = a1exval - sloc;
595 if (v + 0x8000 > 0x10000)
596 return error(range_error);
602 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
613 int m_exg(WORD inst, WORD siz)
619 if (am0 == DREG && am1 == DREG)
621 else if (am0 == AREG && am1 == AREG)
627 m = a1reg; // Get AREG into a1reg
635 inst |= m | reg_9[a0reg] | a1reg;
645 int m_link(WORD inst, WORD siz)
649 // Is this an error condition???
654 inst &= ~((3 << 9) | (1 << 6) | (1 << 4));
666 WORD extra_addressing[16]=
668 0, // 0100 (bd,An,Xn)
669 0, // 0101 ([bd,An],Xn,od)
670 0x180, // 0102 ([bc,An,Xn],od) (111 110 110 111)
671 0, // 0103 (bd,PC,Xn)
672 0, // 0104 ([bd,PC],Xn,od)
673 0, // 0105 ([bc,PC,Xn],od)
688 // Handle MOVE <C_ALL> <C_ALTDATA>
689 // MOVE <C_ALL> <M_AREG>
691 // Optimize MOVE.L #<smalldata>,D0 to a MOVEQ
693 int m_move(WORD inst, WORD size)
695 // Cast the passed in value to an int
698 // Try to optimize to MOVEQ
699 // N.B.: We can get away with casting the uint64_t to a 32-bit value
700 // because it checks for a SIZL (i.e., a 32-bit value).
701 if (CHECK_OPTS(OPT_MOVEL_MOVEQ)
702 && (siz == SIZL) && (am0 == IMMED) && (am1 == DREG)
703 && ((a0exattr & (TDB | DEFINED)) == DEFINED)
704 && ((uint32_t)a0exval + 0x80 < 0x100))
706 m_moveq((WORD)0x7000, (WORD)0);
709 warn("move.l #size,dx converted to moveq");
713 if ((am0 < ABASE) && (am1 < ABASE)) // 68000 modes
715 inst |= siz_12[siz] | am_6[am1] | reg_9[a1reg] | am0 | a0reg;
723 ea1gen((WORD)siz | 0x8000); // Tell ea1gen we're move ea,ea
727 inst |= siz_12[siz] | reg_9[a1reg] | extra_addressing[am0 - ABASE];
743 // Handle MOVE <C_ALL030> <C_ALTDATA>
744 // MOVE <C_ALL030> <M_AREG>
746 int m_move30(WORD inst, WORD size)
749 // TODO: is extra_addressing necessary/correct?
750 //inst |= siz_12[siz] | reg_9[a1reg & 7] | a0reg | extra_addressing[am0 - ABASE];
751 inst |= siz_12[siz] | reg_9[a1reg & 7] | a0reg;
766 // move USP,An -- move An,USP
768 int m_usp(WORD inst, WORD siz)
773 inst |= a1reg; // USP, An
775 inst |= a0reg; // An, USP
786 int m_moveq(WORD inst, WORD siz)
790 // Arrange for future fixup
791 if (!(a0exattr & DEFINED))
793 AddFixup(FU_BYTE | FU_SEXT, sloc + 1, a0expr);
796 else if ((uint32_t)a0exval + 0x100 >= 0x200)
797 return error(range_error);
799 inst |= reg_9[a1reg] | (a0exval & 0xFF);
807 // movep Dn, disp(An) -- movep disp(An), Dn
809 int m_movep(WORD inst, WORD siz)
811 // Tell ea0gen to lay off the 0(a0) optimisations on this one
819 inst |= reg_9[a0reg] | a1reg;
829 inst |= reg_9[a1reg] | a0reg;
846 int m_br(WORD inst, WORD siz)
848 if (a0exattr & DEFINED)
850 if ((a0exattr & TDB) != cursect)
852 //printf("m_br(): a0exattr = %X, cursect = %X, a0exval = %X, sloc = %X\n", a0exattr, cursect, a0exval, sloc);
853 return error(rel_error);
856 uint32_t v = (uint32_t)a0exval - (sloc + 2);
858 // Optimize branch instr. size
861 if (CHECK_OPTS(OPT_BSR_BCC_S) && (v != 0) && ((v + 0x80) < 0x100))
868 warn("Bcc.w/BSR.w converted to .s");
875 if ((v + 0x8000) > 0x10000)
876 return error(range_error);
884 if (siz == SIZB || siz == SIZS)
886 if ((v + 0x80) >= 0x100)
887 return error(range_error);
894 if ((v + 0x8000) >= 0x10000)
895 return error(range_error);
903 else if (siz == SIZN)
906 if (siz == SIZB || siz == SIZS)
909 AddFixup(FU_BBRA | FU_PCREL | FU_SEXT, sloc, a0expr);
917 AddFixup(FU_WORD | FU_PCREL | FU_LBRA | FU_ISBRA, sloc, a0expr);
928 int m_addq(WORD inst, WORD siz)
930 inst |= siz_6[siz] | am1 | a1reg;
932 if (a0exattr & DEFINED)
934 if ((a0exval > 8) || (a0exval == 0)) // Range in 1..8
935 return error(range_error);
937 inst |= (a0exval & 7) << 9;
942 AddFixup(FU_QUICK, sloc, a0expr);
955 int m_trap(WORD inst, WORD siz)
959 if (a0exattr & DEFINED)
962 return error(abs_error);
965 return error(range_error);
971 return error(undef_error);
978 // movem <rlist>,ea -- movem ea,<rlist>
980 int m_movem(WORD inst, WORD siz)
988 return error("bad size suffix");
995 // Handle #<expr>, ea
998 if (abs_expr(&eval) != OK)
1001 if (eval >= 0x10000L)
1002 return error(range_error);
1008 if ((*tok >= KW_D0) && (*tok <= KW_A7))
1011 if (reglist(&rmask) < 0)
1016 return error("missing comma");
1021 inst |= am0 | a0reg;
1023 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
1024 return error("invalid addressing mode");
1026 // If APREDEC, reverse register mask
1032 for(i=0x8000; i; i>>=1, w>>=1)
1033 rmask = (WORD)((rmask << 1) | w & 1);
1042 inst |= 0x0400 | am0 | a0reg;
1045 return error("missing comma");
1048 return error("missing register list");
1055 if (abs_expr(&eval) != OK)
1058 if (eval >= 0x10000)
1059 return error(range_error);
1063 else if (reglist(&rmask) < 0)
1066 if (!(amsktab[am0] & (C_CTRL | M_APOSTINC)))
1067 return error("invalid addressing mode");
1079 // CLR.x An ==> SUBA.x An,An
1081 int m_clra(WORD inst, WORD siz)
1083 inst |= a0reg | reg_9[a0reg] | lwsiz_8[siz];
1091 // CLR.L Dn ==> CLR.L An or MOVEQ #0,Dx
1093 int m_clrd(WORD inst, WORD siz)
1095 if (!CHECK_OPTS(OPT_CLR_DX))
1104 inst = (a0reg << 9) | B16(01110000, 00000000);
1111 ////////////////////////////////////////
1113 // 68020/30/40 instructions
1115 ////////////////////////////////////////
1120 int m_br30(WORD inst, WORD siz)
1122 if (a0exattr & DEFINED)
1124 if ((a0exattr & TDB) != cursect)
1125 return error(rel_error);
1127 uint32_t v = (uint32_t)a0exval - (sloc + 2);
1136 AddFixup(FU_LONG | FU_PCREL | FU_SEXT, sloc, a0expr);
1144 // bfchg, bfclr, bfexts, bfextu, bfffo, bfins, bfset
1145 // (68020, 68030, 68040)
1147 int m_bfop(WORD inst, WORD siz)
1149 if ((bfval1 > 31) || (bfval1 < 0))
1150 return error("bfxxx offset: immediate value must be between 0 and 31");
1152 // First instruction word - just the opcode and first EA
1153 // Note: both am1 is ORed because solely of bfins - maybe it's a good idea
1154 // to make a dedicated function for it?
1161 if (bfval2 > 31 || bfval2 < 0)
1162 return error("bfxxx width: immediate value must be between 0 and 31");
1164 // For Dw both immediate and register number are stuffed
1165 // into the same field O_o
1166 bfparam2 = (bfval2 << 0);
1170 bfparam1 = (bfval1 << 6);
1172 bfparam1 = bfval1 << 12;
1174 D_word((inst | am0 | a0reg | am1 | a1reg));
1175 ea0gen(siz); // Generate EA
1177 // Second instruction word - Dest register (if exists), Do, Offset, Dw, Width
1178 inst = bfparam1 | bfparam2;
1184 inst |= a0reg << 12;
1193 // bkpt (68EC000, 68010, 68020, 68030, 68040, CPU32)
1195 int m_bkpt(WORD inst, WORD siz)
1199 if (a0exattr & DEFINED)
1202 return error(abs_error);
1205 return error(range_error);
1211 return error(undef_error);
1220 int m_callm(WORD inst, WORD siz)
1227 if (a0exattr & DEFINED)
1230 return error(abs_error);
1233 return error(range_error);
1235 inst = (uint16_t)a0exval;
1239 return error(undef_error);
1249 // cas (68020, 68030, 68040)
1251 int m_cas(WORD inst, WORD siz)
1257 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1258 return error(unsupport);
1273 return error("bad size suffix");
1278 if ((*tok < KW_D0) && (*tok > KW_D7))
1279 return error("CAS accepts only data registers");
1281 inst2 = (*tok++) & 7;
1284 return error("missing comma");
1287 if ((*tok < KW_D0) && (*tok > KW_D7))
1288 return error("CAS accepts only data registers");
1290 inst2 |= ((*tok++) & 7) << 6;
1293 return error("missing comma");
1296 if ((modes = amode(1)) < 0)
1300 return error("too many ea fields");
1303 return error("extra (unexpected) text found");
1305 // Reject invalud ea modes
1306 amsk = amsktab[am0];
1308 if ((amsk & (M_AIND | M_APOSTINC | M_APREDEC | M_ADISP | M_AINDEXED | M_ABSW | M_ABSL | M_ABASE | M_MEMPOST | M_MEMPRE)) == 0)
1309 return error("unsupported addressing mode");
1311 inst |= am0 | a0reg;
1321 // cas2 (68020, 68030, 68040)
1323 int m_cas2(WORD inst, WORD siz)
1327 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1328 return error(unsupport);
1343 return error("bad size suffix");
1348 if ((*tok < KW_D0) && (*tok > KW_D7))
1349 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1351 inst2 = (*tok++) & 7;
1354 return error("missing colon");
1357 if ((*tok < KW_D0) && (*tok > KW_D7))
1358 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1360 inst3 = (*tok++) & 7;
1363 return error("missing comma");
1366 if ((*tok < KW_D0) && (*tok > KW_D7))
1367 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1369 inst2 |= ((*tok++) & 7) << 6;
1372 return error("missing colon");
1375 if ((*tok < KW_D0) && (*tok > KW_D7))
1376 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1378 inst3 |= ((*tok++) & 7) << 6;
1381 return error("missing comma");
1385 return error("missing (");
1386 if ((*tok >= KW_D0) && (*tok <= KW_D7))
1387 inst2 |= (((*tok++) & 7) << 12) | (0 << 15);
1388 else if ((*tok >= KW_A0) && (*tok <= KW_A7))
1389 inst2 |= (((*tok++) & 7) << 12) | (1 << 15);
1391 return error("CAS accepts either data or address registers for Rn1:Rn2 pair");
1394 return error("missing (");
1397 return error("missing colon");
1401 return error("missing (");
1402 if ((*tok >= KW_D0) && (*tok <= KW_D7))
1403 inst3 |= (((*tok++) & 7) << 12) | (0 << 15);
1404 else if ((*tok >= KW_A0) && (*tok <= KW_A7))
1405 inst3 |= (((*tok++) & 7) << 12) | (1 << 15);
1407 return error("CAS accepts either data or address registers for Rn1:Rn2 pair");
1410 return error("missing (");
1413 return error("extra (unexpected) text found");
1424 // cmp2 (68020, 68030, 68040, CPU32)
1426 int m_cmp2(WORD inst, WORD siz)
1428 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1429 return error(unsupport);
1431 switch (siz & 0x000F)
1445 WORD flg = inst; // Save flag bits
1446 inst &= ~0x3F; // Clobber flag bits in instr
1448 // Install "standard" instr size bits
1454 // OR-in register number
1456 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1458 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1464 inst |= am1 | a1reg; // Get ea1 into instr
1465 D_word(inst); // Deposit instr
1467 // Generate ea0 if requested
1471 ea1gen(siz); // Generate ea1
1476 inst |= am0 | a0reg; // Get ea0 into instr
1477 D_word(inst); // Deposit instr
1478 ea0gen(siz); // Generate ea0
1480 // Generate ea1 if requested
1485 // If we're called from chk2 then bit 11 of size will be set. This is just
1486 // a dumb mechanism to pass this, required by the extension word. (You might
1487 // have noticed the siz & 15 thing above!)
1488 inst = (a1reg << 12) | (siz & (1 << 11));
1500 // chk2 (68020, 68030, 68040, CPU32)
1502 int m_chk2(WORD inst, WORD siz)
1504 return m_cmp2(inst, siz | (1 << 11));
1509 // cpbcc(68020, 68030)
1511 int m_cpbr(WORD inst, WORD siz)
1513 if ((activecpu & (CPU_68020 | CPU_68030)) == 0)
1514 return error(unsupport);
1516 if (a0exattr & DEFINED)
1518 if ((a0exattr & TDB) != cursect)
1519 return error(rel_error);
1521 uint32_t v = (uint32_t)a0exval - (sloc + 2);
1523 // Optimize branch instr. size
1526 if ((v != 0) && ((v + 0x8000) < 0x10000))
1536 if ((v + 0x8000) >= 0x10000)
1537 return error(range_error);
1545 else if (siz == SIZN)
1552 AddFixup(FU_LONG | FU_PCREL | FU_SEXT, sloc, a0expr);
1560 AddFixup(FU_WORD | FU_PCREL | FU_SEXT, sloc, a0expr);
1569 // cpdbcc(68020, 68030)
1571 int m_cpdbr(WORD inst, WORD siz)
1576 WORD condition = inst & 0x1F; // Grab condition sneakily placed in the lower 5 bits of inst
1577 inst &= 0xFFE0; // And then mask them out - you ain't seen me, roit?
1579 inst |= (1 << 9); // Bolt on FPU id
1586 if (a1exattr & DEFINED)
1588 if ((a1exattr & TDB) != cursect)
1589 return error(rel_error);
1591 v = (uint32_t)a1exval - sloc;
1593 if (v + 0x8000 > 0x10000)
1594 return error(range_error);
1600 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
1611 int m_divs(WORD inst, WORD siz)
1613 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1614 return error(unsupport);
1616 WORD flg = inst; // Save flag bits
1617 inst &= ~0x3F; // Clobber flag bits in instr
1619 // Install "standard" instr size bits
1625 // OR-in register number
1627 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1629 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1635 inst |= am1 | a1reg; // Get ea1 into instr
1636 D_word(inst); // Deposit instr
1638 // Generate ea0 if requested
1642 ea1gen(siz); // Generate ea1
1647 inst |= am0 | a0reg; // Get ea0 into instr
1648 D_word(inst); // Deposit instr
1649 ea0gen(siz); // Generate ea0
1651 // Generate ea1 if requested
1656 inst = a1reg + (a2reg << 12) + (1 << 11);
1666 int m_muls(WORD inst, WORD siz)
1668 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1669 return error(unsupport);
1671 WORD flg = inst; // Save flag bits
1672 inst &= ~0x3F; // Clobber flag bits in instr
1674 // Install "standard" instr size bits
1680 // OR-in register number
1682 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1684 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1690 inst |= am1 | a1reg; // Get ea1 into instr
1691 D_word(inst); // Deposit instr
1694 inst = a1reg + (a2reg << 12) + (1 << 11);
1695 inst |= mulmode; // add size bit
1698 // Generate ea0 if requested
1702 ea1gen(siz); // Generate ea1
1707 inst |= am0 | a0reg; // Get ea0 into instr
1708 D_word(inst); // Deposit instr
1710 inst = a1reg + (a2reg << 12) + (1 << 11);
1711 inst |= mulmode; // add size bit
1714 ea0gen(siz); // Generate ea0
1716 // Generate ea1 if requested
1731 int m_divu(WORD inst, WORD siz)
1733 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1734 return error(unsupport);
1736 //WARNING("divu.l d0,d1 is actually divul.l d0,d1:d1!!!")
1738 WORD flg = inst; // Save flag bits
1739 inst &= ~0x3F; // Clobber flag bits in instr
1741 // Install "standard" instr size bits
1747 // OR-in register number
1749 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1751 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1757 inst |= am1 | a1reg; // Get ea1 into instr
1758 D_word(inst); // Deposit instr
1760 // Generate ea0 if requested
1764 ea1gen(siz); // Generate ea1
1769 inst |= am0 | a0reg; // Get ea0 into instr
1770 D_word(inst); // Deposit instr
1771 ea0gen(siz); // Generate ea0
1773 // Generate ea1 if requested
1778 inst = a1reg + (a2reg << 12);
1788 int m_mulu(WORD inst, WORD siz)
1790 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1791 return error(unsupport);
1793 WORD flg = inst; // Save flag bits
1794 inst &= ~0x3F; // Clobber flag bits in instr
1796 // Install "standard" instr size bits
1802 // OR-in register number
1804 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1806 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1812 inst |= am1 | a1reg; // Get ea1 into instr
1813 D_word(inst); // Deposit instr
1815 // Generate ea0 if requested
1819 ea1gen(siz); // Generate ea1
1824 inst |= am0 | a0reg; // Get ea0 into instr
1825 D_word(inst); // Deposit instr
1826 ea0gen(siz); // Generate ea0
1828 // Generate ea1 if requested
1833 inst = a1reg + (a2reg << 12);
1834 inst |= mulmode; // add size bit
1844 int m_divsl(WORD inst, WORD siz)
1846 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1847 return error(unsupport);
1849 WORD flg = inst; // Save flag bits
1850 inst &= ~0x3F; // Clobber flag bits in instr
1852 // Install "standard" instr size bits
1858 // OR-in register number
1860 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1862 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1868 inst |= am1 | a1reg; // Get ea1 into instr
1869 D_word(inst); // Deposit instr
1871 // Generate ea0 if requested
1875 ea1gen(siz); // Generate ea1
1880 inst |= am0 | a0reg; // Get ea0 into instr
1881 D_word(inst); // Deposit instr
1882 ea0gen(siz); // Generate ea0
1884 // Generate ea1 if requested
1889 inst = a1reg + (a2reg << 12) + (1 << 11) + (1 << 10);
1898 int m_divul(WORD inst, WORD siz)
1900 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1901 return error(unsupport);
1903 WORD flg = inst; // Save flag bits
1904 inst &= ~0x3F; // Clobber flag bits in instr
1906 // Install "standard" instr size bits
1912 // OR-in register number
1914 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1916 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1922 inst |= am1 | a1reg; // Get ea1 into instr
1923 D_word(inst); // Deposit instr
1925 // Generate ea0 if requested
1929 ea1gen(siz); // Generate ea1
1934 inst |= am0 | a0reg; // Get ea0 into instr
1935 D_word(inst); // Deposit instr
1936 ea0gen(siz); // Generate ea0
1938 // Generate ea1 if requested
1943 inst = a1reg + (a2reg << 12) + (1 << 10);
1951 // move16 (ax)+,(ay)+
1953 int m_move16a(WORD inst, WORD siz)
1955 if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1956 return error(unsupport);
1960 inst = (1 << 15) + (a1reg << 12);
1968 // move16 with absolute address
1970 int m_move16b(WORD inst, WORD siz)
1972 if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1973 return error(unsupport);
1979 if (am0 == APOSTINC)
1982 return error("Wasn't this suppose to call m_move16a???");
1985 //move16 (ax)+,(xxx).L
1990 else if (am0 == ABSL)
1994 //move16 (xxx).L,(ax)+
2000 //move16 (xxx).L,(ax)
2005 else if (am0 == AIND)
2007 //move16 (ax),(xxx).L
2020 // pack/unpack (68020/68030/68040)
2022 int m_pack(WORD inst, WORD siz)
2027 return error("bad size suffix");
2029 if (*tok >= KW_D0 && *tok <= KW_D7)
2031 // Dx,Dy,#<adjustment>
2032 inst |= (0 << 3); // R/M
2033 inst |= (*tok++ & 7);
2035 if (*tok != ',' && tok[2] != ',')
2036 return error("missing comma");
2038 if (tok[1] < KW_D0 && tok[1] > KW_D7)
2039 return error(syntax_error);
2041 inst |= ((tok[1] & 7)<<9);
2044 // Fall through for adjustment (common in both valid cases)
2046 else if (*tok == '-')
2048 // -(Ax),-(Ay),#<adjustment>
2049 inst |= (1 << 3); // R/M
2050 tok++; // eat the minus
2052 if ((*tok != '(') && (tok[2]!=')') && (tok[3]!=',') && (tok[4] != '-') && (tok[5] != '(') && (tok[7] != ')') && (tok[8] != ','))
2053 return error(syntax_error);
2055 if (tok[1] < KW_A0 && tok[1] > KW_A7)
2056 return error(syntax_error);
2058 if (tok[5] < KW_A0 && tok[6] > KW_A7)
2059 return error(syntax_error);
2061 inst |= ((tok[1] & 7) << 0);
2062 inst |= ((tok[6] & 7) << 9);
2065 // Fall through for adjustment (common in both valid cases)
2068 return error("invalid syntax");
2070 if ((*tok != CONST) && (*tok != SYMBOL) && (*tok != '-'))
2071 return error(syntax_error);
2073 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2076 if ((a0exattr & DEFINED) == 0)
2077 return error(undef_error);
2079 if (a0exval + 0x8000 > 0x10000)
2083 return error(extra_stuff);
2085 D_word((a0exval & 0xFFFF));
2094 int m_rtm(WORD inst, WORD siz)
2102 else if (am0 == AREG)
2104 inst |= (1 << 3) + a0reg;
2107 return error("rtm only allows data or address registers.");
2118 int m_rtd(WORD inst, WORD siz)
2122 if (a0exattr & DEFINED)
2125 return error(abs_error);
2127 if ((a0exval + 0x8000) <= 0x7FFF)
2128 return error(range_error);
2134 return error(undef_error);
2143 int m_trapcc(WORD inst, WORD siz)
2151 else if (am0 == IMMED)
2155 if (a0exval < 0x10000)
2162 return error("Immediate value too big");
2172 return error("Invalid parameter for trapcc");
2179 // cinvl/p/a (68040)
2181 int m_cinv(WORD inst, WORD siz)
2186 inst |= (0 << 6) | (a1reg);
2190 inst |= (2 << 6) | (a1reg);
2193 inst |= (1 << 6) | (a1reg);
2196 inst |= (3 << 6) | (a1reg);
2206 // cpRESTORE (68020, 68030)
2208 int m_cprest(WORD inst, WORD siz)
2210 if (activecpu & !(CPU_68020 | CPU_68030))
2211 return error(unsupport);
2213 inst |= am0 | a0reg;
2222 // movec (68010, 68020, 68030, 68040, CPU32)
2224 int m_movec(WORD inst, WORD siz)
2228 if (am0 == DREG || am0 == AREG)
2236 inst = (0 << 15) + (a0reg << 12) + CREGlut[a1reg];
2241 inst = (1 << 15) + (a0reg << 12) + CREGlut[a1reg];
2252 inst = (0 << 15) + (a1reg << 12) + CREGlut[a0reg];
2257 inst = (1 << 15) + (a1reg << 12) + CREGlut[a0reg];
2267 // moves (68010, 68020, 68030, 68040, CPU32)
2269 int m_moves(WORD inst, WORD siz)
2271 if (activecpu & !(CPU_68020 | CPU_68030 | CPU_68040))
2272 return error(unsupport);
2276 else if (siz == SIZL)
2283 inst |= am1 | a1reg;
2285 inst = (a0reg << 12) | (1 << 11) | (0 << 15);
2288 else if (am0 == AREG)
2290 inst |= am1 | a1reg;
2292 inst = (a0reg << 12) | (1 << 11) | (1 << 15);
2299 inst |= am0 | a0reg;
2301 inst = (a1reg << 12) | (0 << 11) | (0 << 15);
2306 inst |= am0 | a0reg;
2308 inst = (a1reg << 12) | (0 << 11) | (1 << 15);
2320 int m_pbcc(WORD inst, WORD siz)
2323 return error("Not implemented yet.");
2328 // pflusha (68030, 68040)
2330 int m_pflusha(WORD inst, WORD siz)
2332 if (activecpu == CPU_68030)
2335 inst = (1 << 13) | (1 << 10) | (0 << 5) | 0;
2339 else if (activecpu == CPU_68040)
2341 inst = B16(11110101, 00011000);
2346 return error(unsupport);
2353 // pflush (68030, 68040, 68060)
2355 int m_pflush(WORD inst, WORD siz)
2357 if (activecpu == CPU_68030)
2360 // PFLUSH FC, MASK, < ea >
2368 if (*tok != CONST && *tok != SYMBOL)
2369 return error("function code should be an expression");
2371 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2374 if ((a0exattr & DEFINED) == 0)
2375 return error("function code immediate should be defined");
2377 if (a0exval > 7 && a0exval < 0)
2378 return error("function code out of range (0-7)");
2380 fc = (uint16_t)a0exval;
2390 fc = (1 << 4) | (*tok++ & 7);
2401 return error(syntax_error);
2405 return error("comma exptected");
2408 return error("mask should be an immediate value");
2410 if (*tok != CONST && *tok != SYMBOL)
2411 return error("mask is supposed to be immediate");
2413 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2416 if ((a0exattr & DEFINED) == 0)
2417 return error("mask immediate value should be defined");
2419 if (a0exval > 7 && a0exval < 0)
2420 return error("function code out of range (0-7)");
2422 mask = (uint16_t)a0exval << 5;
2428 inst = (1 << 13) | fc | mask | (4 << 10);
2432 else if (*tok == ',')
2434 // PFLUSH FC, MASK, < ea >
2437 if (amode(0) == ERROR)
2441 return error(extra_stuff);
2443 if (am0 == AIND || am0 == ABSW || am0 == ABSL || am0 == ADISP || am0 == ADISP || am0 == AINDEXED || am0 == ABASE || am0 == MEMPOST || am0 == MEMPRE)
2445 inst |= am0 | a0reg;
2447 inst = (1 << 13) | fc | mask | (6 << 10);
2453 return error("unsupported addressing mode");
2457 return error(syntax_error);
2461 else if (activecpu == CPU_68040 || activecpu == CPU_68060)
2465 if (*tok != '(' && tok[2] != ')')
2466 return error(syntax_error);
2468 if (tok[1] < KW_A0 && tok[1] > KW_A7)
2469 return error("expected (An)");
2471 if ((inst & 7) == 7)
2472 // With pflushn/pflush there's no easy way to distinguish between
2473 // the two in 68040 mode. Ideally the opcode bitfields would have
2474 // been hardcoded in 68ktab but there is aliasing between 68030
2475 // and 68040 opcode. So we just set the 3 lower bits to 1 in
2476 // pflushn inside 68ktab and detect it here.
2477 inst = (inst & 0xff8) | 8;
2479 inst |= (tok[1] & 7) | (5 << 8);
2482 return error(extra_stuff);
2487 return error(unsupport);
2495 int m_pflushr(WORD inst, WORD siz)
2499 WORD flg = inst; // Save flag bits
2500 inst &= ~0x3F; // Clobber flag bits in instr
2502 // Install "standard" instr size bits
2508 // OR-in register number
2510 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
2512 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
2518 inst |= am1 | a1reg; // Get ea1 into instr
2519 D_word(inst); // Deposit instr
2521 // Generate ea0 if requested
2525 ea1gen(siz); // Generate ea1
2530 inst |= am0 | a0reg; // Get ea0 into instr
2531 D_word(inst); // Deposit instr
2532 ea0gen(siz); // Generate ea0
2534 // Generate ea1 if requested
2539 D_word(B16(10100000, 00000000));
2545 // ploadr, ploadw (68030)
2547 int m_pload(WORD inst, WORD siz, WORD extension)
2549 // TODO: 68851 support is not added yet.
2550 // None of the ST series of computers had a 68020 + 68551 socket and since
2551 // this is an Atari targetted assembler...
2561 if (a0reg == KW_SFC - KW_SFC)
2563 else if (a0reg == KW_DFC - KW_SFC)
2566 return error("illegal control register specified");
2570 inst = (1 << 3) | a0reg;
2573 if ((a0exattr & DEFINED) == 0)
2574 return error("constant value must be defined");
2576 inst = (2 << 3) | (uint16_t)a0exval;
2580 inst |= extension | (1 << 13);
2588 int m_ploadr(WORD inst, WORD siz)
2590 return m_pload(inst, siz, 1 << 9);
2593 int m_ploadw(WORD inst, WORD siz)
2595 return m_pload(inst, siz, 0 << 9);
2599 // pmove (68030/68851)
2601 int m_pmove(WORD inst, WORD siz)
2605 // TODO: 68851 support is not added yet.
2606 // None of the ST series of computers had
2607 // a 68020 + 68851 socket and since this is
2608 // an Atari targetted assembler....
2609 // (same for 68EC030)
2612 inst2 = inst & (1 << 8); //Copy the flush bit over to inst2 in case we're called from m_pmovefd
2613 inst &= ~(1 << 8); //And mask it out
2620 else if (am1 == CREG)
2626 return error("pmove sez: Wut?");
2628 // The instruction is a quad-word (8 byte) operation
2629 // for the CPU root pointer and the supervisor root pointer.
2630 // It is a long - word operation for the translation control register
2631 // and the transparent translation registers(TT0 and TT1).
2632 // It is a word operation for the MMU status register.
2634 if (((reg == (KW_URP - KW_SFC)) || (reg == (KW_SRP - KW_SFC)))
2635 && ((siz != SIZD) && (siz != SIZN)))
2636 return error(siz_error);
2638 if (((reg == (KW_TC - KW_SFC)) || (reg == (KW_TT0 - KW_SFC)) || (reg == (KW_TT1 - KW_SFC)))
2639 && ((siz != SIZL) && (siz != SIZN)))
2640 return error(siz_error);
2642 if ((reg == (KW_MMUSR - KW_SFC)) && ((siz != SIZW) && (siz != SIZN)))
2643 return error(siz_error);
2648 inst |= am1 | a1reg;
2651 else if (am1 == CREG)
2653 inst |= am0 | a0reg;
2657 switch (reg + KW_SFC)
2660 inst2 |= (0 << 10) + (1 << 14); break;
2662 inst2 |= (2 << 10) + (1 << 14); break;
2664 inst2 |= (3 << 10) + (1 << 14); break;
2666 inst2 |= (2 << 10) + (0 << 13); break;
2668 inst2 |= (3 << 10) + (0 << 13); break;
2671 inst2 |= (1 << 9) + (3 << 13);
2673 inst2 |= (0 << 9) + (3 << 13);
2676 return error("unsupported register");
2684 else if (am1 == CREG)
2694 int m_pmovefd(WORD inst, WORD siz)
2698 return m_pmove(inst | (1 << 8), siz);
2704 int m_ptrapcc(WORD inst, WORD siz)
2707 // We stash the 5 condition bits
2708 // inside the opcode in 68ktab
2709 // (bits 0-4), so we need to extract
2710 // them first and fill in
2711 // the clobbered bits.
2712 WORD opcode = inst & 0x1F;
2713 inst = (inst & 0xFFE0) | (0x18);
2722 else if (siz == SIZL)
2729 else if (siz == SIZN)
2740 // ptestr, ptestw (68030)
2742 int m_ptest(WORD inst, WORD siz)
2746 if (activecpu == CPU_68030)
2747 return error("Not implemented yet.");
2748 else if (activecpu == CPU_68040)
2749 return error("Not implemented yet.");
2755 #define FPU_NOWARN 0
2756 #define FPU_P_EMUL 1
2757 #define FPU_P2_EMU 2
2762 // Generate a FPU opcode
2764 static inline int gen_fpu(WORD inst, WORD siz, WORD opmode, WORD emul)
2766 if (am0 < AM_NONE) // Check first operand for ea or fp - is this right?
2768 inst |= (1 << 9); // Bolt on FPU id
2775 inst = 1 << 14; // R/M field (we have ea so have to set this to 1)
2779 case SIZB: inst |= (6 << 10); break;
2780 case SIZW: inst |= (4 << 10); break;
2781 case SIZL: inst |= (0 << 10); break;
2783 case SIZS: inst |= (1 << 10); break;
2784 case SIZD: inst |= (5 << 10); break;
2785 case SIZX: inst |= (2 << 10); break;
2790 warn("This encoding will cause an unimplemented data type exception in the MC68040 to allow emulation in software.");
2794 return error("Something bad happened, possibly, in gen_fpu.");
2798 inst |= (a1reg << 7);
2805 inst |= (1 << 9); // Bolt on FPU id
2809 inst |= (a1reg << 7);
2814 if ((emul & FPU_FPSP) && (activefpu == FPU_68040))
2815 warn("Instruction is emulated in 68040");
2822 // fabs, fsabs, fdabs (6888X, 68040)
2824 int m_fabs(WORD inst, WORD siz)
2826 return gen_fpu(inst, siz, B8(00011000), FPU_P_EMUL);
2830 int m_fsabs(WORD inst, WORD siz)
2832 if (activefpu == FPU_68040)
2833 return gen_fpu(inst, siz, B8(01011000), FPU_P_EMUL);
2835 return error("Unsupported in current FPU");
2839 int m_fdabs(WORD inst, WORD siz)
2841 if (activefpu == FPU_68040)
2842 return gen_fpu(inst, siz, B8(01011100), FPU_P_EMUL);
2844 return error("Unsupported in current FPU");
2849 // facos (6888X, 68040FPSP)
2851 int m_facos(WORD inst, WORD siz)
2853 return gen_fpu(inst, siz, B8(00011100), FPU_FPSP);
2858 // fadd (6888X, 68040FPSP)
2860 int m_fadd(WORD inst, WORD siz)
2862 return gen_fpu(inst, siz, B8(00100010), FPU_P_EMUL);
2866 int m_fsadd(WORD inst, WORD siz)
2868 if (activefpu == FPU_68040)
2869 return gen_fpu(inst, siz, B8(01100010), FPU_P_EMUL);
2871 return error("Unsupported in current FPU");
2875 int m_fdadd(WORD inst, WORD siz)
2877 if (activefpu == FPU_68040)
2878 return gen_fpu(inst, siz, B8(01100110), FPU_P_EMUL);
2880 return error("Unsupported in current FPU");
2885 // fasin (6888X, 68040FPSP)f
2887 int m_fasin(WORD inst, WORD siz)
2889 return gen_fpu(inst, siz, B8(00001100), FPU_FPSP);
2894 // fatan (6888X, 68040FPSP)
2896 int m_fatan(WORD inst, WORD siz)
2898 return gen_fpu(inst, siz, B8(00001010), FPU_FPSP);
2903 // fatanh (6888X, 68040FPSP)
2905 int m_fatanh(WORD inst, WORD siz)
2907 return gen_fpu(inst, siz, B8(00001101), FPU_FPSP);
2912 // fcmp (6888X, 68040)
2914 int m_fcmp(WORD inst, WORD siz)
2916 return gen_fpu(inst, siz, B8(00111000), FPU_P_EMUL);
2921 // fcos (6888X, 68040FPSP)
2923 int m_fcos(WORD inst, WORD siz)
2925 return gen_fpu(inst, siz, B8(00011101), FPU_FPSP);
2930 // fcosh (6888X, 68040FPSP)
2932 int m_fcosh(WORD inst, WORD siz)
2934 return gen_fpu(inst, siz, B8(00011001), FPU_FPSP);
2939 // fdbcc (6888X, 68040)
2941 int m_fdbcc(WORD inst, WORD siz)
2943 WORD opcode = inst & 0x3F; // Grab conditional bitfield
2953 if (a1exattr & DEFINED)
2955 if ((a1exattr & TDB) != cursect)
2956 return error(rel_error);
2958 uint32_t v = (uint32_t)a1exval - sloc;
2960 if ((v + 0x8000) > 0x10000)
2961 return error(range_error);
2967 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
2976 // fdiv (6888X, 68040)
2978 int m_fdiv(WORD inst, WORD siz)
2980 return gen_fpu(inst, siz, B8(00100000), FPU_P_EMUL);
2984 int m_fsdiv(WORD inst, WORD siz)
2986 if (activefpu == FPU_68040)
2987 return gen_fpu(inst, siz, B8(01100000), FPU_P_EMUL);
2989 return error("Unsupported in current FPU");
2993 int m_fddiv(WORD inst, WORD siz)
2995 if (activefpu == FPU_68040)
2996 return gen_fpu(inst, siz, B8(01100100), FPU_P_EMUL);
2998 return error("Unsupported in current FPU");
3003 // fetox (6888X, 68040FPSP)
3005 int m_fetox(WORD inst, WORD siz)
3007 return gen_fpu(inst, siz, B8(00010000), FPU_FPSP);
3012 // fetoxm1 (6888X, 68040FPSP)
3014 int m_fetoxm1(WORD inst, WORD siz)
3016 return gen_fpu(inst, siz, B8(00001000), FPU_FPSP);
3021 // fgetexp (6888X, 68040FPSP)
3023 int m_fgetexp(WORD inst, WORD siz)
3025 return gen_fpu(inst, siz, B8(00011110), FPU_FPSP);
3030 // fgetman (6888X, 68040FPSP)
3032 int m_fgetman(WORD inst, WORD siz)
3034 return gen_fpu(inst, siz, B8(00011111), FPU_FPSP);
3039 // fint (6888X, 68040FPSP)
3041 int m_fint(WORD inst, WORD siz)
3044 // special case - fint fpx = fint fpx,fpx
3047 return gen_fpu(inst, siz, B8(00000001), FPU_FPSP);
3052 // fintrz (6888X, 68040FPSP)
3054 int m_fintrz(WORD inst, WORD siz)
3057 // special case - fintrz fpx = fintrz fpx,fpx
3060 return gen_fpu(inst, siz, B8(00000011), FPU_FPSP);
3065 // flog10 (6888X, 68040FPSP)
3067 int m_flog10(WORD inst, WORD siz)
3069 return gen_fpu(inst, siz, B8(00010101), FPU_FPSP);
3074 // flog2 (6888X, 68040FPSP)
3076 int m_flog2(WORD inst, WORD siz)
3078 return gen_fpu(inst, siz, B8(00010110), FPU_FPSP);
3083 // flogn (6888X, 68040FPSP)
3085 int m_flogn(WORD inst, WORD siz)
3087 return gen_fpu(inst, siz, B8(00010100), FPU_FPSP);
3092 // flognp1 (6888X, 68040FPSP)
3094 int m_flognp1(WORD inst, WORD siz)
3096 return gen_fpu(inst, siz, B8(00000110), FPU_FPSP);
3101 // fmod (6888X, 68040FPSP)
3103 int m_fmod(WORD inst, WORD siz)
3105 return gen_fpu(inst, siz, B8(00100001), FPU_FPSP);
3110 // fmove (6888X, 68040)
3112 int m_fmove(WORD inst, WORD siz)
3116 if ((am0 == FREG) && (am1 < AM_USP))
3120 inst |= am1 | a1reg;
3129 case SIZB: inst |= (6 << 10); break;
3130 case SIZW: inst |= (4 << 10); break;
3131 case SIZL: inst |= (0 << 10); break;
3133 case SIZS: inst |= (1 << 10); break;
3134 case SIZD: inst |= (5 << 10); break;
3135 case SIZX: inst |= (2 << 10); break;
3136 case SIZP: inst |= (3 << 10);
3137 // In P size we have 2 cases: {#k} where k is immediate
3138 // and {Dn} where Dn=Data register
3144 inst |= bfval1 << 4;
3149 if (bfval1 > 63 && bfval1 < -64)
3150 return error("K-factor must be between -64 and 63");
3152 inst |= bfval1 & 127;
3157 return error("Something bad happened, possibly.");
3162 // Destination specifier
3163 inst |= (a0reg << 7);
3171 else if ((am0 < AM_USP) && (am1 == FREG))
3176 inst |= am0 | a0reg;
3185 case SIZB: inst |= (6 << 10); break;
3186 case SIZW: inst |= (4 << 10); break;
3187 case SIZL: inst |= (0 << 10); break;
3189 case SIZS: inst |= (1 << 10); break;
3190 case SIZD: inst |= (5 << 10); break;
3191 case SIZX: inst |= (2 << 10); break;
3192 case SIZP: inst |= (3 << 10); break;
3194 return error("Something bad happened, possibly.");
3198 // Destination specifier
3199 inst |= (a1reg << 7);
3207 else if ((am0 == FREG) && (am1 == FREG))
3209 // register-to-register
3210 // Essentially ea to register with R/0=0
3220 return error("Invalid size");
3223 inst |= (a0reg << 10);
3225 // Destination register
3226 inst |= (a1reg << 7);
3236 // fmove (6888X, 68040)
3238 int m_fmovescr(WORD inst, WORD siz)
3240 // Move Floating-Point System Control Register (FPCR)
3244 if ((am0 == FPSCR) && (am1 < AM_USP))
3246 inst |= am1 | a1reg;
3248 inst = (1 << 13) + (1 << 15);
3254 else if ((am1 == FPSCR) && (am0 < AM_USP))
3256 inst |= am0 | a0reg;
3258 inst = (0 << 13) + (1 << 15);
3265 return error("m_fmovescr says: wut?");
3269 // fsmove/fdmove (68040)
3271 int m_fsmove(WORD inst, WORD siz)
3273 return error("Not implemented yet.");
3276 if (activefpu == FPU_68040)
3277 return gen_fpu(inst, siz, B8(01100100), FPU_P_EMUL);
3279 return error("Unsupported in current FPU");
3284 int m_fdmove(WORD inst, WORD siz)
3286 return error("Not implemented yet.");
3289 if (activefpu == FPU_68040)
3290 return gen_fpu(inst, siz, B8(01100100), FPU_P_EMUL);
3292 return error("Unsupported in current FPU");
3298 // fmovecr (6888X, 68040FPSP)
3300 int m_fmovecr(WORD inst, WORD siz)
3308 if (activefpu == FPU_68040)
3309 warn("Instruction is emulated in 68040");
3316 // fmovem (6888X, 68040)
3318 int m_fmovem(WORD inst, WORD siz)
3323 if (siz == SIZX || siz==SIZN)
3325 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
3327 //fmovem.x <rlist>,ea
3328 if (fpu_reglist_left(®mask) < 0)
3332 return error("missing comma");
3337 inst |= am0 | a0reg;
3339 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3340 return error("invalid addressing mode");
3343 inst = (1 << 15) | (1 << 14) | (1 << 13) | (0 << 11) | regmask;
3348 else if ((*tok >= KW_D0) && (*tok <= KW_D7))
3351 datareg = (*tok++ & 7) << 10;
3354 return error("missing comma");
3359 inst |= am0 | a0reg;
3361 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3362 return error("invalid addressing mode");
3365 inst = (1 << 15) | (1 << 14) | (1 << 13) | (1 << 11) | (datareg << 4);
3376 inst |= am0 | a0reg;
3379 return error("missing comma");
3381 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
3383 //fmovem.x ea,<rlist>
3384 if (fpu_reglist_right(®mask) < 0)
3388 inst = (1 << 15) | (1 << 14) | (0 << 13) | (2 << 11) | regmask;
3396 datareg = (*tok++ & 7) << 10;
3398 inst = (1 << 15) | (1 << 14) | (0 << 13) | (3 << 11) | (datareg << 4);
3405 else if (siz == SIZL)
3407 if ((*tok == KW_FPCR) || (*tok == KW_FPSR) || (*tok == KW_FPIAR))
3409 //fmovem.l <rlist>,ea
3410 regmask = (1 << 15) | (1 << 13);
3412 if (*tok == KW_FPCR)
3414 regmask |= (1 << 12);
3419 if (*tok == KW_FPSR)
3421 regmask |= (1 << 11);
3426 if (*tok == KW_FPIAR)
3428 regmask |= (1 << 10);
3433 if ((*tok == '/') || (*tok == '-'))
3440 return error("missing comma");
3445 inst |= am0 | a0reg;
3452 //fmovem.l ea,<rlist>
3456 inst |= am0 | a0reg;
3459 return error("missing comma");
3461 regmask = (1 << 15) | (0 << 13);
3464 if (*tok == KW_FPCR)
3466 regmask |= (1 << 12);
3471 if (*tok == KW_FPSR)
3473 regmask |= (1 << 11);
3478 if (*tok == KW_FPIAR)
3480 regmask |= (1 << 10);
3485 if ((*tok == '/') || (*tok == '-'))
3492 return error("extra (unexpected) text found");
3494 inst |= am0 | a0reg;
3501 return error("bad size suffix");
3508 // fmul (6888X, 68040)
3510 int m_fmul(WORD inst, WORD siz)
3512 return gen_fpu(inst, siz, B8(00100011), FPU_P_EMUL);
3516 int m_fsmul(WORD inst, WORD siz)
3518 if (activefpu == FPU_68040)
3519 return gen_fpu(inst, siz, B8(01100011), FPU_P_EMUL);
3521 return error("Unsupported in current FPU");
3525 int m_fdmul(WORD inst, WORD siz)
3527 if (activefpu == FPU_68040)
3528 return gen_fpu(inst, siz, B8(01100111), FPU_P_EMUL);
3530 return error("Unsupported in current FPU");
3535 // fneg (6888X, 68040)
3537 int m_fneg(WORD inst, WORD siz)
3539 return gen_fpu(inst, siz, B8(00011010), FPU_P_EMUL);
3543 int m_fsneg(WORD inst, WORD siz)
3545 if (activefpu == FPU_68040)
3546 return gen_fpu(inst, siz, B8(01011010), FPU_P_EMUL);
3548 return error("Unsupported in current FPU");
3552 int m_fdneg(WORD inst, WORD siz)
3554 if (activefpu == FPU_68040)
3555 return gen_fpu(inst, siz, B8(01011110), FPU_P_EMUL);
3557 return error("Unsupported in current FPU");
3562 // fnop (6888X, 68040)
3564 int m_fnop(WORD inst, WORD siz)
3566 return gen_fpu(inst, siz, B8(00000000), FPU_P_EMUL);
3571 // frem (6888X, 68040FPSP)
3573 int m_frem(WORD inst, WORD siz)
3575 return gen_fpu(inst, siz, B8(00100101), FPU_FPSP);
3580 // fscale (6888X, 68040FPSP)
3582 int m_fscale(WORD inst, WORD siz)
3584 return gen_fpu(inst, siz, B8(00100110), FPU_FPSP);
3589 // FScc (6888X, 68040), cpScc (68851, 68030), PScc (68851)
3590 // TODO: Add check for PScc to ensure 68020+68851 active
3591 // TODO: Add check for cpScc to ensure 68020+68851, 68030
3593 int m_fscc(WORD inst, WORD siz)
3595 // We stash the 5 condition bits
3596 // inside the opcode in 68ktab
3597 // (bits 4-0), so we need to extract
3598 // them first and fill in
3599 // the clobbered bits.
3600 WORD opcode = inst & 0x1F;
3602 inst |= am0 | a0reg;
3610 // FTRAPcc (6888X, 68040)
3613 int m_ftrapcc(WORD inst, WORD siz)
3615 // We stash the 5 condition bits
3616 // inside the opcode in 68ktab
3617 // (bits 3-7), so we need to extract
3618 // them first and fill in
3619 // the clobbered bits.
3620 WORD opcode = (inst >> 3) & 0x1F;
3621 inst = (inst & 0xFF07) | (0xF << 3);
3629 else if (siz == SIZL)
3636 else if (siz = SIZN)
3647 // fsgldiv (6888X, 68040)
3649 int m_fsgldiv(WORD inst, WORD siz)
3651 return gen_fpu(inst, siz, B8(00100100), FPU_P_EMUL);
3656 // fsglmul (6888X, 68040)
3658 int m_fsglmul(WORD inst, WORD siz)
3660 return gen_fpu(inst, siz, B8(00100111), FPU_P_EMUL);
3665 // fsin (6888X, 68040FPSP)
3667 int m_fsin(WORD inst, WORD siz)
3669 return gen_fpu(inst, siz, B8(00001110), FPU_FPSP);
3674 // fsincos (6888X, 68040FPSP)
3676 int m_fsincos(WORD inst, WORD siz)
3678 // Swap a1reg, a2reg as a2reg should be stored
3679 // in the bitfield gen_fpu generates
3684 if (gen_fpu(inst, siz, B8(00110000), FPU_FPSP) == OK)
3695 // fsin (6888X, 68040FPSP)
3697 int m_fsinh(WORD inst, WORD siz)
3699 return gen_fpu(inst, siz, B8(00000010), FPU_FPSP);
3704 // fsqrt (6888X, 68040)
3706 int m_fsqrt(WORD inst, WORD siz)
3708 return gen_fpu(inst, siz, B8(00000100), FPU_P_EMUL);
3712 int m_fsfsqrt(WORD inst, WORD siz)
3714 if (activefpu == FPU_68040)
3715 return gen_fpu(inst, siz, B8(01000001), FPU_P_EMUL);
3717 return error("Unsupported in current FPU");
3721 int m_fdfsqrt(WORD inst, WORD siz)
3723 if (activefpu == FPU_68040)
3724 return gen_fpu(inst, siz, B8(01000101), FPU_P_EMUL);
3726 return error("Unsupported in current FPU");
3731 // fsub (6888X, 68040)
3733 int m_fsub(WORD inst, WORD siz)
3735 return gen_fpu(inst, siz, B8(00101000), FPU_P_EMUL);
3739 int m_fsfsub(WORD inst, WORD siz)
3741 if (activefpu == FPU_68040)
3742 return gen_fpu(inst, siz, B8(01101000), FPU_P_EMUL);
3744 return error("Unsupported in current FPU");
3748 int m_fdsub(WORD inst, WORD siz)
3750 if (activefpu == FPU_68040)
3751 return gen_fpu(inst, siz, B8(01101100), FPU_P_EMUL);
3753 return error("Unsupported in current FPU");
3758 // ftan (6888X, 68040FPSP)
3760 int m_ftan(WORD inst, WORD siz)
3762 return gen_fpu(inst, siz, B8(00001111), FPU_FPSP);
3767 // ftanh (6888X, 68040FPSP)
3769 int m_ftanh(WORD inst, WORD siz)
3771 return gen_fpu(inst, siz, B8(00001001), FPU_FPSP);
3776 // ftentox (6888X, 68040FPSP)
3778 int m_ftentox(WORD inst, WORD siz)
3780 return gen_fpu(inst, siz, B8(00010010), FPU_FPSP);
3785 // ftst (6888X, 68040)
3787 int m_ftst(WORD inst, WORD siz)
3789 return gen_fpu(inst, siz, B8(00111010), FPU_P_EMUL);
3794 // ftwotox (6888X, 68040FPSP)
3796 int m_ftwotox(WORD inst, WORD siz)
3798 return gen_fpu(inst, siz, B8(00010001), FPU_FPSP);