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];
744 // Handle MOVE <C_ALL030> <C_ALTDATA>
745 // MOVE <C_ALL030> <M_AREG>
747 int m_move30(WORD inst, WORD size)
750 // TODO: is extra_addressing necessary/correct?
751 //inst |= siz_12[siz] | reg_9[a1reg & 7] | a0reg | extra_addressing[am0 - ABASE];
752 inst |= siz_12[siz] | reg_9[a1reg & 7] | a0reg;
767 // move USP,An -- move An,USP
769 int m_usp(WORD inst, WORD siz)
774 inst |= a1reg; // USP, An
776 inst |= a0reg; // An, USP
787 int m_moveq(WORD inst, WORD siz)
791 // Arrange for future fixup
792 if (!(a0exattr & DEFINED))
794 AddFixup(FU_BYTE | FU_SEXT, sloc + 1, a0expr);
797 else if ((uint32_t)a0exval + 0x100 >= 0x200)
798 return error(range_error);
800 inst |= reg_9[a1reg] | (a0exval & 0xFF);
808 // movep Dn, disp(An) -- movep disp(An), Dn
810 int m_movep(WORD inst, WORD siz)
812 // Tell ea0gen to lay off the 0(a0) optimisations on this one
820 inst |= reg_9[a0reg] | a1reg;
830 inst |= reg_9[a1reg] | a0reg;
847 int m_br(WORD inst, WORD siz)
849 if (a0exattr & DEFINED)
851 if ((a0exattr & TDB) != cursect)
853 //printf("m_br(): a0exattr = %X, cursect = %X, a0exval = %X, sloc = %X\n", a0exattr, cursect, a0exval, sloc);
854 return error(rel_error);
857 uint32_t v = (uint32_t)a0exval - (sloc + 2);
859 // Optimize branch instr. size
862 if (CHECK_OPTS(OPT_BSR_BCC_S) && (v != 0) && ((v + 0x80) < 0x100))
869 warn("Bcc.w/BSR.w converted to .s");
876 if ((v + 0x8000) > 0x10000)
877 return error(range_error);
885 if (siz == SIZB || siz == SIZS)
887 if ((v + 0x80) >= 0x100)
888 return error(range_error);
895 if ((v + 0x8000) >= 0x10000)
896 return error(range_error);
904 else if (siz == SIZN)
907 if (siz == SIZB || siz == SIZS)
910 AddFixup(FU_BBRA | FU_PCREL | FU_SEXT, sloc, a0expr);
918 AddFixup(FU_WORD | FU_PCREL | FU_LBRA | FU_ISBRA, sloc, a0expr);
929 int m_addq(WORD inst, WORD siz)
931 inst |= siz_6[siz] | am1 | a1reg;
933 if (a0exattr & DEFINED)
935 if ((a0exval > 8) || (a0exval == 0)) // Range in 1..8
936 return error(range_error);
938 inst |= (a0exval & 7) << 9;
943 AddFixup(FU_QUICK, sloc, a0expr);
956 int m_trap(WORD inst, WORD siz)
960 if (a0exattr & DEFINED)
963 return error(abs_error);
966 return error(range_error);
972 return error(undef_error);
979 // movem <rlist>,ea -- movem ea,<rlist>
981 int m_movem(WORD inst, WORD siz)
989 return error("bad size suffix");
996 // Handle #<expr>, ea
999 if (abs_expr(&eval) != OK)
1002 if (eval >= 0x10000L)
1003 return error(range_error);
1009 if ((*tok >= KW_D0) && (*tok <= KW_A7))
1012 if (reglist(&rmask) < 0)
1017 return error("missing comma");
1022 inst |= am0 | a0reg;
1024 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
1025 return error("invalid addressing mode");
1027 // If APREDEC, reverse register mask
1033 for(i=0x8000; i; i>>=1, w>>=1)
1034 rmask = (WORD)((rmask << 1) | w & 1);
1043 inst |= 0x0400 | am0 | a0reg;
1046 return error("missing comma");
1049 return error("missing register list");
1056 if (abs_expr(&eval) != OK)
1059 if (eval >= 0x10000)
1060 return error(range_error);
1064 else if (reglist(&rmask) < 0)
1067 if (!(amsktab[am0] & (C_CTRL | M_APOSTINC)))
1068 return error("invalid addressing mode");
1080 // CLR.x An ==> SUBA.x An,An
1082 int m_clra(WORD inst, WORD siz)
1084 inst |= a0reg | reg_9[a0reg] | lwsiz_8[siz];
1092 // CLR.L Dn ==> CLR.L An or MOVEQ #0,Dx
1094 int m_clrd(WORD inst, WORD siz)
1096 if (!CHECK_OPTS(OPT_CLR_DX))
1099 inst = (a0reg << 9) | B16(01110000, 00000000);
1107 ////////////////////////////////////////
1109 // 68020/30/40 instructions
1111 ////////////////////////////////////////
1116 int m_br30(WORD inst, WORD siz)
1118 if (a0exattr & DEFINED)
1120 if ((a0exattr & TDB) != cursect)
1121 return error(rel_error);
1123 uint32_t v = (uint32_t)a0exval - (sloc + 2);
1132 AddFixup(FU_LONG | FU_PCREL | FU_SEXT, sloc, a0expr);
1140 // bfchg, bfclr, bfexts, bfextu, bfffo, bfins, bfset
1141 // (68020, 68030, 68040)
1143 int m_bfop(WORD inst, WORD siz)
1145 if ((bfval1 > 31) || (bfval1 < 0))
1146 return error("bfxxx offset: immediate value must be between 0 and 31");
1148 // First instruction word - just the opcode and first EA
1149 // Note: both am1 is ORed because solely of bfins - maybe it's a good idea
1150 // to make a dedicated function for it?
1157 if (bfval2 > 31 || bfval2 < 0)
1158 return error("bfxxx width: immediate value must be between 0 and 31");
1160 // For Dw both immediate and register number are stuffed
1161 // into the same field O_o
1162 bfparam2 = (bfval2 << 0);
1166 bfparam1 = (bfval1 << 6);
1168 bfparam1 = bfval1 << 12;
1170 D_word((inst | am0 | a0reg | am1 | a1reg));
1171 ea0gen(siz); // Generate EA
1173 // Second instruction word - Dest register (if exists), Do, Offset, Dw, Width
1174 inst = bfparam1 | bfparam2;
1180 inst |= a0reg << 12;
1189 // bkpt (68EC000, 68010, 68020, 68030, 68040, CPU32)
1191 int m_bkpt(WORD inst, WORD siz)
1195 if (a0exattr & DEFINED)
1198 return error(abs_error);
1201 return error(range_error);
1207 return error(undef_error);
1216 int m_callm(WORD inst, WORD siz)
1223 if (a0exattr & DEFINED)
1226 return error(abs_error);
1229 return error(range_error);
1231 inst = (uint16_t)a0exval;
1235 return error(undef_error);
1245 // cas (68020, 68030, 68040)
1247 int m_cas(WORD inst, WORD siz)
1253 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1254 return error(unsupport);
1269 return error("bad size suffix");
1274 if ((*tok < KW_D0) && (*tok > KW_D7))
1275 return error("CAS accepts only data registers");
1277 inst2 = (*tok++) & 7;
1280 return error("missing comma");
1283 if ((*tok < KW_D0) && (*tok > KW_D7))
1284 return error("CAS accepts only data registers");
1286 inst2 |= ((*tok++) & 7) << 6;
1289 return error("missing comma");
1292 if ((modes = amode(1)) < 0)
1296 return error("too many ea fields");
1299 return error("extra (unexpected) text found");
1301 // Reject invalud ea modes
1302 amsk = amsktab[am0];
1304 if ((amsk & (M_AIND | M_APOSTINC | M_APREDEC | M_ADISP | M_AINDEXED | M_ABSW | M_ABSL | M_ABASE | M_MEMPOST | M_MEMPRE)) == 0)
1305 return error("unsupported addressing mode");
1307 inst |= am0 | a0reg;
1317 // cas2 (68020, 68030, 68040)
1319 int m_cas2(WORD inst, WORD siz)
1323 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1324 return error(unsupport);
1339 return error("bad size suffix");
1344 if ((*tok < KW_D0) && (*tok > KW_D7))
1345 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1347 inst2 = (*tok++) & 7;
1350 return error("missing colon");
1353 if ((*tok < KW_D0) && (*tok > KW_D7))
1354 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1356 inst3 = (*tok++) & 7;
1359 return error("missing comma");
1362 if ((*tok < KW_D0) && (*tok > KW_D7))
1363 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1365 inst2 |= ((*tok++) & 7) << 6;
1368 return error("missing colon");
1371 if ((*tok < KW_D0) && (*tok > KW_D7))
1372 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1374 inst3 |= ((*tok++) & 7) << 6;
1377 return error("missing comma");
1381 return error("missing (");
1382 if ((*tok >= KW_D0) && (*tok <= KW_D7))
1383 inst2 |= (((*tok++) & 7) << 12) | (0 << 15);
1384 else if ((*tok >= KW_A0) && (*tok <= KW_A7))
1385 inst2 |= (((*tok++) & 7) << 12) | (1 << 15);
1387 return error("CAS accepts either data or address registers for Rn1:Rn2 pair");
1390 return error("missing (");
1393 return error("missing colon");
1397 return error("missing (");
1398 if ((*tok >= KW_D0) && (*tok <= KW_D7))
1399 inst3 |= (((*tok++) & 7) << 12) | (0 << 15);
1400 else if ((*tok >= KW_A0) && (*tok <= KW_A7))
1401 inst3 |= (((*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("extra (unexpected) text found");
1420 // cmp2 (68020, 68030, 68040, CPU32)
1422 int m_cmp2(WORD inst, WORD siz)
1424 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1425 return error(unsupport);
1427 switch (siz & 0x000F)
1441 WORD flg = inst; // Save flag bits
1442 inst &= ~0x3F; // Clobber flag bits in instr
1444 // Install "standard" instr size bits
1450 // OR-in register number
1452 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1454 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1460 inst |= am1 | a1reg; // Get ea1 into instr
1461 D_word(inst); // Deposit instr
1463 // Generate ea0 if requested
1467 ea1gen(siz); // Generate ea1
1472 inst |= am0 | a0reg; // Get ea0 into instr
1473 D_word(inst); // Deposit instr
1474 ea0gen(siz); // Generate ea0
1476 // Generate ea1 if requested
1481 // If we're called from chk2 then bit 11 of size will be set. This is just
1482 // a dumb mechanism to pass this, required by the extension word. (You might
1483 // have noticed the siz & 15 thing above!)
1484 inst = (a1reg << 12) | (siz & (1 << 11));
1496 // chk2 (68020, 68030, 68040, CPU32)
1498 int m_chk2(WORD inst, WORD siz)
1500 return m_cmp2(inst, siz | (1 << 11));
1505 // cpbcc(68020, 68030)
1507 int m_cpbr(WORD inst, WORD siz)
1509 if ((activecpu & (CPU_68020 | CPU_68030)) == 0)
1510 return error(unsupport);
1512 if (a0exattr & DEFINED)
1514 if ((a0exattr & TDB) != cursect)
1515 return error(rel_error);
1517 uint32_t v = (uint32_t)a0exval - (sloc + 2);
1519 // Optimize branch instr. size
1522 if ((v != 0) && ((v + 0x8000) < 0x10000))
1532 if ((v + 0x8000) >= 0x10000)
1533 return error(range_error);
1541 else if (siz == SIZN)
1548 AddFixup(FU_LONG | FU_PCREL | FU_SEXT, sloc, a0expr);
1556 AddFixup(FU_WORD | FU_PCREL | FU_SEXT, sloc, a0expr);
1565 // cpdbcc(68020, 68030)
1567 int m_cpdbr(WORD inst, WORD siz)
1572 WORD condition = inst & 0x1F; // Grab condition sneakily placed in the lower 5 bits of inst
1573 inst &= 0xFFE0; // And then mask them out - you ain't seen me, roit?
1575 inst |= (1 << 9); // Bolt on FPU id
1582 if (a1exattr & DEFINED)
1584 if ((a1exattr & TDB) != cursect)
1585 return error(rel_error);
1587 v = (uint32_t)a1exval - sloc;
1589 if (v + 0x8000 > 0x10000)
1590 return error(range_error);
1596 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
1607 int m_divs(WORD inst, WORD siz)
1609 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1610 return error(unsupport);
1612 WORD flg = inst; // Save flag bits
1613 inst &= ~0x3F; // Clobber flag bits in instr
1615 // Install "standard" instr size bits
1621 // OR-in register number
1623 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1625 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1631 inst |= am1 | a1reg; // Get ea1 into instr
1632 D_word(inst); // Deposit instr
1634 // Generate ea0 if requested
1638 ea1gen(siz); // Generate ea1
1643 inst |= am0 | a0reg; // Get ea0 into instr
1644 D_word(inst); // Deposit instr
1645 ea0gen(siz); // Generate ea0
1647 // Generate ea1 if requested
1652 inst = a1reg + (a2reg << 12) + (1 << 11);
1662 int m_muls(WORD inst, WORD siz)
1664 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1665 return error(unsupport);
1667 WORD flg = inst; // Save flag bits
1668 inst &= ~0x3F; // Clobber flag bits in instr
1670 // Install "standard" instr size bits
1676 // OR-in register number
1678 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1680 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1686 inst |= am1 | a1reg; // Get ea1 into instr
1687 D_word(inst); // Deposit instr
1690 inst = a1reg + (a2reg << 12) + (1 << 11);
1691 inst |= mulmode; // add size bit
1694 // Generate ea0 if requested
1698 ea1gen(siz); // Generate ea1
1703 inst |= am0 | a0reg; // Get ea0 into instr
1704 D_word(inst); // Deposit instr
1706 inst = a1reg + (a2reg << 12) + (1 << 11);
1707 inst |= mulmode; // add size bit
1710 ea0gen(siz); // Generate ea0
1712 // Generate ea1 if requested
1727 int m_divu(WORD inst, WORD siz)
1729 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1730 return error(unsupport);
1732 //WARNING("divu.l d0,d1 is actually divul.l d0,d1:d1!!!")
1734 WORD flg = inst; // Save flag bits
1735 inst &= ~0x3F; // Clobber flag bits in instr
1737 // Install "standard" instr size bits
1743 // OR-in register number
1745 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1747 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1753 inst |= am1 | a1reg; // Get ea1 into instr
1754 D_word(inst); // Deposit instr
1756 // Generate ea0 if requested
1760 ea1gen(siz); // Generate ea1
1765 inst |= am0 | a0reg; // Get ea0 into instr
1766 D_word(inst); // Deposit instr
1767 ea0gen(siz); // Generate ea0
1769 // Generate ea1 if requested
1774 inst = a1reg + (a2reg << 12);
1784 int m_mulu(WORD inst, WORD siz)
1786 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1787 return error(unsupport);
1789 WORD flg = inst; // Save flag bits
1790 inst &= ~0x3F; // Clobber flag bits in instr
1792 // Install "standard" instr size bits
1798 // OR-in register number
1800 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1802 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1808 inst |= am1 | a1reg; // Get ea1 into instr
1809 D_word(inst); // Deposit instr
1811 // Generate ea0 if requested
1815 ea1gen(siz); // Generate ea1
1820 inst |= am0 | a0reg; // Get ea0 into instr
1821 D_word(inst); // Deposit instr
1822 ea0gen(siz); // Generate ea0
1824 // Generate ea1 if requested
1829 inst = a1reg + (a2reg << 12);
1830 inst |= mulmode; // add size bit
1840 int m_divsl(WORD inst, WORD siz)
1842 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1843 return error(unsupport);
1845 WORD flg = inst; // Save flag bits
1846 inst &= ~0x3F; // Clobber flag bits in instr
1848 // Install "standard" instr size bits
1854 // OR-in register number
1856 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1858 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1864 inst |= am1 | a1reg; // Get ea1 into instr
1865 D_word(inst); // Deposit instr
1867 // Generate ea0 if requested
1871 ea1gen(siz); // Generate ea1
1876 inst |= am0 | a0reg; // Get ea0 into instr
1877 D_word(inst); // Deposit instr
1878 ea0gen(siz); // Generate ea0
1880 // Generate ea1 if requested
1885 inst = a1reg + (a2reg << 12) + (1 << 11) + (1 << 10);
1895 int m_divul(WORD inst, WORD siz)
1897 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1898 return error(unsupport);
1900 WORD flg = inst; // Save flag bits
1901 inst &= ~0x3F; // Clobber flag bits in instr
1903 // Install "standard" instr size bits
1909 // OR-in register number
1911 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1913 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1919 inst |= am1 | a1reg; // Get ea1 into instr
1920 D_word(inst); // Deposit instr
1922 // Generate ea0 if requested
1926 ea1gen(siz); // Generate ea1
1931 inst |= am0 | a0reg; // Get ea0 into instr
1932 D_word(inst); // Deposit instr
1933 ea0gen(siz); // Generate ea0
1935 // Generate ea1 if requested
1940 inst = a1reg + (a2reg << 12) + (1 << 10);
1948 // move16 (ax)+,(ay)+
1950 int m_move16a(WORD inst, WORD siz)
1952 if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1953 return error(unsupport);
1957 inst = (1 << 15) + (a1reg << 12);
1965 // move16 with absolute address
1967 int m_move16b(WORD inst, WORD siz)
1969 if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1970 return error(unsupport);
1976 if (am0 == APOSTINC)
1979 return error("Wasn't this suppose to call m_move16a???");
1982 //move16 (ax)+,(xxx).L
1987 else if (am0 == ABSL)
1991 //move16 (xxx).L,(ax)+
1997 //move16 (xxx).L,(ax)
2002 else if (am0 == AIND)
2004 //move16 (ax),(xxx).L
2017 // pack/unpack (68020/68030/68040)
2019 int m_pack(WORD inst, WORD siz)
2024 return error("bad size suffix");
2026 if (*tok >= KW_D0 && *tok <= KW_D7)
2028 // Dx,Dy,#<adjustment>
2029 inst |= (0 << 3); // R/M
2030 inst |= (*tok++ & 7);
2032 if (*tok != ',' && tok[2] != ',')
2033 return error("missing comma");
2035 if (tok[1] < KW_D0 && tok[1] > KW_D7)
2036 return error(syntax_error);
2038 inst |= ((tok[1] & 7)<<9);
2041 // Fall through for adjustment (common in both valid cases)
2043 else if (*tok == '-')
2045 // -(Ax),-(Ay),#<adjustment>
2046 inst |= (1 << 3); // R/M
2047 tok++; // eat the minus
2049 if ((*tok != '(') && (tok[2]!=')') && (tok[3]!=',') && (tok[4] != '-') && (tok[5] != '(') && (tok[7] != ')') && (tok[8] != ','))
2050 return error(syntax_error);
2052 if (tok[1] < KW_A0 && tok[1] > KW_A7)
2053 return error(syntax_error);
2055 if (tok[5] < KW_A0 && tok[6] > KW_A7)
2056 return error(syntax_error);
2058 inst |= ((tok[1] & 7) << 0);
2059 inst |= ((tok[6] & 7) << 9);
2062 // Fall through for adjustment (common in both valid cases)
2065 return error("invalid syntax");
2067 if ((*tok != CONST) && (*tok != SYMBOL) && (*tok != '-'))
2068 return error(syntax_error);
2070 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2073 if ((a0exattr & DEFINED) == 0)
2074 return error(undef_error);
2076 if (a0exval + 0x8000 > 0x10000)
2080 return error(extra_stuff);
2082 D_word((a0exval & 0xFFFF));
2091 int m_rtm(WORD inst, WORD siz)
2099 else if (am0 == AREG)
2101 inst |= (1 << 3) + a0reg;
2104 return error("rtm only allows data or address registers.");
2115 int m_rtd(WORD inst, WORD siz)
2119 if (a0exattr & DEFINED)
2122 return error(abs_error);
2124 if ((a0exval + 0x8000) <= 0x7FFF)
2125 return error(range_error);
2131 return error(undef_error);
2140 int m_trapcc(WORD inst, WORD siz)
2148 else if (am0 == IMMED)
2152 if (a0exval < 0x10000)
2159 return error("Immediate value too big");
2169 return error("Invalid parameter for trapcc");
2176 // cinvl/p/a (68040)
2178 int m_cinv(WORD inst, WORD siz)
2183 inst |= (0 << 6) | (a1reg);
2187 inst |= (2 << 6) | (a1reg);
2190 inst |= (1 << 6) | (a1reg);
2193 inst |= (3 << 6) | (a1reg);
2203 // cpRESTORE (68020, 68030)
2205 int m_cprest(WORD inst, WORD siz)
2207 if (activecpu & !(CPU_68020 | CPU_68030))
2208 return error(unsupport);
2210 inst |= am0 | a0reg;
2219 // movec (68010, 68020, 68030, 68040, CPU32)
2221 int m_movec(WORD inst, WORD siz)
2225 if (am0 == DREG || am0 == AREG)
2233 inst = (0 << 15) + (a0reg << 12) + CREGlut[a1reg];
2238 inst = (1 << 15) + (a0reg << 12) + CREGlut[a1reg];
2249 inst = (0 << 15) + (a1reg << 12) + CREGlut[a0reg];
2254 inst = (1 << 15) + (a1reg << 12) + CREGlut[a0reg];
2264 // moves (68010, 68020, 68030, 68040, CPU32)
2266 int m_moves(WORD inst, WORD siz)
2268 if (activecpu & !(CPU_68020 | CPU_68030 | CPU_68040))
2269 return error(unsupport);
2273 else if (siz == SIZL)
2280 inst |= am1 | a1reg;
2282 inst = (a0reg << 12) | (1 << 11) | (0 << 15);
2285 else if (am0 == AREG)
2287 inst |= am1 | a1reg;
2289 inst = (a0reg << 12) | (1 << 11) | (1 << 15);
2296 inst |= am0 | a0reg;
2298 inst = (a1reg << 12) | (0 << 11) | (0 << 15);
2303 inst |= am0 | a0reg;
2305 inst = (a1reg << 12) | (0 << 11) | (1 << 15);
2317 int m_pbcc(WORD inst, WORD siz)
2320 return error("Not implemented yet.");
2325 // pflusha (68030, 68040)
2327 int m_pflusha(WORD inst, WORD siz)
2329 if (activecpu == CPU_68030)
2332 inst = (1 << 13) | (1 << 10) | (0 << 5) | 0;
2336 else if (activecpu == CPU_68040)
2338 inst = B16(11110101, 00011000);
2343 return error(unsupport);
2350 // pflush (68030, 68040, 68060)
2352 int m_pflush(WORD inst, WORD siz)
2354 if (activecpu == CPU_68030)
2357 // PFLUSH FC, MASK, < ea >
2365 if (*tok != CONST && *tok != SYMBOL)
2366 return error("function code should be an expression");
2368 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2371 if ((a0exattr & DEFINED) == 0)
2372 return error("function code immediate should be defined");
2374 if (a0exval > 7 && a0exval < 0)
2375 return error("function code out of range (0-7)");
2377 fc = (uint16_t)a0exval;
2387 fc = (1 << 4) | (*tok++ & 7);
2398 return error(syntax_error);
2402 return error("comma exptected");
2405 return error("mask should be an immediate value");
2407 if (*tok != CONST && *tok != SYMBOL)
2408 return error("mask is supposed to be immediate");
2410 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2413 if ((a0exattr & DEFINED) == 0)
2414 return error("mask immediate value should be defined");
2416 if (a0exval > 7 && a0exval < 0)
2417 return error("function code out of range (0-7)");
2419 mask = (uint16_t)a0exval << 5;
2425 inst = (1 << 13) | fc | mask | (4 << 10);
2429 else if (*tok == ',')
2431 // PFLUSH FC, MASK, < ea >
2434 if (amode(0) == ERROR)
2438 return error(extra_stuff);
2440 if (am0 == AIND || am0 == ABSW || am0 == ABSL || am0 == ADISP || am0 == ADISP || am0 == AINDEXED || am0 == ABASE || am0 == MEMPOST || am0 == MEMPRE)
2442 inst |= am0 | a0reg;
2444 inst = (1 << 13) | fc | mask | (6 << 10);
2450 return error("unsupported addressing mode");
2454 return error(syntax_error);
2458 else if (activecpu == CPU_68040 || activecpu == CPU_68060)
2462 if (*tok != '(' && tok[2] != ')')
2463 return error(syntax_error);
2465 if (tok[1] < KW_A0 && tok[1] > KW_A7)
2466 return error("expected (An)");
2468 if ((inst & 7) == 7)
2469 // With pflushn/pflush there's no easy way to distinguish between
2470 // the two in 68040 mode. Ideally the opcode bitfields would have
2471 // been hardcoded in 68ktab but there is aliasing between 68030
2472 // and 68040 opcode. So we just set the 3 lower bits to 1 in
2473 // pflushn inside 68ktab and detect it here.
2474 inst = (inst & 0xff8) | 8;
2476 inst |= (tok[1] & 7) | (5 << 8);
2479 return error(extra_stuff);
2484 return error(unsupport);
2493 int m_pflushr(WORD inst, WORD siz)
2497 WORD flg = inst; // Save flag bits
2498 inst &= ~0x3F; // Clobber flag bits in instr
2500 // Install "standard" instr size bits
2506 // OR-in register number
2508 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
2510 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
2516 inst |= am1 | a1reg; // Get ea1 into instr
2517 D_word(inst); // Deposit instr
2519 // Generate ea0 if requested
2523 ea1gen(siz); // Generate ea1
2528 inst |= am0 | a0reg; // Get ea0 into instr
2529 D_word(inst); // Deposit instr
2530 ea0gen(siz); // Generate ea0
2532 // Generate ea1 if requested
2537 D_word(B16(10100000, 00000000));
2543 // ploadr, ploadw (68030)
2545 int m_pload(WORD inst, WORD siz, WORD extension)
2547 // TODO: 68851 support is not added yet.
2548 // None of the ST series of computers had a 68020 + 68851 socket and since
2549 // this is an Atari targetted assembler...
2558 if (a0reg == KW_SFC - KW_SFC)
2560 else if (a0reg == KW_DFC - KW_SFC)
2563 return error("illegal control register specified");
2567 inst = (1 << 3) | a0reg;
2570 if ((a0exattr & DEFINED) == 0)
2571 return error("constant value must be defined");
2573 inst = (2 << 3) | (uint16_t)a0exval;
2577 inst |= extension | (1 << 13);
2586 int m_ploadr(WORD inst, WORD siz)
2588 return m_pload(inst, siz, 1 << 9);
2592 int m_ploadw(WORD inst, WORD siz)
2594 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. None of the ST series of
2606 // computers had a 68020 + 68851 socket and since this is an Atari
2607 // targetted assembler.... (same for 68EC030)
2610 inst2 = inst & (1 << 8); // Copy the flush bit over to inst2 in case we're called from m_pmovefd
2611 inst &= ~(1 << 8); // And mask it out
2618 else if (am1 == CREG)
2624 return error("pmove sez: Wut?");
2626 // The instruction is a quad-word (8 byte) operation
2627 // for the CPU root pointer and the supervisor root pointer.
2628 // It is a long - word operation for the translation control register
2629 // and the transparent translation registers(TT0 and TT1).
2630 // It is a word operation for the MMU status register.
2632 if (((reg == (KW_URP - KW_SFC)) || (reg == (KW_SRP - KW_SFC)))
2633 && ((siz != SIZD) && (siz != SIZN)))
2634 return error(siz_error);
2636 if (((reg == (KW_TC - KW_SFC)) || (reg == (KW_TT0 - KW_SFC)) || (reg == (KW_TT1 - KW_SFC)))
2637 && ((siz != SIZL) && (siz != SIZN)))
2638 return error(siz_error);
2640 if ((reg == (KW_MMUSR - KW_SFC)) && ((siz != SIZW) && (siz != SIZN)))
2641 return error(siz_error);
2645 inst |= am1 | a1reg;
2648 else if (am1 == CREG)
2650 inst |= am0 | a0reg;
2654 switch (reg + KW_SFC)
2657 inst2 |= (0 << 10) + (1 << 14); break;
2659 inst2 |= (2 << 10) + (1 << 14); break;
2661 inst2 |= (3 << 10) + (1 << 14); break;
2663 inst2 |= (2 << 10) + (0 << 13); break;
2665 inst2 |= (3 << 10) + (0 << 13); break;
2668 inst2 |= (1 << 9) + (3 << 13);
2670 inst2 |= (0 << 9) + (3 << 13);
2673 return error("unsupported register");
2681 else if (am1 == CREG)
2691 int m_pmovefd(WORD inst, WORD siz)
2695 return m_pmove(inst | (1 << 8), siz);
2702 int m_ptrapcc(WORD inst, WORD siz)
2705 // We stash the 5 condition bits inside the opcode in 68ktab (bits 0-4),
2706 // so we need to extract them first and fill in the clobbered bits.
2707 WORD opcode = inst & 0x1F;
2708 inst = (inst & 0xFFE0) | (0x18);
2717 else if (siz == SIZL)
2724 else if (siz == SIZN)
2736 // ptestr, ptestw (68030)
2738 int m_ptest(WORD inst, WORD siz)
2742 if (activecpu == CPU_68030)
2743 return error("Not implemented yet.");
2744 else if (activecpu == CPU_68040)
2745 return error("Not implemented yet.");
2751 #define FPU_NOWARN 0
2752 #define FPU_P_EMUL 1
2753 #define FPU_P2_EMU 2
2758 // Generate a FPU opcode
2760 static inline int gen_fpu(WORD inst, WORD siz, WORD opmode, WORD emul)
2762 if (am0 < AM_NONE) // Check first operand for ea or fp - is this right?
2764 inst |= (1 << 9); // Bolt on FPU id
2771 inst = 1 << 14; // R/M field (we have ea so have to set this to 1)
2775 case SIZB: inst |= (6 << 10); break;
2776 case SIZW: inst |= (4 << 10); break;
2777 case SIZL: inst |= (0 << 10); break;
2779 case SIZS: inst |= (1 << 10); break;
2780 case SIZD: inst |= (5 << 10); break;
2781 case SIZX: inst |= (2 << 10); break;
2786 warn("This encoding will cause an unimplemented data type exception in the MC68040 to allow emulation in software.");
2790 return error("Something bad happened, possibly, in gen_fpu.");
2794 inst |= (a1reg << 7);
2801 inst |= (1 << 9); // Bolt on FPU id
2805 inst |= (a1reg << 7);
2810 if ((emul & FPU_FPSP) && (activefpu == FPU_68040))
2811 warn("Instruction is emulated in 68040");
2818 // fabs, fsabs, fdabs (6888X, 68040)
2820 int m_fabs(WORD inst, WORD siz)
2822 return gen_fpu(inst, siz, B8(00011000), FPU_P_EMUL);
2826 int m_fsabs(WORD inst, WORD siz)
2828 if (activefpu == FPU_68040)
2829 return gen_fpu(inst, siz, B8(01011000), FPU_P_EMUL);
2831 return error("Unsupported in current FPU");
2835 int m_fdabs(WORD inst, WORD siz)
2837 if (activefpu == FPU_68040)
2838 return gen_fpu(inst, siz, B8(01011100), FPU_P_EMUL);
2840 return error("Unsupported in current FPU");
2845 // facos (6888X, 68040FPSP)
2847 int m_facos(WORD inst, WORD siz)
2849 return gen_fpu(inst, siz, B8(00011100), FPU_FPSP);
2854 // fadd (6888X, 68040FPSP)
2856 int m_fadd(WORD inst, WORD siz)
2858 return gen_fpu(inst, siz, B8(00100010), FPU_P_EMUL);
2862 int m_fsadd(WORD inst, WORD siz)
2864 if (activefpu == FPU_68040)
2865 return gen_fpu(inst, siz, B8(01100010), FPU_P_EMUL);
2867 return error("Unsupported in current FPU");
2871 int m_fdadd(WORD inst, WORD siz)
2873 if (activefpu == FPU_68040)
2874 return gen_fpu(inst, siz, B8(01100110), FPU_P_EMUL);
2876 return error("Unsupported in current FPU");
2881 // fasin (6888X, 68040FPSP)f
2883 int m_fasin(WORD inst, WORD siz)
2885 return gen_fpu(inst, siz, B8(00001100), FPU_FPSP);
2890 // fatan (6888X, 68040FPSP)
2892 int m_fatan(WORD inst, WORD siz)
2894 return gen_fpu(inst, siz, B8(00001010), FPU_FPSP);
2899 // fatanh (6888X, 68040FPSP)
2901 int m_fatanh(WORD inst, WORD siz)
2903 return gen_fpu(inst, siz, B8(00001101), FPU_FPSP);
2908 // fcmp (6888X, 68040)
2910 int m_fcmp(WORD inst, WORD siz)
2912 return gen_fpu(inst, siz, B8(00111000), FPU_P_EMUL);
2917 // fcos (6888X, 68040FPSP)
2919 int m_fcos(WORD inst, WORD siz)
2921 return gen_fpu(inst, siz, B8(00011101), FPU_FPSP);
2926 // fcosh (6888X, 68040FPSP)
2928 int m_fcosh(WORD inst, WORD siz)
2930 return gen_fpu(inst, siz, B8(00011001), FPU_FPSP);
2935 // fdbcc (6888X, 68040)
2937 int m_fdbcc(WORD inst, WORD siz)
2939 WORD opcode = inst & 0x3F; // Grab conditional bitfield
2949 if (a1exattr & DEFINED)
2951 if ((a1exattr & TDB) != cursect)
2952 return error(rel_error);
2954 uint32_t v = (uint32_t)a1exval - sloc;
2956 if ((v + 0x8000) > 0x10000)
2957 return error(range_error);
2963 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
2972 // fdiv (6888X, 68040)
2974 int m_fdiv(WORD inst, WORD siz)
2976 return gen_fpu(inst, siz, B8(00100000), FPU_P_EMUL);
2980 int m_fsdiv(WORD inst, WORD siz)
2982 if (activefpu == FPU_68040)
2983 return gen_fpu(inst, siz, B8(01100000), FPU_P_EMUL);
2985 return error("Unsupported in current FPU");
2989 int m_fddiv(WORD inst, WORD siz)
2991 if (activefpu == FPU_68040)
2992 return gen_fpu(inst, siz, B8(01100100), FPU_P_EMUL);
2994 return error("Unsupported in current FPU");
2999 // fetox (6888X, 68040FPSP)
3001 int m_fetox(WORD inst, WORD siz)
3003 return gen_fpu(inst, siz, B8(00010000), FPU_FPSP);
3008 // fetoxm1 (6888X, 68040FPSP)
3010 int m_fetoxm1(WORD inst, WORD siz)
3012 return gen_fpu(inst, siz, B8(00001000), FPU_FPSP);
3017 // fgetexp (6888X, 68040FPSP)
3019 int m_fgetexp(WORD inst, WORD siz)
3021 return gen_fpu(inst, siz, B8(00011110), FPU_FPSP);
3026 // fgetman (6888X, 68040FPSP)
3028 int m_fgetman(WORD inst, WORD siz)
3030 return gen_fpu(inst, siz, B8(00011111), FPU_FPSP);
3035 // fint (6888X, 68040FPSP)
3037 int m_fint(WORD inst, WORD siz)
3040 // special case - fint fpx = fint fpx,fpx
3043 return gen_fpu(inst, siz, B8(00000001), FPU_FPSP);
3048 // fintrz (6888X, 68040FPSP)
3050 int m_fintrz(WORD inst, WORD siz)
3053 // special case - fintrz fpx = fintrz fpx,fpx
3056 return gen_fpu(inst, siz, B8(00000011), FPU_FPSP);
3061 // flog10 (6888X, 68040FPSP)
3063 int m_flog10(WORD inst, WORD siz)
3065 return gen_fpu(inst, siz, B8(00010101), FPU_FPSP);
3070 // flog2 (6888X, 68040FPSP)
3072 int m_flog2(WORD inst, WORD siz)
3074 return gen_fpu(inst, siz, B8(00010110), FPU_FPSP);
3079 // flogn (6888X, 68040FPSP)
3081 int m_flogn(WORD inst, WORD siz)
3083 return gen_fpu(inst, siz, B8(00010100), FPU_FPSP);
3088 // flognp1 (6888X, 68040FPSP)
3090 int m_flognp1(WORD inst, WORD siz)
3092 return gen_fpu(inst, siz, B8(00000110), FPU_FPSP);
3097 // fmod (6888X, 68040FPSP)
3099 int m_fmod(WORD inst, WORD siz)
3101 return gen_fpu(inst, siz, B8(00100001), FPU_FPSP);
3106 // fmove (6888X, 68040)
3108 int m_fmove(WORD inst, WORD siz)
3111 if ((am0 == FREG) && (am1 < AM_USP))
3115 inst |= am1 | a1reg;
3124 case SIZB: inst |= (6 << 10); break;
3125 case SIZW: inst |= (4 << 10); break;
3126 case SIZL: inst |= (0 << 10); break;
3128 case SIZS: inst |= (1 << 10); break;
3129 case SIZD: inst |= (5 << 10); break;
3130 case SIZX: inst |= (2 << 10); break;
3131 case SIZP: inst |= (3 << 10);
3132 // In P size we have 2 cases: {#k} where k is immediate
3133 // and {Dn} where Dn=Data register
3138 inst |= bfval1 << 4;
3143 if (bfval1 > 63 && bfval1 < -64)
3144 return error("K-factor must be between -64 and 63");
3146 inst |= bfval1 & 127;
3151 return error("Something bad happened, possibly.");
3155 // Destination specifier
3156 inst |= (a0reg << 7);
3164 else if ((am0 < AM_USP) && (am1 == FREG))
3169 inst |= am0 | a0reg;
3178 case SIZB: inst |= (6 << 10); break;
3179 case SIZW: inst |= (4 << 10); break;
3180 case SIZL: inst |= (0 << 10); break;
3182 case SIZS: inst |= (1 << 10); break;
3183 case SIZD: inst |= (5 << 10); break;
3184 case SIZX: inst |= (2 << 10); break;
3185 case SIZP: inst |= (3 << 10); break;
3187 return error("Something bad happened, possibly.");
3191 // Destination specifier
3192 inst |= (a1reg << 7);
3200 else if ((am0 == FREG) && (am1 == FREG))
3202 // register-to-register
3203 // Essentially ea to register with R/0=0
3213 return error("Invalid size");
3216 inst |= (a0reg << 10);
3218 // Destination register
3219 inst |= (a1reg << 7);
3229 // fmove (6888X, 68040)
3231 int m_fmovescr(WORD inst, WORD siz)
3233 // Move Floating-Point System Control Register (FPCR)
3237 if ((am0 == FPSCR) && (am1 < AM_USP))
3239 inst |= am1 | a1reg;
3241 inst = (1 << 13) + (1 << 15);
3247 else if ((am1 == FPSCR) && (am0 < AM_USP))
3249 inst |= am0 | a0reg;
3251 inst = (0 << 13) + (1 << 15);
3258 return error("m_fmovescr says: wut?");
3262 // fsmove/fdmove (68040)
3264 int m_fsmove(WORD inst, WORD siz)
3266 return error("Not implemented yet.");
3269 if (activefpu == FPU_68040)
3270 return gen_fpu(inst, siz, B8(01100100), FPU_P_EMUL);
3272 return error("Unsupported in current FPU");
3277 int m_fdmove(WORD inst, WORD siz)
3279 return error("Not implemented yet.");
3282 if (activefpu == FPU_68040)
3283 return gen_fpu(inst, siz, B8(01100100), FPU_P_EMUL);
3285 return error("Unsupported in current FPU");
3291 // fmovecr (6888X, 68040FPSP)
3293 int m_fmovecr(WORD inst, WORD siz)
3301 if (activefpu == FPU_68040)
3302 warn("Instruction is emulated in 68040");
3309 // fmovem (6888X, 68040)
3311 int m_fmovem(WORD inst, WORD siz)
3316 if (siz == SIZX || siz == SIZN)
3318 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
3320 //fmovem.x <rlist>,ea
3321 if (fpu_reglist_left(®mask) < 0)
3325 return error("missing comma");
3330 inst |= am0 | a0reg;
3332 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3333 return error("invalid addressing mode");
3336 inst = (1 << 15) | (1 << 14) | (1 << 13) | (0 << 11) | regmask;
3341 else if ((*tok >= KW_D0) && (*tok <= KW_D7))
3344 datareg = (*tok++ & 7) << 10;
3347 return error("missing comma");
3352 inst |= am0 | a0reg;
3354 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3355 return error("invalid addressing mode");
3358 inst = (1 << 15) | (1 << 14) | (1 << 13) | (1 << 11) | (datareg << 4);
3369 inst |= am0 | a0reg;
3372 return error("missing comma");
3374 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
3376 //fmovem.x ea,<rlist>
3377 if (fpu_reglist_right(®mask) < 0)
3381 inst = (1 << 15) | (1 << 14) | (0 << 13) | (2 << 11) | regmask;
3389 datareg = (*tok++ & 7) << 10;
3391 inst = (1 << 15) | (1 << 14) | (0 << 13) | (3 << 11) | (datareg << 4);
3398 else if (siz == SIZL)
3400 if ((*tok == KW_FPCR) || (*tok == KW_FPSR) || (*tok == KW_FPIAR))
3402 //fmovem.l <rlist>,ea
3403 regmask = (1 << 15) | (1 << 13);
3405 if (*tok == KW_FPCR)
3407 regmask |= (1 << 12);
3412 if (*tok == KW_FPSR)
3414 regmask |= (1 << 11);
3419 if (*tok == KW_FPIAR)
3421 regmask |= (1 << 10);
3426 if ((*tok == '/') || (*tok == '-'))
3433 return error("missing comma");
3438 inst |= am0 | a0reg;
3445 //fmovem.l ea,<rlist>
3449 inst |= am0 | a0reg;
3452 return error("missing comma");
3454 regmask = (1 << 15) | (0 << 13);
3457 if (*tok == KW_FPCR)
3459 regmask |= (1 << 12);
3464 if (*tok == KW_FPSR)
3466 regmask |= (1 << 11);
3471 if (*tok == KW_FPIAR)
3473 regmask |= (1 << 10);
3478 if ((*tok == '/') || (*tok == '-'))
3485 return error("extra (unexpected) text found");
3487 inst |= am0 | a0reg;
3494 return error("bad size suffix");
3501 // fmul (6888X, 68040)
3503 int m_fmul(WORD inst, WORD siz)
3505 return gen_fpu(inst, siz, B8(00100011), FPU_P_EMUL);
3509 int m_fsmul(WORD inst, WORD siz)
3511 if (activefpu == FPU_68040)
3512 return gen_fpu(inst, siz, B8(01100011), FPU_P_EMUL);
3514 return error("Unsupported in current FPU");
3518 int m_fdmul(WORD inst, WORD siz)
3520 if (activefpu == FPU_68040)
3521 return gen_fpu(inst, siz, B8(01100111), FPU_P_EMUL);
3523 return error("Unsupported in current FPU");
3528 // fneg (6888X, 68040)
3530 int m_fneg(WORD inst, WORD siz)
3532 return gen_fpu(inst, siz, B8(00011010), FPU_P_EMUL);
3536 int m_fsneg(WORD inst, WORD siz)
3538 if (activefpu == FPU_68040)
3539 return gen_fpu(inst, siz, B8(01011010), FPU_P_EMUL);
3541 return error("Unsupported in current FPU");
3545 int m_fdneg(WORD inst, WORD siz)
3547 if (activefpu == FPU_68040)
3548 return gen_fpu(inst, siz, B8(01011110), FPU_P_EMUL);
3550 return error("Unsupported in current FPU");
3555 // fnop (6888X, 68040)
3557 int m_fnop(WORD inst, WORD siz)
3559 return gen_fpu(inst, siz, B8(00000000), FPU_P_EMUL);
3564 // frem (6888X, 68040FPSP)
3566 int m_frem(WORD inst, WORD siz)
3568 return gen_fpu(inst, siz, B8(00100101), FPU_FPSP);
3573 // fscale (6888X, 68040FPSP)
3575 int m_fscale(WORD inst, WORD siz)
3577 return gen_fpu(inst, siz, B8(00100110), FPU_FPSP);
3582 // FScc (6888X, 68040), cpScc (68851, 68030), PScc (68851)
3583 // TODO: Add check for PScc to ensure 68020+68851 active
3584 // TODO: Add check for cpScc to ensure 68020+68851, 68030
3586 int m_fscc(WORD inst, WORD siz)
3588 // We stash the 5 condition bits inside the opcode in 68ktab (bits 4-0),
3589 // so we need to extract them first and fill in the clobbered bits.
3590 WORD opcode = inst & 0x1F;
3592 inst |= am0 | a0reg;
3601 // FTRAPcc (6888X, 68040)
3603 int m_ftrapcc(WORD inst, WORD siz)
3605 // We stash the 5 condition bits inside the opcode in 68ktab (bits 3-7),
3606 // so we need to extract them first and fill in the clobbered bits.
3607 WORD opcode = (inst >> 3) & 0x1F;
3608 inst = (inst & 0xFF07) | (0xF << 3);
3617 else if (siz == SIZL)
3624 else if (siz = SIZN)
3637 // fsgldiv (6888X, 68040)
3639 int m_fsgldiv(WORD inst, WORD siz)
3641 return gen_fpu(inst, siz, B8(00100100), FPU_P_EMUL);
3646 // fsglmul (6888X, 68040)
3648 int m_fsglmul(WORD inst, WORD siz)
3650 return gen_fpu(inst, siz, B8(00100111), FPU_P_EMUL);
3655 // fsin (6888X, 68040FPSP)
3657 int m_fsin(WORD inst, WORD siz)
3659 return gen_fpu(inst, siz, B8(00001110), FPU_FPSP);
3664 // fsincos (6888X, 68040FPSP)
3666 int m_fsincos(WORD inst, WORD siz)
3668 // Swap a1reg, a2reg as a2reg should be stored in the bitfield gen_fpu
3675 if (gen_fpu(inst, siz, B8(00110000), FPU_FPSP) == OK)
3686 // fsin (6888X, 68040FPSP)
3688 int m_fsinh(WORD inst, WORD siz)
3690 return gen_fpu(inst, siz, B8(00000010), FPU_FPSP);
3695 // fsqrt (6888X, 68040)
3697 int m_fsqrt(WORD inst, WORD siz)
3699 return gen_fpu(inst, siz, B8(00000100), FPU_P_EMUL);
3703 int m_fsfsqrt(WORD inst, WORD siz)
3705 if (activefpu == FPU_68040)
3706 return gen_fpu(inst, siz, B8(01000001), FPU_P_EMUL);
3708 return error("Unsupported in current FPU");
3712 int m_fdfsqrt(WORD inst, WORD siz)
3714 if (activefpu == FPU_68040)
3715 return gen_fpu(inst, siz, B8(01000101), FPU_P_EMUL);
3717 return error("Unsupported in current FPU");
3722 // fsub (6888X, 68040)
3724 int m_fsub(WORD inst, WORD siz)
3726 return gen_fpu(inst, siz, B8(00101000), FPU_P_EMUL);
3730 int m_fsfsub(WORD inst, WORD siz)
3732 if (activefpu == FPU_68040)
3733 return gen_fpu(inst, siz, B8(01101000), FPU_P_EMUL);
3735 return error("Unsupported in current FPU");
3739 int m_fdsub(WORD inst, WORD siz)
3741 if (activefpu == FPU_68040)
3742 return gen_fpu(inst, siz, B8(01101100), FPU_P_EMUL);
3744 return error("Unsupported in current FPU");
3749 // ftan (6888X, 68040FPSP)
3751 int m_ftan(WORD inst, WORD siz)
3753 return gen_fpu(inst, siz, B8(00001111), FPU_FPSP);
3758 // ftanh (6888X, 68040FPSP)
3760 int m_ftanh(WORD inst, WORD siz)
3762 return gen_fpu(inst, siz, B8(00001001), FPU_FPSP);
3767 // ftentox (6888X, 68040FPSP)
3769 int m_ftentox(WORD inst, WORD siz)
3771 return gen_fpu(inst, siz, B8(00010010), FPU_FPSP);
3776 // ftst (6888X, 68040)
3778 int m_ftst(WORD inst, WORD siz)
3780 return gen_fpu(inst, siz, B8(00111010), FPU_P_EMUL);
3785 // ftwotox (6888X, 68040FPSP)
3787 int m_ftwotox(WORD inst, WORD siz)
3789 return gen_fpu(inst, siz, B8(00010001), FPU_FPSP);