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, WORD);
45 int m_moveq(WORD, WORD);
46 int m_usp(WORD, WORD);
47 int m_movep(WORD, WORD);
48 int m_trap(WORD, WORD);
49 int m_movem(WORD, WORD);
50 int m_clra(WORD, WORD);
51 int m_clrd(WORD, WORD);
53 int m_move30(WORD, WORD); // 68020/30/40/60
54 int m_br30(WORD inst, WORD siz);
55 int m_ea030(WORD inst, WORD siz);
56 int m_bfop(WORD inst, WORD siz);
57 int m_callm(WORD inst, WORD siz);
58 int m_cas(WORD inst, WORD siz);
59 int m_cas2(WORD inst, WORD siz);
60 int m_chk2(WORD inst, WORD siz);
61 int m_cmp2(WORD inst, WORD siz);
62 int m_bkpt(WORD inst, WORD siz);
63 int m_cpbr(WORD inst, WORD siz);
64 int m_cpdbr(WORD inst, WORD siz);
65 int m_muls(WORD inst, WORD siz);
66 int m_move16a(WORD inst, WORD siz);
67 int m_move16b(WORD inst, WORD siz);
68 int m_pack(WORD inst, WORD siz);
69 int m_rtm(WORD inst, WORD siz);
70 int m_rtd(WORD inst, WORD siz);
71 int m_trapcc(WORD inst, WORD siz);
72 int m_cinv(WORD inst, WORD siz);
73 int m_cprest(WORD inst, WORD siz);
74 int m_movec(WORD inst, WORD siz);
75 int m_moves(WORD inst, WORD siz);
78 int m_pbcc(WORD inst, WORD siz);
79 int m_pflusha(WORD inst, WORD siz);
80 int m_pflush(WORD inst, WORD siz);
81 int m_pflushr(WORD inst, WORD siz);
82 int m_pload(WORD inst, WORD siz, WORD extension);
83 int m_pmove(WORD inst, WORD siz);
84 int m_pmovefd(WORD inst, WORD siz);
85 int m_ptest(WORD inst, WORD siz);
86 int m_ptrapcc(WORD inst, WORD siz);
87 int m_ploadr(WORD inst, WORD siz);
88 int m_ploadw(WORD inst, WORD siz);
91 int m_fabs(WORD inst, WORD siz);
92 int m_facos(WORD inst, WORD siz);
93 int m_fadd(WORD inst, WORD siz);
94 int m_fasin(WORD inst, WORD siz);
95 int m_fatan(WORD inst, WORD siz);
96 int m_fatanh(WORD inst, WORD siz);
97 int m_fcmp(WORD inst, WORD siz);
98 int m_fcos(WORD inst, WORD siz);
99 int m_fcosh(WORD inst, WORD siz);
100 int m_fdabs(WORD inst, WORD siz);
101 int m_fdadd(WORD inst, WORD siz);
102 int m_fdbcc(WORD inst, WORD siz);
103 int m_fddiv(WORD inst, WORD siz);
104 int m_fdfsqrt(WORD inst, WORD siz);
105 int m_fdiv(WORD inst, WORD siz);
106 int m_fdmove(WORD inst, WORD siz);
107 int m_fdmul(WORD inst, WORD siz);
108 int m_fdneg(WORD inst, WORD siz);
109 int m_fdsub(WORD inst, WORD siz);
110 int m_fetox(WORD inst, WORD siz);
111 int m_fetoxm1(WORD inst, WORD siz);
112 int m_fgetexp(WORD inst, WORD siz);
113 int m_fgetman(WORD inst, WORD siz);
114 int m_fint(WORD inst, WORD siz);
115 int m_fintrz(WORD inst, WORD siz);
116 int m_flog10(WORD inst, WORD siz);
117 int m_flog2(WORD inst, WORD siz);
118 int m_flogn(WORD inst, WORD siz);
119 int m_flognp1(WORD inst, WORD siz);
120 int m_fmod(WORD inst, WORD siz);
121 int m_fmove(WORD inst, WORD siz);
122 int m_fmovescr(WORD inst, WORD siz);
123 int m_fmovecr(WORD inst, WORD siz);
124 int m_fmovem(WORD inst, WORD siz);
125 int m_fmul(WORD inst, WORD siz);
126 int m_fneg(WORD inst, WORD siz);
127 int m_fnop(WORD inst, WORD siz);
128 int m_frem(WORD inst, WORD siz);
129 int m_fsabs(WORD inst, WORD siz);
130 int m_fsadd(WORD inst, WORD siz);
131 int m_fscc(WORD inst, WORD siz);
132 int m_fscale(WORD inst, WORD siz);
133 int m_fsdiv(WORD inst, WORD siz);
134 int m_fsfsqrt(WORD inst, WORD siz);
135 int m_fsfsub(WORD inst, WORD siz);
136 int m_fsgldiv(WORD inst, WORD siz);
137 int m_fsglmul(WORD inst, WORD siz);
138 int m_fsin(WORD inst, WORD siz);
139 int m_fsincos(WORD inst, WORD siz);
140 int m_fsinh(WORD inst, WORD siz);
141 int m_fsmove(WORD inst, WORD siz);
142 int m_fsmul(WORD inst, WORD siz);
143 int m_fsneg(WORD inst, WORD siz);
144 int m_fsqrt(WORD inst, WORD siz);
145 int m_fsub(WORD inst, WORD siz);
146 int m_ftan(WORD inst, WORD siz);
147 int m_ftanh(WORD inst, WORD siz);
148 int m_ftentox(WORD inst, WORD siz);
149 int m_ftst(WORD inst, WORD siz);
150 int m_ftwotox(WORD inst, WORD siz);
151 int m_ftrapcc(WORD inst, WORD siz);
153 // Common error messages
154 char range_error[] = "expression out of range";
155 char abs_error[] = "illegal absolute expression";
156 char seg_error[] = "bad (section) expression";
157 char rel_error[] = "illegal relative address";
158 char siz_error[] = "bad size specified";
159 char undef_error[] = "undefined expression";
160 char fwd_error[] = "forward or undefined expression";
161 char unsupport[] = "unsupported for selected CPU";
163 // Include code tables
165 { 0xFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000, 0, m_badmode }, // 0
167 { 0, 0L, 0L, 0x0000, 0, m_unimp } // Last entry
170 // Register number << 9
172 0, 1 << 9, 2 << 9, 3 << 9, 4 << 9, 5 << 9, 6 << 9, 7 << 9
175 // SIZB==>00, SIZW==>01, SIZL==>10, SIZN==>01 << 6
179 1<<6, (WORD)-1, // SIZW, n/a
180 2<<6, (WORD)-1, (WORD)-1, (WORD)-1, // SIZL, n/a, n/a, n/a
184 // Byte/word/long size for MOVE instrs
188 0x3000, (WORD)-1, // Word
189 0x2000, (WORD)-1, (WORD)-1, (WORD)-1, // Long
190 0x3000 // Word (SIZN)
193 // Word/long size (0=.w, 1=.l) in bit 8
197 0, (WORD)-1, // SIZW, n/a
198 1<<8, (WORD)-1, (WORD)-1, (WORD)-1, // SIZL, n/a, n/a, n/a
202 // Byte/Word/long size (0=.w, 1=.l) in bit 9
206 1<<9, (WORD)-1, // Word
207 1<<10, (WORD)-1, (WORD)-1, (WORD)-1, // Long
211 // Addressing mode in bits 6..11 (register/mode fields are reversed)
213 00000, 01000, 02000, 03000, 04000, 05000, 06000, 07000,
214 00100, 01100, 02100, 03100, 04100, 05100, 06100, 07100,
215 00200, 01200, 02200, 03200, 04200, 05200, 06200, 07200,
216 00300, 01300, 02300, 03300, 04300, 05300, 06300, 07300,
217 00400, 01400, 02400, 03400, 04400, 05400, 06400, 07400,
218 00500, 01500, 02500, 03500, 04500, 05500, 06500, 07500,
219 00600, 01600, 02600, 03600, 04600, 05600, 06600, 07600,
220 00700, 01700, 02700, 03700, 04700, 05700, 06700, 07700
223 // Control registers lookup table
225 // MC68010/MC68020/MC68030/MC68040/CPU32
226 0x000, // Source Function Code(SFC)
227 0x001, // Destination Function Code(DFC)
228 0x800, // User Stack Pointer(USP)
229 0x801, // Vector Base Register(VBR)
230 // MC68020 / MC68030 / MC68040
231 0x002, // Cache Control Register(CACR)
232 0x802, // Cache Address Register(CAAR) (020/030 only)
233 0x803, // Master Stack Pointer(MSP)
234 0x804, // Interrupt Stack Pointer(ISP)
235 // MC68040 / MC68LC040
236 0x003, // MMU Translation Control Register(TC)
237 0x004, // Instruction Transparent Translation Register 0 (ITT0)
238 0x005, // Instruction Transparent Translation Register 1 (ITT1)
239 0x006, // Data Transparent Translation Register 0 (DTT0)
240 0x007, // Data Transparent Translation Register 1 (DTT1)
241 0x805, // MMU Status Register(MMUSR)
242 0x806, // User Root Pointer(URP)
243 0x807, // Supervisor Root Pointer(SRP)
245 0x004, // Instruction Access Control Register 0 (IACR0)
246 0x005, // Instruction Access Control Register 1 (IACR1)
247 0x006, // Data Access Control Register 0 (DACR1)
248 0x007, // Data Access Control Register 1 (DACR1)
250 0xFFF // CPU Root Pointer (CRP) - There's no movec with CRP in it, this is just a guard entry
255 int m_unimp(WORD unused1, WORD unused2)
257 return (int)error("unimplemented mnemonic");
261 //int m_badmode(void)
262 int m_badmode(WORD unused1, WORD unused2)
264 return (int)error("inappropriate addressing mode");
268 int m_self(WORD inst, WORD usused)
276 // Do one EA in bits 0..5
278 // Bits in `inst' have the following meaning:
280 // Bit zero specifies which ea (ea0 or ea1) to generate in the lower six bits
283 // If bit one is set, the OTHER ea (the one that wasn't generated by bit zero)
284 // is generated after the instruction. Regardless of bit 0's value, ea0 is
285 // always deposited in memory before ea1.
287 // If bit two is set, standard size bits are set in the instr in bits 6 and 7.
289 // If bit four is set, bit three specifies which eaXreg to place in bits 9..11
292 int m_ea(WORD inst, WORD siz)
294 WORD flg = inst; // Save flag bits
295 inst &= ~0x3F; // Clobber flag bits in instr
297 // Install "standard" instr size bits
303 // OR-in register number
305 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
307 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
313 inst |= am1 | a1reg; // Get ea1 into instr
314 D_word(inst); // Deposit instr
316 // Generate ea0 if requested
320 ea1gen(siz); // Generate ea1
325 inst |= am0 | a0reg; // Get ea0 into instr
326 D_word(inst); // Deposit instr
327 ea0gen(siz); // Generate ea0
329 // Generate ea1 if requested
339 // Check if lea x(an),an can be optimised to addq.w #x,an--otherwise fall back
342 int m_lea(WORD inst, WORD siz)
344 if (CHECK_OPTS(OPT_LEA_ADDQ)
345 && ((am0 == ADISP) && (a0reg == a1reg) && (a0exattr & DEFINED))
346 && ((a0exval > 0) && (a0exval <= 8)))
348 inst = B16(01010000, 01001000) | (((uint16_t)a0exval & 7) << 9) | (a0reg);
350 warn("lea size(An),An converted to addq #size,An");
354 return m_ea(inst, siz);
358 int m_ea030(WORD inst, WORD siz)
361 WORD flg = inst; // Save flag bits
362 inst &= ~0x3F; // Clobber flag bits in instr
364 // Install "standard" instr size bits
370 // OR-in register number
373 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
377 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
384 inst |= am1 | a1reg; // Get ea1 into instr
385 D_word(inst); // Deposit instr
387 // Generate ea0 if requested
391 ea1gen(siz); // Generate ea1
397 // We get here if we're doing 020+ addressing and an address
398 // register is used. For example, something like "tst a0". A bit of
399 // a corner case, so kludge it
401 else if (am0 == PCDISP)
402 //Another corner case (possibly!), so kludge ahoy
403 inst |= am0; // Get ea0 into instr
404 else if (am0 == IMMED)
405 inst |= am0 | a0reg; // Get ea0 into instr
406 else if (am0 == AM_CCR)
408 else if (am0 == AIND)
411 inst |= a0reg; // Get ea0 into instr
412 D_word(inst); // Deposit instr
413 ea0gen(siz); // Generate ea0
415 // Generate ea1 if requested
425 // Dx,Dy nnnnXXXnssnnnYYY If bit 0 of `inst' is set, install size bits in bits
428 int m_abcd(WORD inst, WORD siz)
437 inst |= a0reg | reg_9[a1reg];
447 int m_adda(WORD inst, WORD siz)
449 if (a0exattr & DEFINED)
451 if (CHECK_OPTS(OPT_ADDA_ADDQ))
452 if (a0exval > 1 && a0exval <= 8)
453 // Immediate is between 1 and 8 so let's convert to addq
454 return m_addq(B16(01010000, 00000000), siz);
455 if (CHECK_OPTS(OPT_ADDA_LEA))
458 // Immediate is larger than 8 so let's convert to lea
459 am0 = ADISP; // Change addressing mode
460 a0reg = a1reg; // In ADISP a0reg is used instead of a1reg!
461 return m_lea(B16(01000001, 11011000), SIZW);
465 inst |= am0 | a0reg | lwsiz_8[siz] | reg_9[a1reg];
467 ea0gen(siz); // Generate EA
474 // If bit 0 of `inst' is 1, install size bits in bits 6..7 of instr.
475 // If bit 1 of `inst' is 1, install a1reg in bits 9..11 of instr.
477 int m_reg(WORD inst, WORD siz)
484 // Install other register (9..11)
485 inst |= reg_9[a1reg];
487 inst &= ~7; // Clear off crufty bits
488 inst |= a0reg; // Install first register
498 int m_imm(WORD inst, WORD siz)
510 int m_imm8(WORD inst, WORD siz)
523 int m_shr(WORD inst, WORD siz)
525 inst |= reg_9[a0reg] | a1reg | siz_6[siz];
535 int m_shi(WORD inst, WORD siz)
537 inst |= a1reg | siz_6[siz];
539 if (a0exattr & DEFINED)
542 return error(range_error);
544 inst |= (a0exval & 7) << 9;
549 AddFixup(FU_QUICK, sloc, a0expr);
558 // {bset, btst, bchg, bclr} -- #immed,ea -- Dn,ea
560 int m_bitop(WORD inst, WORD siz)
562 // Enforce instruction sizes
564 { // X,Dn must be .n or .l
565 if (siz & (SIZB | SIZW))
566 return error(siz_error);
568 else if (siz & (SIZW | SIZL)) // X,ea must be .n or .b
569 return error(siz_error);
571 // Construct instr and EAs
577 ea0gen(SIZB); // Immediate bit number
581 inst |= reg_9[a0reg];
592 int m_dbra(WORD inst, WORD siz)
598 if (a1exattr & DEFINED)
600 if ((a1exattr & TDB) != cursect)
601 return error(rel_error);
603 uint32_t v = a1exval - sloc;
605 if (v + 0x8000 > 0x10000)
606 return error(range_error);
612 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
623 int m_exg(WORD inst, WORD siz)
629 if (am0 == DREG && am1 == DREG)
631 else if (am0 == AREG && am1 == AREG)
637 m = a1reg; // Get AREG into a1reg
645 inst |= m | reg_9[a0reg] | a1reg;
655 int m_link(WORD inst, WORD siz)
659 // Is this an error condition???
664 inst &= ~((3 << 9) | (1 << 6) | (1 << 4));
676 WORD extra_addressing[16]=
678 0, // 0100 (bd,An,Xn)
679 0, // 0101 ([bd,An],Xn,od)
680 0x180, // 0102 ([bc,An,Xn],od) (111 110 110 111)
681 0, // 0103 (bd,PC,Xn)
682 0, // 0104 ([bd,PC],Xn,od)
683 0, // 0105 ([bc,PC,Xn],od)
698 // Handle MOVE <C_ALL> <C_ALTDATA>
699 // MOVE <C_ALL> <M_AREG>
701 // Optimize MOVE.L #<smalldata>,D0 to a MOVEQ
703 int m_move(WORD inst, WORD size)
705 // Cast the passed in value to an int
708 // Try to optimize to MOVEQ
709 // N.B.: We can get away with casting the uint64_t to a 32-bit value
710 // because it checks for a SIZL (i.e., a 32-bit value).
711 if (CHECK_OPTS(OPT_MOVEL_MOVEQ)
712 && (siz == SIZL) && (am0 == IMMED) && (am1 == DREG)
713 && ((a0exattr & (TDB | DEFINED)) == DEFINED)
714 && ((uint32_t)a0exval + 0x80 < 0x100))
716 m_moveq((WORD)0x7000, (WORD)0);
719 warn("move.l #size,dx converted to moveq");
723 if ((am0 < ABASE) && (am1 < ABASE)) // 68000 modes
725 inst |= siz_12[siz] | am_6[am1] | reg_9[a1reg] | am0 | a0reg;
733 ea1gen((WORD)siz | 0x8000); // Tell ea1gen we're move ea,ea
737 inst |= siz_12[siz] | reg_9[a1reg] | extra_addressing[am0 - ABASE];
754 // Handle MOVE <C_ALL030> <C_ALTDATA>
755 // MOVE <C_ALL030> <M_AREG>
757 int m_move30(WORD inst, WORD size)
760 // TODO: is extra_addressing necessary/correct?
761 //inst |= siz_12[siz] | reg_9[a1reg & 7] | a0reg | extra_addressing[am0 - ABASE];
762 inst |= siz_12[siz] | reg_9[a1reg & 7] | a0reg;
777 // move USP,An -- move An,USP
779 int m_usp(WORD inst, WORD siz)
784 inst |= a1reg; // USP, An
786 inst |= a0reg; // An, USP
797 int m_moveq(WORD inst, WORD siz)
801 // Arrange for future fixup
802 if (!(a0exattr & DEFINED))
804 AddFixup(FU_BYTE | FU_SEXT, sloc + 1, a0expr);
807 else if ((uint32_t)a0exval + 0x100 >= 0x200)
808 return error(range_error);
810 inst |= reg_9[a1reg] | (a0exval & 0xFF);
818 // movep Dn, disp(An) -- movep disp(An), Dn
820 int m_movep(WORD inst, WORD siz)
822 // Tell ea0gen to lay off the 0(a0) optimisations on this one
830 inst |= reg_9[a0reg] | a1reg;
840 inst |= reg_9[a1reg] | a0reg;
857 int m_br(WORD inst, WORD siz)
859 if (a0exattr & DEFINED)
861 if ((a0exattr & TDB) != cursect)
863 //printf("m_br(): a0exattr = %X, cursect = %X, a0exval = %X, sloc = %X\n", a0exattr, cursect, a0exval, sloc);
864 return error(rel_error);
867 uint32_t v = (uint32_t)a0exval - (sloc + 2);
869 // Optimize branch instr. size
872 if (CHECK_OPTS(OPT_BSR_BCC_S) && (v != 0) && ((v + 0x80) < 0x100))
879 warn("Bcc.w/BSR.w converted to .s");
886 if ((v + 0x8000) > 0x10000)
887 return error(range_error);
895 if (siz == SIZB || siz == SIZS)
897 if ((v + 0x80) >= 0x100)
898 return error(range_error);
905 if ((v + 0x8000) >= 0x10000)
906 return error(range_error);
914 else if (siz == SIZN)
917 if (siz == SIZB || siz == SIZS)
920 AddFixup(FU_BBRA | FU_PCREL | FU_SEXT, sloc, a0expr);
928 AddFixup(FU_WORD | FU_PCREL | FU_LBRA | FU_ISBRA, sloc, a0expr);
939 int m_addq(WORD inst, WORD siz)
941 inst |= siz_6[siz] | am1 | a1reg;
943 if (a0exattr & DEFINED)
945 if ((a0exval > 8) || (a0exval == 0)) // Range in 1..8
946 return error(range_error);
948 inst |= (a0exval & 7) << 9;
953 AddFixup(FU_QUICK, sloc, a0expr);
966 int m_trap(WORD inst, WORD siz)
970 if (a0exattr & DEFINED)
973 return error(abs_error);
976 return error(range_error);
982 return error(undef_error);
989 // movem <rlist>,ea -- movem ea,<rlist>
991 int m_movem(WORD inst, WORD siz)
999 return error("bad size suffix");
1006 // Handle #<expr>, ea
1009 if (abs_expr(&eval) != OK)
1012 if (eval >= 0x10000L)
1013 return error(range_error);
1019 if ((*tok >= KW_D0) && (*tok <= KW_A7))
1022 if (reglist(&rmask) < 0)
1027 return error("missing comma");
1032 inst |= am0 | a0reg;
1034 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
1035 return error("invalid addressing mode");
1037 // If APREDEC, reverse register mask
1043 for(i=0x8000; i; i>>=1, w>>=1)
1044 rmask = (WORD)((rmask << 1) | w & 1);
1053 inst |= 0x0400 | am0 | a0reg;
1056 return error("missing comma");
1059 return error("missing register list");
1066 if (abs_expr(&eval) != OK)
1069 if (eval >= 0x10000)
1070 return error(range_error);
1074 else if (reglist(&rmask) < 0)
1077 if (!(amsktab[am0] & (C_CTRL | M_APOSTINC)))
1078 return error("invalid addressing mode");
1090 // CLR.x An ==> SUBA.x An,An
1092 int m_clra(WORD inst, WORD siz)
1094 inst |= a0reg | reg_9[a0reg] | lwsiz_8[siz];
1102 // CLR.L Dn ==> CLR.L An or MOVEQ #0,Dx
1104 int m_clrd(WORD inst, WORD siz)
1106 if (!CHECK_OPTS(OPT_CLR_DX))
1109 inst = (a0reg << 9) | B16(01110000, 00000000);
1117 ////////////////////////////////////////
1119 // 68020/30/40/60 instructions
1121 ////////////////////////////////////////
1126 int m_br30(WORD inst, WORD siz)
1128 if (a0exattr & DEFINED)
1130 if ((a0exattr & TDB) != cursect)
1131 return error(rel_error);
1133 uint32_t v = (uint32_t)a0exval - (sloc + 2);
1142 AddFixup(FU_LONG | FU_PCREL | FU_SEXT, sloc, a0expr);
1150 // bfchg, bfclr, bfexts, bfextu, bfffo, bfins, bfset
1151 // (68020, 68030, 68040)
1153 int m_bfop(WORD inst, WORD siz)
1155 if ((bfval1 > 31) || (bfval1 < 0))
1156 return error("bfxxx offset: immediate value must be between 0 and 31");
1158 // First instruction word - just the opcode and first EA
1159 // Note: both am1 is ORed because solely of bfins - maybe it's a good idea
1160 // to make a dedicated function for it?
1167 if (bfval2 > 31 || bfval2 < 0)
1168 return error("bfxxx width: immediate value must be between 0 and 31");
1170 // For Dw both immediate and register number are stuffed
1171 // into the same field O_o
1172 bfparam2 = (bfval2 << 0);
1176 bfparam1 = (bfval1 << 6);
1178 bfparam1 = bfval1 << 12;
1180 D_word((inst | am0 | a0reg | am1 | a1reg));
1181 ea0gen(siz); // Generate EA
1183 // Second instruction word - Dest register (if exists), Do, Offset, Dw, Width
1184 inst = bfparam1 | bfparam2;
1190 inst |= a0reg << 12;
1199 // bkpt (68EC000, 68010, 68020, 68030, 68040, CPU32)
1201 int m_bkpt(WORD inst, WORD siz)
1205 if (a0exattr & DEFINED)
1208 return error(abs_error);
1211 return error(range_error);
1217 return error(undef_error);
1226 int m_callm(WORD inst, WORD siz)
1233 if (a0exattr & DEFINED)
1236 return error(abs_error);
1239 return error(range_error);
1241 inst = (uint16_t)a0exval;
1245 return error(undef_error);
1255 // cas (68020, 68030, 68040)
1257 int m_cas(WORD inst, WORD siz)
1263 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1264 return error(unsupport);
1279 return error("bad size suffix");
1284 if ((*tok < KW_D0) && (*tok > KW_D7))
1285 return error("CAS accepts only data registers");
1287 inst2 = (*tok++) & 7;
1290 return error("missing comma");
1293 if ((*tok < KW_D0) && (*tok > KW_D7))
1294 return error("CAS accepts only data registers");
1296 inst2 |= ((*tok++) & 7) << 6;
1299 return error("missing comma");
1302 if ((modes = amode(1)) < 0)
1306 return error("too many ea fields");
1309 return error("extra (unexpected) text found");
1311 // Reject invalid ea modes
1312 amsk = amsktab[am0];
1314 if ((amsk & (M_AIND | M_APOSTINC | M_APREDEC | M_ADISP | M_AINDEXED | M_ABSW | M_ABSL | M_ABASE | M_MEMPOST | M_MEMPRE)) == 0)
1315 return error("unsupported addressing mode");
1317 inst |= am0 | a0reg;
1327 // cas2 (68020, 68030, 68040)
1329 int m_cas2(WORD inst, WORD siz)
1333 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1334 return error(unsupport);
1349 return error("bad size suffix");
1354 if ((*tok < KW_D0) && (*tok > KW_D7))
1355 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1357 inst2 = (*tok++) & 7;
1360 return error("missing colon");
1363 if ((*tok < KW_D0) && (*tok > KW_D7))
1364 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1366 inst3 = (*tok++) & 7;
1369 return error("missing comma");
1372 if ((*tok < KW_D0) && (*tok > KW_D7))
1373 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1375 inst2 |= ((*tok++) & 7) << 6;
1378 return error("missing colon");
1381 if ((*tok < KW_D0) && (*tok > KW_D7))
1382 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1384 inst3 |= ((*tok++) & 7) << 6;
1387 return error("missing comma");
1391 return error("missing (");
1392 if ((*tok >= KW_D0) && (*tok <= KW_D7))
1393 inst2 |= (((*tok++) & 7) << 12) | (0 << 15);
1394 else if ((*tok >= KW_A0) && (*tok <= KW_A7))
1395 inst2 |= (((*tok++) & 7) << 12) | (1 << 15);
1397 return error("CAS accepts either data or address registers for Rn1:Rn2 pair");
1400 return error("missing (");
1403 return error("missing colon");
1407 return error("missing (");
1408 if ((*tok >= KW_D0) && (*tok <= KW_D7))
1409 inst3 |= (((*tok++) & 7) << 12) | (0 << 15);
1410 else if ((*tok >= KW_A0) && (*tok <= KW_A7))
1411 inst3 |= (((*tok++) & 7) << 12) | (1 << 15);
1413 return error("CAS accepts either data or address registers for Rn1:Rn2 pair");
1416 return error("missing (");
1419 return error("extra (unexpected) text found");
1430 // cmp2 (68020, 68030, 68040, CPU32)
1432 int m_cmp2(WORD inst, WORD siz)
1434 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1435 return error(unsupport);
1437 switch (siz & 0x000F)
1451 WORD flg = inst; // Save flag bits
1452 inst &= ~0x3F; // Clobber flag bits in instr
1454 // Install "standard" instr size bits
1460 // OR-in register number
1462 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1464 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1470 inst |= am1 | a1reg; // Get ea1 into instr
1471 D_word(inst); // Deposit instr
1473 // Generate ea0 if requested
1477 ea1gen(siz); // Generate ea1
1482 inst |= am0 | a0reg; // Get ea0 into instr
1483 D_word(inst); // Deposit instr
1484 ea0gen(siz); // Generate ea0
1486 // Generate ea1 if requested
1491 // If we're called from chk2 then bit 11 of size will be set. This is just
1492 // a dumb mechanism to pass this, required by the extension word. (You might
1493 // have noticed the siz & 15 thing above!)
1494 inst = (a1reg << 12) | (siz & (1 << 11));
1506 // chk2 (68020, 68030, 68040, CPU32)
1508 int m_chk2(WORD inst, WORD siz)
1510 return m_cmp2(inst, siz | (1 << 11));
1515 // cpbcc(68020, 68030)
1517 int m_cpbr(WORD inst, WORD siz)
1519 if ((activecpu & (CPU_68020 | CPU_68030)) == 0)
1520 return error(unsupport);
1522 if (a0exattr & DEFINED)
1524 if ((a0exattr & TDB) != cursect)
1525 return error(rel_error);
1527 uint32_t v = (uint32_t)a0exval - (sloc + 2);
1529 // Optimize branch instr. size
1532 if ((v != 0) && ((v + 0x8000) < 0x10000))
1542 if ((v + 0x8000) >= 0x10000)
1543 return error(range_error);
1551 else if (siz == SIZN)
1558 AddFixup(FU_LONG | FU_PCREL | FU_SEXT, sloc, a0expr);
1566 AddFixup(FU_WORD | FU_PCREL | FU_SEXT, sloc, a0expr);
1575 // cpdbcc(68020, 68030)
1577 int m_cpdbr(WORD inst, WORD siz)
1582 WORD condition = inst & 0x1F; // Grab condition sneakily placed in the lower 5 bits of inst
1583 inst &= 0xFFE0; // And then mask them out - you ain't seen me, roit?
1585 inst |= (1 << 9); // Bolt on FPU id
1592 if (a1exattr & DEFINED)
1594 if ((a1exattr & TDB) != cursect)
1595 return error(rel_error);
1597 v = (uint32_t)a1exval - sloc;
1599 if (v + 0x8000 > 0x10000)
1600 return error(range_error);
1606 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
1615 // muls.l / divs.l / divu.l / mulu.l (68020+)
1617 int m_muls(WORD inst, WORD siz)
1619 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1620 return error(unsupport);
1622 WORD flg = inst; // Save flag bits
1623 inst &= ~0x33F; // Clobber flag and extension bits in instr
1625 // Install "standard" instr size bits
1631 // OR-in register number
1633 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1635 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1638 // Regarding extension word: bit 11 is signed/unsigned selector
1639 // bit 10 is 32/64 bit selector
1640 // Both of these are packed in bits 9 and 8 of the instruction
1641 // field in 68ktab. Extra compilcations arise from the fact we
1642 // have to distinguish between divu/s.l Dn,Dm (which is encoded
1643 // as divu/s.l Dn,Dm:Dm) and divu/s.l Dn,Dm:Dx - the first is
1644 // 32 bit while the second 64 bit
1649 inst |= am1 | a1reg; // Get ea1 into instr
1650 D_word(inst); // Deposit instr
1654 inst = a1reg + (a2reg << 12) + ((flg & 0x200) << 2);
1656 inst = a1reg + (a2reg << 12) + ((flg & 0x300) << 2);
1660 // Generate ea0 if requested
1664 ea1gen(siz); // Generate ea1
1671 inst |= am0 | a0reg; // Get ea0 into instr
1672 D_word(inst); // Deposit instr
1676 inst = a1reg + (a2reg << 12) + ((flg & 0x200) << 2);
1678 inst = a1reg + (a2reg << 12) + ((flg & 0x300) << 2);
1682 ea0gen(siz); // Generate ea0
1684 // Generate ea1 if requested
1694 // move16 (ax)+,(ay)+
1696 int m_move16a(WORD inst, WORD siz)
1698 if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1699 return error(unsupport);
1703 inst = (1 << 15) + (a1reg << 12);
1711 // move16 with absolute address
1713 int m_move16b(WORD inst, WORD siz)
1715 if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1716 return error(unsupport);
1722 if (am0 == APOSTINC)
1725 return error("Wasn't this suppose to call m_move16a???");
1728 //move16 (ax)+,(xxx).L
1733 else if (am0 == ABSL)
1737 //move16 (xxx).L,(ax)+
1743 //move16 (xxx).L,(ax)
1748 else if (am0 == AIND)
1750 //move16 (ax),(xxx).L
1763 // pack/unpack (68020/68030/68040)
1765 int m_pack(WORD inst, WORD siz)
1770 return error("bad size suffix");
1772 if (*tok >= KW_D0 && *tok <= KW_D7)
1774 // Dx,Dy,#<adjustment>
1775 inst |= (0 << 3); // R/M
1776 inst |= (*tok++ & 7);
1778 if (*tok != ',' && tok[2] != ',')
1779 return error("missing comma");
1781 if (tok[1] < KW_D0 && tok[1] > KW_D7)
1782 return error(syntax_error);
1784 inst |= ((tok[1] & 7)<<9);
1787 // Fall through for adjustment (common in both valid cases)
1789 else if (*tok == '-')
1791 // -(Ax),-(Ay),#<adjustment>
1792 inst |= (1 << 3); // R/M
1793 tok++; // eat the minus
1795 if ((*tok != '(') && (tok[2]!=')') && (tok[3]!=',') && (tok[4] != '-') && (tok[5] != '(') && (tok[7] != ')') && (tok[8] != ','))
1796 return error(syntax_error);
1798 if (tok[1] < KW_A0 && tok[1] > KW_A7)
1799 return error(syntax_error);
1801 if (tok[5] < KW_A0 && tok[6] > KW_A7)
1802 return error(syntax_error);
1804 inst |= ((tok[1] & 7) << 0);
1805 inst |= ((tok[6] & 7) << 9);
1808 // Fall through for adjustment (common in both valid cases)
1811 return error("invalid syntax");
1813 if ((*tok != CONST) && (*tok != SYMBOL) && (*tok != '-'))
1814 return error(syntax_error);
1816 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
1819 if ((a0exattr & DEFINED) == 0)
1820 return error(undef_error);
1822 if (a0exval + 0x8000 > 0x10000)
1826 return error(extra_stuff);
1828 D_word((a0exval & 0xFFFF));
1837 int m_rtm(WORD inst, WORD siz)
1845 else if (am0 == AREG)
1847 inst |= (1 << 3) + a0reg;
1850 return error("rtm only allows data or address registers.");
1861 int m_rtd(WORD inst, WORD siz)
1865 if (a0exattr & DEFINED)
1868 return error(abs_error);
1870 if ((a0exval + 0x8000) <= 0x7FFF)
1871 return error(range_error);
1877 return error(undef_error);
1886 int m_trapcc(WORD inst, WORD siz)
1894 else if (am0 == IMMED)
1898 if (a0exval < 0x10000)
1905 return error("Immediate value too big");
1915 return error("Invalid parameter for trapcc");
1922 // cinvl/p/a (68040)
1924 int m_cinv(WORD inst, WORD siz)
1929 inst |= (0 << 6) | (a1reg);
1933 inst |= (2 << 6) | (a1reg);
1936 inst |= (1 << 6) | (a1reg);
1939 inst |= (3 << 6) | (a1reg);
1949 // cpRESTORE (68020, 68030)
1951 int m_cprest(WORD inst, WORD siz)
1953 if (activecpu & !(CPU_68020 | CPU_68030))
1954 return error(unsupport);
1956 inst |= am0 | a0reg;
1965 // movec (68010, 68020, 68030, 68040, CPU32)
1967 int m_movec(WORD inst, WORD siz)
1971 if (am0 == DREG || am0 == AREG)
1979 inst = (0 << 15) + (a0reg << 12) + CREGlut[a1reg];
1984 inst = (1 << 15) + (a0reg << 12) + CREGlut[a1reg];
1995 inst = (0 << 15) + (a1reg << 12) + CREGlut[a0reg];
2000 inst = (1 << 15) + (a1reg << 12) + CREGlut[a0reg];
2010 // moves (68010, 68020, 68030, 68040, CPU32)
2012 int m_moves(WORD inst, WORD siz)
2014 if (activecpu & !(CPU_68020 | CPU_68030 | CPU_68040))
2015 return error(unsupport);
2019 else if (siz == SIZL)
2026 inst |= am1 | a1reg;
2028 inst = (a0reg << 12) | (1 << 11) | (0 << 15);
2031 else if (am0 == AREG)
2033 inst |= am1 | a1reg;
2035 inst = (a0reg << 12) | (1 << 11) | (1 << 15);
2042 inst |= am0 | a0reg;
2044 inst = (a1reg << 12) | (0 << 11) | (0 << 15);
2049 inst |= am0 | a0reg;
2051 inst = (a1reg << 12) | (0 << 11) | (1 << 15);
2063 int m_pbcc(WORD inst, WORD siz)
2066 return error("Not implemented yet.");
2071 // pflusha (68030, 68040)
2073 int m_pflusha(WORD inst, WORD siz)
2075 if (activecpu == CPU_68030)
2078 inst = (1 << 13) | (1 << 10) | (0 << 5) | 0;
2082 else if (activecpu == CPU_68040)
2084 inst = B16(11110101, 00011000);
2089 return error(unsupport);
2096 // pflush (68030, 68040, 68060)
2098 int m_pflush(WORD inst, WORD siz)
2100 if (activecpu == CPU_68030)
2103 // PFLUSH FC, MASK, < ea >
2111 if (*tok != CONST && *tok != SYMBOL)
2112 return error("function code should be an expression");
2114 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2117 if ((a0exattr & DEFINED) == 0)
2118 return error("function code immediate should be defined");
2120 if (a0exval > 7 && a0exval < 0)
2121 return error("function code out of range (0-7)");
2123 fc = (uint16_t)a0exval;
2133 fc = (1 << 4) | (*tok++ & 7);
2144 return error(syntax_error);
2148 return error("comma exptected");
2151 return error("mask should be an immediate value");
2153 if (*tok != CONST && *tok != SYMBOL)
2154 return error("mask is supposed to be immediate");
2156 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2159 if ((a0exattr & DEFINED) == 0)
2160 return error("mask immediate value should be defined");
2162 if (a0exval > 7 && a0exval < 0)
2163 return error("function code out of range (0-7)");
2165 mask = (uint16_t)a0exval << 5;
2171 inst = (1 << 13) | fc | mask | (4 << 10);
2175 else if (*tok == ',')
2177 // PFLUSH FC, MASK, < ea >
2180 if (amode(0) == ERROR)
2184 return error(extra_stuff);
2186 if (am0 == AIND || am0 == ABSW || am0 == ABSL || am0 == ADISP || am0 == ADISP || am0 == AINDEXED || am0 == ABASE || am0 == MEMPOST || am0 == MEMPRE)
2188 inst |= am0 | a0reg;
2190 inst = (1 << 13) | fc | mask | (6 << 10);
2196 return error("unsupported addressing mode");
2200 return error(syntax_error);
2204 else if (activecpu == CPU_68040 || activecpu == CPU_68060)
2208 if (*tok != '(' && tok[2] != ')')
2209 return error(syntax_error);
2211 if (tok[1] < KW_A0 && tok[1] > KW_A7)
2212 return error("expected (An)");
2214 if ((inst & 7) == 7)
2215 // With pflushn/pflush there's no easy way to distinguish between
2216 // the two in 68040 mode. Ideally the opcode bitfields would have
2217 // been hardcoded in 68ktab but there is aliasing between 68030
2218 // and 68040 opcode. So we just set the 3 lower bits to 1 in
2219 // pflushn inside 68ktab and detect it here.
2220 inst = (inst & 0xff8) | 8;
2222 inst |= (tok[1] & 7) | (5 << 8);
2225 return error(extra_stuff);
2230 return error(unsupport);
2239 int m_pflushr(WORD inst, WORD siz)
2243 WORD flg = inst; // Save flag bits
2244 inst &= ~0x3F; // Clobber flag bits in instr
2246 // Install "standard" instr size bits
2252 // OR-in register number
2254 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
2256 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
2262 inst |= am1 | a1reg; // Get ea1 into instr
2263 D_word(inst); // Deposit instr
2265 // Generate ea0 if requested
2269 ea1gen(siz); // Generate ea1
2274 inst |= am0 | a0reg; // Get ea0 into instr
2275 D_word(inst); // Deposit instr
2276 ea0gen(siz); // Generate ea0
2278 // Generate ea1 if requested
2283 D_word(B16(10100000, 00000000));
2289 // ploadr, ploadw (68030)
2291 int m_pload(WORD inst, WORD siz, WORD extension)
2293 // TODO: 68851 support is not added yet.
2294 // None of the ST series of computers had a 68020 + 68851 socket and since
2295 // this is an Atari targetted assembler...
2304 if (a0reg == KW_SFC - KW_SFC)
2306 else if (a0reg == KW_DFC - KW_SFC)
2309 return error("illegal control register specified");
2313 inst = (1 << 3) | a0reg;
2316 if ((a0exattr & DEFINED) == 0)
2317 return error("constant value must be defined");
2319 inst = (2 << 3) | (uint16_t)a0exval;
2323 inst |= extension | (1 << 13);
2332 int m_ploadr(WORD inst, WORD siz)
2334 return m_pload(inst, siz, 1 << 9);
2338 int m_ploadw(WORD inst, WORD siz)
2340 return m_pload(inst, siz, 0 << 9);
2345 // pmove (68030/68851)
2347 int m_pmove(WORD inst, WORD siz)
2351 // TODO: 68851 support is not added yet. None of the ST series of
2352 // computers had a 68020 + 68851 socket and since this is an Atari
2353 // targetted assembler.... (same for 68EC030)
2356 inst2 = inst & (1 << 8); // Copy the flush bit over to inst2 in case we're called from m_pmovefd
2357 inst &= ~(1 << 8); // And mask it out
2364 else if (am1 == CREG)
2370 return error("pmove sez: Wut?");
2372 // The instruction is a quad-word (8 byte) operation
2373 // for the CPU root pointer and the supervisor root pointer.
2374 // It is a long - word operation for the translation control register
2375 // and the transparent translation registers(TT0 and TT1).
2376 // It is a word operation for the MMU status register.
2378 if (((reg == (KW_URP - KW_SFC)) || (reg == (KW_SRP - KW_SFC)))
2379 && ((siz != SIZD) && (siz != SIZN)))
2380 return error(siz_error);
2382 if (((reg == (KW_TC - KW_SFC)) || (reg == (KW_TT0 - KW_SFC)) || (reg == (KW_TT1 - KW_SFC)))
2383 && ((siz != SIZL) && (siz != SIZN)))
2384 return error(siz_error);
2386 if ((reg == (KW_MMUSR - KW_SFC)) && ((siz != SIZW) && (siz != SIZN)))
2387 return error(siz_error);
2391 inst |= am1 | a1reg;
2394 else if (am1 == CREG)
2396 inst |= am0 | a0reg;
2400 switch (reg + KW_SFC)
2403 inst2 |= (0 << 10) + (1 << 14); break;
2405 inst2 |= (2 << 10) + (1 << 14); break;
2407 inst2 |= (3 << 10) + (1 << 14); break;
2409 inst2 |= (2 << 10) + (0 << 13); break;
2411 inst2 |= (3 << 10) + (0 << 13); break;
2414 inst2 |= (1 << 9) + (3 << 13);
2416 inst2 |= (0 << 9) + (3 << 13);
2419 return error("unsupported register");
2427 else if (am1 == CREG)
2437 int m_pmovefd(WORD inst, WORD siz)
2441 return m_pmove(inst | (1 << 8), siz);
2448 int m_ptrapcc(WORD inst, WORD siz)
2451 // We stash the 5 condition bits inside the opcode in 68ktab (bits 0-4),
2452 // so we need to extract them first and fill in the clobbered bits.
2453 WORD opcode = inst & 0x1F;
2454 inst = (inst & 0xFFE0) | (0x18);
2463 else if (siz == SIZL)
2470 else if (siz == SIZN)
2482 // ptestr, ptestw (68030)
2484 int m_ptest(WORD inst, WORD siz)
2488 if (activecpu == CPU_68030)
2489 return error("Not implemented yet.");
2490 else if (activecpu == CPU_68040)
2491 return error("Not implemented yet.");
2497 #define FPU_NOWARN 0
2498 #define FPU_P_EMUL 1
2499 #define FPU_P2_EMU 2
2504 // Generate a FPU opcode
2506 static inline int gen_fpu(WORD inst, WORD siz, WORD opmode, WORD emul)
2508 if (am0 < AM_NONE) // Check first operand for ea or fp - is this right?
2510 inst |= (1 << 9); // Bolt on FPU id
2517 inst = 1 << 14; // R/M field (we have ea so have to set this to 1)
2521 case SIZB: inst |= (6 << 10); break;
2522 case SIZW: inst |= (4 << 10); break;
2523 case SIZL: inst |= (0 << 10); break;
2525 case SIZS: inst |= (1 << 10); break;
2526 case SIZD: inst |= (5 << 10); break;
2527 case SIZX: inst |= (2 << 10); break;
2532 warn("This encoding will cause an unimplemented data type exception in the MC68040 to allow emulation in software.");
2536 return error("Something bad happened, possibly, in gen_fpu.");
2540 inst |= (a1reg << 7);
2547 inst |= (1 << 9); // Bolt on FPU id
2551 inst |= (a1reg << 7);
2556 if ((emul & FPU_FPSP) && (activefpu == FPU_68040))
2557 warn("Instruction is emulated in 68040");
2564 // fabs, fsabs, fdabs (6888X, 68040)
2566 int m_fabs(WORD inst, WORD siz)
2568 return gen_fpu(inst, siz, B8(00011000), FPU_P_EMUL);
2572 int m_fsabs(WORD inst, WORD siz)
2574 if (activefpu == FPU_68040)
2575 return gen_fpu(inst, siz, B8(01011000), FPU_P_EMUL);
2577 return error("Unsupported in current FPU");
2581 int m_fdabs(WORD inst, WORD siz)
2583 if (activefpu == FPU_68040)
2584 return gen_fpu(inst, siz, B8(01011100), FPU_P_EMUL);
2586 return error("Unsupported in current FPU");
2591 // facos (6888X, 68040FPSP)
2593 int m_facos(WORD inst, WORD siz)
2595 return gen_fpu(inst, siz, B8(00011100), FPU_FPSP);
2600 // fadd (6888X, 68040FPSP)
2602 int m_fadd(WORD inst, WORD siz)
2604 return gen_fpu(inst, siz, B8(00100010), FPU_P_EMUL);
2608 int m_fsadd(WORD inst, WORD siz)
2610 if (activefpu == FPU_68040)
2611 return gen_fpu(inst, siz, B8(01100010), FPU_P_EMUL);
2613 return error("Unsupported in current FPU");
2617 int m_fdadd(WORD inst, WORD siz)
2619 if (activefpu == FPU_68040)
2620 return gen_fpu(inst, siz, B8(01100110), FPU_P_EMUL);
2622 return error("Unsupported in current FPU");
2627 // fasin (6888X, 68040FPSP)f
2629 int m_fasin(WORD inst, WORD siz)
2631 return gen_fpu(inst, siz, B8(00001100), FPU_FPSP);
2636 // fatan (6888X, 68040FPSP)
2638 int m_fatan(WORD inst, WORD siz)
2640 return gen_fpu(inst, siz, B8(00001010), FPU_FPSP);
2645 // fatanh (6888X, 68040FPSP)
2647 int m_fatanh(WORD inst, WORD siz)
2649 return gen_fpu(inst, siz, B8(00001101), FPU_FPSP);
2654 // fcmp (6888X, 68040)
2656 int m_fcmp(WORD inst, WORD siz)
2658 return gen_fpu(inst, siz, B8(00111000), FPU_P_EMUL);
2663 // fcos (6888X, 68040FPSP)
2665 int m_fcos(WORD inst, WORD siz)
2667 return gen_fpu(inst, siz, B8(00011101), FPU_FPSP);
2672 // fcosh (6888X, 68040FPSP)
2674 int m_fcosh(WORD inst, WORD siz)
2676 return gen_fpu(inst, siz, B8(00011001), FPU_FPSP);
2681 // fdbcc (6888X, 68040)
2683 int m_fdbcc(WORD inst, WORD siz)
2685 WORD opcode = inst & 0x3F; // Grab conditional bitfield
2695 if (a1exattr & DEFINED)
2697 if ((a1exattr & TDB) != cursect)
2698 return error(rel_error);
2700 uint32_t v = (uint32_t)a1exval - sloc;
2702 if ((v + 0x8000) > 0x10000)
2703 return error(range_error);
2709 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
2718 // fdiv (6888X, 68040)
2720 int m_fdiv(WORD inst, WORD siz)
2722 return gen_fpu(inst, siz, B8(00100000), FPU_P_EMUL);
2726 int m_fsdiv(WORD inst, WORD siz)
2728 if (activefpu == FPU_68040)
2729 return gen_fpu(inst, siz, B8(01100000), FPU_P_EMUL);
2731 return error("Unsupported in current FPU");
2735 int m_fddiv(WORD inst, WORD siz)
2737 if (activefpu == FPU_68040)
2738 return gen_fpu(inst, siz, B8(01100100), FPU_P_EMUL);
2740 return error("Unsupported in current FPU");
2745 // fetox (6888X, 68040FPSP)
2747 int m_fetox(WORD inst, WORD siz)
2749 return gen_fpu(inst, siz, B8(00010000), FPU_FPSP);
2754 // fetoxm1 (6888X, 68040FPSP)
2756 int m_fetoxm1(WORD inst, WORD siz)
2758 return gen_fpu(inst, siz, B8(00001000), FPU_FPSP);
2763 // fgetexp (6888X, 68040FPSP)
2765 int m_fgetexp(WORD inst, WORD siz)
2767 return gen_fpu(inst, siz, B8(00011110), FPU_FPSP);
2772 // fgetman (6888X, 68040FPSP)
2774 int m_fgetman(WORD inst, WORD siz)
2776 return gen_fpu(inst, siz, B8(00011111), FPU_FPSP);
2781 // fint (6888X, 68040FPSP)
2783 int m_fint(WORD inst, WORD siz)
2786 // special case - fint fpx = fint fpx,fpx
2789 return gen_fpu(inst, siz, B8(00000001), FPU_FPSP);
2794 // fintrz (6888X, 68040FPSP)
2796 int m_fintrz(WORD inst, WORD siz)
2799 // special case - fintrz fpx = fintrz fpx,fpx
2802 return gen_fpu(inst, siz, B8(00000011), FPU_FPSP);
2807 // flog10 (6888X, 68040FPSP)
2809 int m_flog10(WORD inst, WORD siz)
2811 return gen_fpu(inst, siz, B8(00010101), FPU_FPSP);
2816 // flog2 (6888X, 68040FPSP)
2818 int m_flog2(WORD inst, WORD siz)
2820 return gen_fpu(inst, siz, B8(00010110), FPU_FPSP);
2825 // flogn (6888X, 68040FPSP)
2827 int m_flogn(WORD inst, WORD siz)
2829 return gen_fpu(inst, siz, B8(00010100), FPU_FPSP);
2834 // flognp1 (6888X, 68040FPSP)
2836 int m_flognp1(WORD inst, WORD siz)
2838 return gen_fpu(inst, siz, B8(00000110), FPU_FPSP);
2843 // fmod (6888X, 68040FPSP)
2845 int m_fmod(WORD inst, WORD siz)
2847 return gen_fpu(inst, siz, B8(00100001), FPU_FPSP);
2852 // fmove (6888X, 68040)
2854 int m_fmove(WORD inst, WORD siz)
2857 if ((am0 == FREG) && (am1 < AM_USP))
2861 inst |= am1 | a1reg;
2870 case SIZB: inst |= (6 << 10); break;
2871 case SIZW: inst |= (4 << 10); break;
2872 case SIZL: inst |= (0 << 10); break;
2874 case SIZS: inst |= (1 << 10); break;
2875 case SIZD: inst |= (5 << 10); break;
2876 case SIZX: inst |= (2 << 10); break;
2877 case SIZP: inst |= (3 << 10);
2878 // In P size we have 2 cases: {#k} where k is immediate
2879 // and {Dn} where Dn=Data register
2884 inst |= bfval1 << 4;
2889 if (bfval1 > 63 && bfval1 < -64)
2890 return error("K-factor must be between -64 and 63");
2892 inst |= bfval1 & 127;
2897 return error("Something bad happened, possibly.");
2901 // Destination specifier
2902 inst |= (a0reg << 7);
2910 else if ((am0 < AM_USP) && (am1 == FREG))
2915 inst |= am0 | a0reg;
2924 case SIZB: inst |= (6 << 10); break;
2925 case SIZW: inst |= (4 << 10); break;
2926 case SIZL: inst |= (0 << 10); break;
2928 case SIZS: inst |= (1 << 10); break;
2929 case SIZD: inst |= (5 << 10); break;
2930 case SIZX: inst |= (2 << 10); break;
2931 case SIZP: inst |= (3 << 10); break;
2933 return error("Something bad happened, possibly.");
2937 // Destination specifier
2938 inst |= (a1reg << 7);
2946 else if ((am0 == FREG) && (am1 == FREG))
2948 // register-to-register
2949 // Essentially ea to register with R/0=0
2959 return error("Invalid size");
2962 inst |= (a0reg << 10);
2964 // Destination register
2965 inst |= (a1reg << 7);
2975 // fmove (6888X, 68040)
2977 int m_fmovescr(WORD inst, WORD siz)
2979 // Move Floating-Point System Control Register (FPCR)
2983 if ((am0 == FPSCR) && (am1 < AM_USP))
2985 inst |= am1 | a1reg;
2987 inst = (1 << 13) + (1 << 15);
2993 else if ((am1 == FPSCR) && (am0 < AM_USP))
2995 inst |= am0 | a0reg;
2997 inst = (0 << 13) + (1 << 15);
3004 return error("m_fmovescr says: wut?");
3008 // fsmove/fdmove (68040)
3010 int m_fsmove(WORD inst, WORD siz)
3012 return error("Not implemented yet.");
3015 if (activefpu == FPU_68040)
3016 return gen_fpu(inst, siz, B8(01100100), FPU_P_EMUL);
3018 return error("Unsupported in current FPU");
3023 int m_fdmove(WORD inst, WORD siz)
3025 return error("Not implemented yet.");
3028 if (activefpu == FPU_68040)
3029 return gen_fpu(inst, siz, B8(01100100), FPU_P_EMUL);
3031 return error("Unsupported in current FPU");
3037 // fmovecr (6888X, 68040FPSP)
3039 int m_fmovecr(WORD inst, WORD siz)
3047 if (activefpu == FPU_68040)
3048 warn("Instruction is emulated in 68040");
3055 // fmovem (6888X, 68040)
3057 int m_fmovem(WORD inst, WORD siz)
3062 if (siz == SIZX || siz == SIZN)
3064 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
3066 //fmovem.x <rlist>,ea
3067 if (fpu_reglist_left(®mask) < 0)
3071 return error("missing comma");
3076 inst |= am0 | a0reg;
3078 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3079 return error("invalid addressing mode");
3082 inst = (1 << 15) | (1 << 14) | (1 << 13) | (0 << 11) | regmask;
3087 else if ((*tok >= KW_D0) && (*tok <= KW_D7))
3090 datareg = (*tok++ & 7) << 10;
3093 return error("missing comma");
3098 inst |= am0 | a0reg;
3100 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3101 return error("invalid addressing mode");
3104 inst = (1 << 15) | (1 << 14) | (1 << 13) | (1 << 11) | (datareg << 4);
3115 inst |= am0 | a0reg;
3118 return error("missing comma");
3120 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
3122 //fmovem.x ea,<rlist>
3123 if (fpu_reglist_right(®mask) < 0)
3127 inst = (1 << 15) | (1 << 14) | (0 << 13) | (2 << 11) | regmask;
3135 datareg = (*tok++ & 7) << 10;
3137 inst = (1 << 15) | (1 << 14) | (0 << 13) | (3 << 11) | (datareg << 4);
3144 else if (siz == SIZL)
3146 if ((*tok == KW_FPCR) || (*tok == KW_FPSR) || (*tok == KW_FPIAR))
3148 //fmovem.l <rlist>,ea
3149 regmask = (1 << 15) | (1 << 13);
3151 if (*tok == KW_FPCR)
3153 regmask |= (1 << 12);
3158 if (*tok == KW_FPSR)
3160 regmask |= (1 << 11);
3165 if (*tok == KW_FPIAR)
3167 regmask |= (1 << 10);
3172 if ((*tok == '/') || (*tok == '-'))
3179 return error("missing comma");
3184 inst |= am0 | a0reg;
3191 //fmovem.l ea,<rlist>
3195 inst |= am0 | a0reg;
3198 return error("missing comma");
3200 regmask = (1 << 15) | (0 << 13);
3203 if (*tok == KW_FPCR)
3205 regmask |= (1 << 12);
3210 if (*tok == KW_FPSR)
3212 regmask |= (1 << 11);
3217 if (*tok == KW_FPIAR)
3219 regmask |= (1 << 10);
3224 if ((*tok == '/') || (*tok == '-'))
3231 return error("extra (unexpected) text found");
3233 inst |= am0 | a0reg;
3240 return error("bad size suffix");
3247 // fmul (6888X, 68040)
3249 int m_fmul(WORD inst, WORD siz)
3251 return gen_fpu(inst, siz, B8(00100011), FPU_P_EMUL);
3255 int m_fsmul(WORD inst, WORD siz)
3257 if (activefpu == FPU_68040)
3258 return gen_fpu(inst, siz, B8(01100011), FPU_P_EMUL);
3260 return error("Unsupported in current FPU");
3264 int m_fdmul(WORD inst, WORD siz)
3266 if (activefpu == FPU_68040)
3267 return gen_fpu(inst, siz, B8(01100111), FPU_P_EMUL);
3269 return error("Unsupported in current FPU");
3274 // fneg (6888X, 68040)
3276 int m_fneg(WORD inst, WORD siz)
3278 return gen_fpu(inst, siz, B8(00011010), FPU_P_EMUL);
3282 int m_fsneg(WORD inst, WORD siz)
3284 if (activefpu == FPU_68040)
3285 return gen_fpu(inst, siz, B8(01011010), FPU_P_EMUL);
3287 return error("Unsupported in current FPU");
3291 int m_fdneg(WORD inst, WORD siz)
3293 if (activefpu == FPU_68040)
3294 return gen_fpu(inst, siz, B8(01011110), FPU_P_EMUL);
3296 return error("Unsupported in current FPU");
3301 // fnop (6888X, 68040)
3303 int m_fnop(WORD inst, WORD siz)
3305 return gen_fpu(inst, siz, B8(00000000), FPU_P_EMUL);
3310 // frem (6888X, 68040FPSP)
3312 int m_frem(WORD inst, WORD siz)
3314 return gen_fpu(inst, siz, B8(00100101), FPU_FPSP);
3319 // fscale (6888X, 68040FPSP)
3321 int m_fscale(WORD inst, WORD siz)
3323 return gen_fpu(inst, siz, B8(00100110), FPU_FPSP);
3328 // FScc (6888X, 68040), cpScc (68851, 68030), PScc (68851)
3329 // TODO: Add check for PScc to ensure 68020+68851 active
3330 // TODO: Add check for cpScc to ensure 68020+68851, 68030
3332 int m_fscc(WORD inst, WORD siz)
3334 // We stash the 5 condition bits inside the opcode in 68ktab (bits 4-0),
3335 // so we need to extract them first and fill in the clobbered bits.
3336 WORD opcode = inst & 0x1F;
3338 inst |= am0 | a0reg;
3347 // FTRAPcc (6888X, 68040)
3349 int m_ftrapcc(WORD inst, WORD siz)
3351 // We stash the 5 condition bits inside the opcode in 68ktab (bits 3-7),
3352 // so we need to extract them first and fill in the clobbered bits.
3353 WORD opcode = (inst >> 3) & 0x1F;
3354 inst = (inst & 0xFF07) | (0xF << 3);
3363 else if (siz == SIZL)
3370 else if (siz = SIZN)
3383 // fsgldiv (6888X, 68040)
3385 int m_fsgldiv(WORD inst, WORD siz)
3387 return gen_fpu(inst, siz, B8(00100100), FPU_P_EMUL);
3392 // fsglmul (6888X, 68040)
3394 int m_fsglmul(WORD inst, WORD siz)
3396 return gen_fpu(inst, siz, B8(00100111), FPU_P_EMUL);
3401 // fsin (6888X, 68040FPSP)
3403 int m_fsin(WORD inst, WORD siz)
3405 return gen_fpu(inst, siz, B8(00001110), FPU_FPSP);
3410 // fsincos (6888X, 68040FPSP)
3412 int m_fsincos(WORD inst, WORD siz)
3414 // Swap a1reg, a2reg as a2reg should be stored in the bitfield gen_fpu
3421 if (gen_fpu(inst, siz, B8(00110000), FPU_FPSP) == OK)
3432 // fsin (6888X, 68040FPSP)
3434 int m_fsinh(WORD inst, WORD siz)
3436 return gen_fpu(inst, siz, B8(00000010), FPU_FPSP);
3441 // fsqrt (6888X, 68040)
3443 int m_fsqrt(WORD inst, WORD siz)
3445 return gen_fpu(inst, siz, B8(00000100), FPU_P_EMUL);
3449 int m_fsfsqrt(WORD inst, WORD siz)
3451 if (activefpu == FPU_68040)
3452 return gen_fpu(inst, siz, B8(01000001), FPU_P_EMUL);
3454 return error("Unsupported in current FPU");
3458 int m_fdfsqrt(WORD inst, WORD siz)
3460 if (activefpu == FPU_68040)
3461 return gen_fpu(inst, siz, B8(01000101), FPU_P_EMUL);
3463 return error("Unsupported in current FPU");
3468 // fsub (6888X, 68040)
3470 int m_fsub(WORD inst, WORD siz)
3472 return gen_fpu(inst, siz, B8(00101000), FPU_P_EMUL);
3476 int m_fsfsub(WORD inst, WORD siz)
3478 if (activefpu == FPU_68040)
3479 return gen_fpu(inst, siz, B8(01101000), FPU_P_EMUL);
3481 return error("Unsupported in current FPU");
3485 int m_fdsub(WORD inst, WORD siz)
3487 if (activefpu == FPU_68040)
3488 return gen_fpu(inst, siz, B8(01101100), FPU_P_EMUL);
3490 return error("Unsupported in current FPU");
3495 // ftan (6888X, 68040FPSP)
3497 int m_ftan(WORD inst, WORD siz)
3499 return gen_fpu(inst, siz, B8(00001111), FPU_FPSP);
3504 // ftanh (6888X, 68040FPSP)
3506 int m_ftanh(WORD inst, WORD siz)
3508 return gen_fpu(inst, siz, B8(00001001), FPU_FPSP);
3513 // ftentox (6888X, 68040FPSP)
3515 int m_ftentox(WORD inst, WORD siz)
3517 return gen_fpu(inst, siz, B8(00010010), FPU_FPSP);
3522 // ftst (6888X, 68040)
3524 int m_ftst(WORD inst, WORD siz)
3526 return gen_fpu(inst, siz, B8(00111010), FPU_P_EMUL);
3531 // ftwotox (6888X, 68040FPSP)
3533 int m_ftwotox(WORD inst, WORD siz)
3535 return gen_fpu(inst, siz, B8(00010001), FPU_FPSP);