2 // RMAC - Reboot's Macro Assembler for all Atari computers
3 // MACH.C - Code Generation
4 // Copyright (C) 199x Landon Dyer, 2011-2020 Reboot and Friends
5 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
6 // Source utilised with the kind permission of Landon Dyer
24 int movep = 0; // Global flag to indicate we're generating a movep instruction
26 // Function prototypes
27 int m_unimp(WORD, WORD), m_badmode(WORD, WORD);
28 int m_self(WORD, WORD);
29 int m_abcd(WORD, WORD);
30 int m_reg(WORD, WORD);
31 int m_imm(WORD, WORD);
32 int m_imm8(WORD, WORD);
33 int m_shi(WORD, WORD);
34 int m_shr(WORD, WORD);
35 int m_bitop(WORD, WORD);
36 int m_exg(WORD, WORD);
38 int m_lea(WORD, WORD);
40 int m_dbra(WORD, WORD);
41 int m_link(WORD, WORD);
42 int m_adda(WORD, WORD);
43 int m_addq(WORD, WORD);
44 int m_move(WORD, WORD);
45 int m_moveq(WORD, WORD);
46 int m_usp(WORD, WORD);
47 int m_movep(WORD, WORD);
48 int m_trap(WORD, WORD);
49 int m_movem(WORD, WORD);
50 int m_clra(WORD, WORD);
51 int m_clrd(WORD, WORD);
53 int m_move30(WORD, WORD); // 68020/30/40/60
54 int m_br30(WORD inst, WORD siz);
55 int m_ea030(WORD inst, WORD siz);
56 int m_bfop(WORD inst, WORD siz);
57 int m_callm(WORD inst, WORD siz);
58 int m_cas(WORD inst, WORD siz);
59 int m_cas2(WORD inst, WORD siz);
60 int m_chk2(WORD inst, WORD siz);
61 int m_cmp2(WORD inst, WORD siz);
62 int m_bkpt(WORD inst, WORD siz);
63 int m_cpbcc(WORD inst, WORD siz);
64 int m_cpdbr(WORD inst, WORD siz);
65 int m_muls(WORD inst, WORD siz);
66 int m_move16a(WORD inst, WORD siz);
67 int m_move16b(WORD inst, WORD siz);
68 int m_pack(WORD inst, WORD siz);
69 int m_rtm(WORD inst, WORD siz);
70 int m_rtd(WORD inst, WORD siz);
71 int m_trapcc(WORD inst, WORD siz);
72 int m_cinv(WORD inst, WORD siz);
73 int m_cprest(WORD inst, WORD siz);
74 int m_movec(WORD inst, WORD siz);
75 int m_moves(WORD inst, WORD siz);
76 int m_lpstop(WORD inst, WORD siz);
77 int m_plpa(WORD inst, WORD siz);
80 int m_pbcc(WORD inst, WORD siz);
81 int m_pflusha(WORD inst, WORD siz);
82 int m_pflush(WORD inst, WORD siz);
83 int m_pflushr(WORD inst, WORD siz);
84 int m_pflushan(WORD inst, WORD siz);
85 int m_pload(WORD inst, WORD siz, WORD extension);
86 int m_pmove(WORD inst, WORD siz);
87 int m_pmovefd(WORD inst, WORD siz);
88 int m_ptest(WORD inst, WORD siz, WORD extension);
89 int m_ptestr(WORD inste, WORD siz);
90 int m_ptestw(WORD inste, WORD siz);
91 int m_ptrapcc(WORD inst, WORD siz);
92 int m_ploadr(WORD inst, WORD siz);
93 int m_ploadw(WORD inst, WORD siz);
96 int m_fabs(WORD inst, WORD siz);
97 int m_fbcc(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_frestore(WORD inst, WORD siz);
136 int m_fsabs(WORD inst, WORD siz);
137 int m_fsadd(WORD inst, WORD siz);
138 int m_fscc(WORD inst, WORD siz);
139 int m_fscale(WORD inst, WORD siz);
140 int m_fsdiv(WORD inst, WORD siz);
141 int m_fsfsqrt(WORD inst, WORD siz);
142 int m_fsfsub(WORD inst, WORD siz);
143 int m_fsgldiv(WORD inst, WORD siz);
144 int m_fsglmul(WORD inst, WORD siz);
145 int m_fsin(WORD inst, WORD siz);
146 int m_fsincos(WORD inst, WORD siz);
147 int m_fsinh(WORD inst, WORD siz);
148 int m_fsmove(WORD inst, WORD siz);
149 int m_fsmul(WORD inst, WORD siz);
150 int m_fsneg(WORD inst, WORD siz);
151 int m_fsqrt(WORD inst, WORD siz);
152 int m_fsub(WORD inst, WORD siz);
153 int m_ftan(WORD inst, WORD siz);
154 int m_ftanh(WORD inst, WORD siz);
155 int m_ftentox(WORD inst, WORD siz);
156 int m_ftst(WORD inst, WORD siz);
157 int m_ftwotox(WORD inst, WORD siz);
158 int m_ftrapcc(WORD inst, WORD siz);
160 // Common error messages
161 char range_error[] = "expression out of range";
162 char abs_error[] = "illegal absolute expression";
163 char seg_error[] = "bad (section) expression";
164 char rel_error[] = "illegal relative address";
165 char siz_error[] = "bad size specified";
166 char undef_error[] = "undefined expression";
167 char fwd_error[] = "forward or undefined expression";
168 char unsupport[] = "unsupported for selected CPU";
170 // Include code tables
172 { 0xFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000, 0, m_badmode }, // 0
174 { 0, 0L, 0L, 0x0000, 0, m_unimp } // Last entry
177 // Register number << 9
179 0, 1 << 9, 2 << 9, 3 << 9, 4 << 9, 5 << 9, 6 << 9, 7 << 9
182 // SIZB==>00, SIZW==>01, SIZL==>10, SIZN==>01 << 6
186 1<<6, (WORD)-1, // SIZW, n/a
187 2<<6, (WORD)-1, (WORD)-1, (WORD)-1, // SIZL, n/a, n/a, n/a
191 // Byte/word/long size for MOVE instrs
195 0x3000, (WORD)-1, // Word
196 0x2000, (WORD)-1, (WORD)-1, (WORD)-1, // Long
197 0x3000 // Word (SIZN)
200 // Word/long size (0=.w, 1=.l) in bit 8
204 0, (WORD)-1, // SIZW, n/a
205 1<<8, (WORD)-1, (WORD)-1, (WORD)-1, // SIZL, n/a, n/a, n/a
209 // Byte/Word/long size (0=.w, 1=.l) in bit 9
213 1<<9, (WORD)-1, // Word
214 1<<10, (WORD)-1, (WORD)-1, (WORD)-1, // Long
218 // Addressing mode in bits 6..11 (register/mode fields are reversed)
220 00000, 01000, 02000, 03000, 04000, 05000, 06000, 07000,
221 00100, 01100, 02100, 03100, 04100, 05100, 06100, 07100,
222 00200, 01200, 02200, 03200, 04200, 05200, 06200, 07200,
223 00300, 01300, 02300, 03300, 04300, 05300, 06300, 07300,
224 00400, 01400, 02400, 03400, 04400, 05400, 06400, 07400,
225 00500, 01500, 02500, 03500, 04500, 05500, 06500, 07500,
226 00600, 01600, 02600, 03600, 04600, 05600, 06600, 07600,
227 00700, 01700, 02700, 03700, 04700, 05700, 06700, 07700
230 // Control registers lookup table
232 // MC68010/MC68020/MC68030/MC68040/CPU32
233 0x000, // Source Function Code(SFC)
234 0x001, // Destination Function Code(DFC)
235 0x800, // User Stack Pointer(USP)
236 0x801, // Vector Base Register(VBR)
237 // MC68020 / MC68030 / MC68040
238 0x002, // Cache Control Register(CACR)
239 0x802, // Cache Address Register(CAAR) (020/030 only)
240 0x803, // Master Stack Pointer(MSP)
241 0x804, // Interrupt Stack Pointer(ISP)
242 // MC68040 / MC68LC040
243 0x003, // MMU Translation Control Register(TC)
244 0x004, // Instruction Transparent Translation Register 0 (ITT0)
245 0x005, // Instruction Transparent Translation Register 1 (ITT1)
246 0x006, // Data Transparent Translation Register 0 (DTT0)
247 0x007, // Data Transparent Translation Register 1 (DTT1)
248 0x805, // MMU Status Register(MMUSR)
249 0x806, // User Root Pointer(URP)
250 0x807, // Supervisor Root Pointer(SRP)
252 0x004, // Instruction Access Control Register 0 (IACR0)
253 0x005, // Instruction Access Control Register 1 (IACR1)
254 0x006, // Data Access Control Register 0 (DACR1)
255 0x007, // Data Access Control Register 1 (DACR1)
257 0xFFF // CPU Root Pointer (CRP) - There's no movec with CRP in it, this is just a guard entry
262 int m_unimp(WORD unused1, WORD unused2)
264 return (int)error("unimplemented mnemonic");
268 //int m_badmode(void)
269 int m_badmode(WORD unused1, WORD unused2)
271 return (int)error("inappropriate addressing mode");
275 int m_self(WORD inst, WORD usused)
283 // Do one EA in bits 0..5
285 // Bits in `inst' have the following meaning:
287 // Bit zero specifies which ea (ea0 or ea1) to generate in the lower six bits
290 // If bit one is set, the OTHER ea (the one that wasn't generated by bit zero)
291 // is generated after the instruction. Regardless of bit 0's value, ea0 is
292 // always deposited in memory before ea1.
294 // If bit two is set, standard size bits are set in the instr in bits 6 and 7.
296 // If bit four is set, bit three specifies which eaXreg to place in bits 9..11
299 int m_ea(WORD inst, WORD siz)
301 WORD flg = inst; // Save flag bits
302 inst &= ~0x3F; // Clobber flag bits in instr
304 // Install "standard" instr size bits
310 // OR-in register number
312 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
314 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
320 inst |= am1 | a1reg; // Get ea1 into instr
321 D_word(inst); // Deposit instr
323 // Generate ea0 if requested
327 ea1gen(siz); // Generate ea1
332 inst |= am0 | a0reg; // Get ea0 into instr
333 D_word(inst); // Deposit instr
334 ea0gen(siz); // Generate ea0
336 // Generate ea1 if requested
346 // Check if lea x(an),an can be optimised to addq.w #x,an--otherwise fall back
349 int m_lea(WORD inst, WORD siz)
351 if (CHECK_OPTS(OPT_LEA_ADDQ)
352 && ((am0 == ADISP) && (a0reg == a1reg) && (a0exattr & DEFINED))
353 && ((a0exval > 0) && (a0exval <= 8)))
355 inst = B16(01010000, 01001000) | (((uint16_t)a0exval & 7) << 9) | (a0reg);
357 warn("lea size(An),An converted to addq #size,An");
361 return m_ea(inst, siz);
365 int m_ea030(WORD inst, WORD siz)
368 WORD flg = inst; // Save flag bits
369 inst &= ~0x3F; // Clobber flag bits in instr
371 // Install "standard" instr size bits
377 // OR-in register number
380 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
384 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
391 inst |= am1 | a1reg; // Get ea1 into instr
392 D_word(inst); // Deposit instr
394 // Generate ea0 if requested
398 ea1gen(siz); // Generate ea1
404 // We get here if we're doing 020+ addressing and an address
405 // register is used. For example, something like "tst a0". A bit of
406 // a corner case, so kludge it
408 else if (am0 == PCDISP)
409 // Another corner case (possibly!), so kludge ahoy
410 inst |= am0; // Get ea0 into instr
411 else if (am0 == IMMED && am1 == MEMPOST)
413 // Added for addi/andi/cmpi/eori/ori/subi #xx,(bd,An,Dm)
414 inst |= a1reg | AINDEXED;
416 else if (am0 == IMMED)
417 inst |= am0 | a0reg; // Get ea0 into instr
418 else if (am0 == AM_CCR)
420 else if (am0 == AIND)
423 inst |= a0reg; // Get ea0 into instr
424 D_word(inst); // Deposit instr
425 ea0gen(siz); // Generate ea0
427 // Generate ea1 if requested
437 // Dx,Dy nnnnXXXnssnnnYYY If bit 0 of `inst' is set, install size bits in bits
440 int m_abcd(WORD inst, WORD siz)
449 inst |= a0reg | reg_9[a1reg];
459 int m_adda(WORD inst, WORD siz)
461 if (a0exattr & DEFINED)
463 if (CHECK_OPTS(OPT_ADDA_ADDQ))
464 if (a0exval > 1 && a0exval <= 8)
465 // Immediate is between 1 and 8 so let's convert to addq
466 return m_addq(B16(01010000, 00000000), siz);
467 if (CHECK_OPTS(OPT_ADDA_LEA))
468 if (a0exval > 8 && (a0exval+0x8000)<0x10000)
470 // Immediate is larger than 8 and word size so let's convert to lea
471 am0 = ADISP; // Change addressing mode
472 a0reg = a1reg; // In ADISP a0reg is used instead of a1reg!
473 if (!(inst & (1 << 14)))
475 // We have a suba #x,AREG so let's negate the value
478 return m_lea(B16(01000001, 11011000), SIZW);
482 inst |= am0 | a0reg | lwsiz_8[siz] | reg_9[a1reg];
484 ea0gen(siz); // Generate EA
491 // If bit 0 of `inst' is 1, install size bits in bits 6..7 of instr.
492 // If bit 1 of `inst' is 1, install a1reg in bits 9..11 of instr.
494 int m_reg(WORD inst, WORD siz)
501 // Install other register (9..11)
502 inst |= reg_9[a1reg];
504 inst &= ~7; // Clear off crufty bits
505 inst |= a0reg; // Install first register
515 int m_imm(WORD inst, WORD siz)
527 int m_imm8(WORD inst, WORD siz)
540 int m_shr(WORD inst, WORD siz)
542 inst |= reg_9[a0reg] | a1reg | siz_6[siz];
552 int m_shi(WORD inst, WORD siz)
554 inst |= a1reg | siz_6[siz];
556 if (a0exattr & DEFINED)
559 return error(range_error);
561 inst |= (a0exval & 7) << 9;
566 AddFixup(FU_QUICK, sloc, a0expr);
575 // {bset, btst, bchg, bclr} -- #immed,ea -- Dn,ea
577 int m_bitop(WORD inst, WORD siz)
579 // Enforce instruction sizes
581 { // X,Dn must be .n or .l
582 if (siz & (SIZB | SIZW))
583 return error(siz_error);
585 else if (siz & (SIZW | SIZL)) // X,ea must be .n or .b
586 return error(siz_error);
588 // Construct instr and EAs
594 ea0gen(SIZB); // Immediate bit number
598 inst |= reg_9[a0reg];
609 int m_dbra(WORD inst, WORD siz)
615 if (a1exattr & DEFINED)
617 if ((a1exattr & TDB) != cursect)
618 return error(rel_error);
620 uint32_t v = (uint32_t)a1exval - sloc;
622 if (v + 0x8000 > 0x10000)
623 return error(range_error);
629 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
640 int m_exg(WORD inst, WORD siz)
646 if (am0 == DREG && am1 == DREG)
648 else if (am0 == AREG && am1 == AREG)
654 m = a1reg; // Get AREG into a1reg
662 inst |= m | reg_9[a0reg] | a1reg;
672 int m_link(WORD inst, WORD siz)
676 // Is this an error condition???
681 inst &= ~((3 << 9) | (1 << 6) | (1 << 4));
693 WORD extra_addressing[16]=
695 0x30, // 0100 (bd,An,Xn)
696 0x30, // 0101 ([bd,An],Xn,od)
697 0x30, // 0102 ([bc,An,Xn],od)
698 0x30, // 0103 (bd,PC,Xn)
699 0x30, // 0104 ([bd,PC],Xn,od)
700 0x30, // 0105 ([bc,PC,Xn],od)
715 // Handle MOVE <C_ALL> <C_ALTDATA>
716 // MOVE <C_ALL> <M_AREG>
718 // Optimize MOVE.L #<smalldata>,D0 to a MOVEQ
720 int m_move(WORD inst, WORD size)
722 // Cast the passed in value to an int
725 // Try to optimize to MOVEQ
726 // N.B.: We can get away with casting the uint64_t to a 32-bit value
727 // because it checks for a SIZL (i.e., a 32-bit value).
728 if (CHECK_OPTS(OPT_MOVEL_MOVEQ)
729 && (siz == SIZL) && (am0 == IMMED) && (am1 == DREG)
730 && ((a0exattr & (TDB | DEFINED)) == DEFINED)
731 && ((uint32_t)a0exval + 0x80 < 0x100))
733 m_moveq((WORD)0x7000, (WORD)0);
736 warn("move.l #size,dx converted to moveq");
740 if ((am0 < ABASE) && (am1 < ABASE)) // 68000 modes
742 inst |= siz_12[siz] | am_6[am1] | reg_9[a1reg] | am0 | a0reg;
750 ea1gen((WORD)siz | 0x8000); // Tell ea1gen we're move ea,ea
754 inst |= siz_12[siz] | reg_9[a1reg] | extra_addressing[am0 - ABASE];
771 // Handle MOVE <C_ALL030> <C_ALTDATA>
772 // MOVE <C_ALL030> <M_AREG>
774 int m_move30(WORD inst, WORD size)
777 inst |= siz_12[siz] | reg_9[a1reg & 7] | a0reg | extra_addressing[am0 - ABASE];
792 // move USP,An -- move An,USP
794 int m_usp(WORD inst, WORD siz)
799 inst |= a1reg; // USP, An
801 inst |= a0reg; // An, USP
812 int m_moveq(WORD inst, WORD siz)
816 // Arrange for future fixup
817 if (!(a0exattr & DEFINED))
819 AddFixup(FU_BYTE | FU_SEXT, sloc + 1, a0expr);
822 else if ((uint32_t)a0exval + 0x100 >= 0x200)
823 return error(range_error);
825 inst |= reg_9[a1reg] | (a0exval & 0xFF);
833 // movep Dn, disp(An) -- movep disp(An), Dn
835 int m_movep(WORD inst, WORD siz)
837 // Tell ea0gen to lay off the 0(a0) optimisations on this one
845 inst |= reg_9[a0reg] | a1reg;
855 inst |= reg_9[a1reg] | a0reg;
872 int m_br(WORD inst, WORD siz)
874 if (a0exattr & DEFINED)
876 if ((a0exattr & TDB) != cursect)
878 //printf("m_br(): a0exattr = %X, cursect = %X, a0exval = %X, sloc = %X\n", a0exattr, cursect, a0exval, sloc);
879 return error(rel_error);
882 uint32_t v = (uint32_t)a0exval - (sloc + 2);
884 // Optimize branch instr. size
887 if (CHECK_OPTS(OPT_BSR_BCC_S) && (v != 0) && ((v + 0x80) < 0x100))
894 warn("Bcc.w/BSR.w converted to .s");
901 if ((v + 0x8000) > 0x10000)
902 return error(range_error);
910 if (siz == SIZB || siz == SIZS)
912 if ((v + 0x80) >= 0x100)
913 return error(range_error);
920 if ((v + 0x8000) >= 0x10000)
921 return error(range_error);
929 else if (siz == SIZN)
932 if (siz == SIZB || siz == SIZS)
935 AddFixup(FU_BBRA | FU_PCREL | FU_SEXT, sloc, a0expr);
943 AddFixup(FU_WORD | FU_PCREL | FU_LBRA | FU_ISBRA, sloc, a0expr);
954 int m_addq(WORD inst, WORD siz)
956 inst |= siz_6[siz] | am1 | a1reg;
958 if (a0exattr & DEFINED)
960 if ((a0exval > 8) || (a0exval == 0)) // Range in 1..8
961 return error(range_error);
963 inst |= (a0exval & 7) << 9;
968 AddFixup(FU_QUICK, sloc, a0expr);
981 int m_trap(WORD inst, WORD siz)
985 if (a0exattr & DEFINED)
988 return error(abs_error);
991 return error(range_error);
997 return error(undef_error);
1004 // movem <rlist>,ea -- movem ea,<rlist>
1006 int m_movem(WORD inst, WORD siz)
1014 return error("bad size suffix");
1021 // Handle #<expr>, ea
1024 if (abs_expr(&eval) != OK)
1027 if (eval >= 0x10000L)
1028 return error(range_error);
1034 if ((*tok >= KW_D0) && (*tok <= KW_A7))
1037 if (reglist(&rmask) < 0)
1042 return error("missing comma");
1047 inst |= am0 | a0reg;
1049 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
1050 return error("invalid addressing mode");
1052 // If APREDEC, reverse register mask
1058 for(i=0x8000; i; i>>=1, w>>=1)
1059 rmask = (WORD)((rmask << 1) | (w & 1));
1068 inst |= 0x0400 | am0 | a0reg;
1071 return error("missing comma");
1074 return error("missing register list");
1081 if (abs_expr(&eval) != OK)
1084 if (eval >= 0x10000)
1085 return error(range_error);
1089 else if (reglist(&rmask) < 0)
1092 if (!(amsktab[am0] & (C_CTRL | M_APOSTINC)))
1093 return error("invalid addressing mode");
1105 // CLR.x An ==> SUBA.x An,An
1107 int m_clra(WORD inst, WORD siz)
1109 inst |= a0reg | reg_9[a0reg] | lwsiz_8[siz];
1117 // CLR.L Dn ==> CLR.L An or MOVEQ #0,Dx
1119 int m_clrd(WORD inst, WORD siz)
1121 if (!CHECK_OPTS(OPT_CLR_DX))
1124 inst = (a0reg << 9) | B16(01110000, 00000000);
1132 ////////////////////////////////////////
1134 // 68020/30/40/60 instructions
1136 ////////////////////////////////////////
1141 int m_br30(WORD inst, WORD siz)
1143 if (a0exattr & DEFINED)
1145 if ((a0exattr & TDB) != cursect)
1146 return error(rel_error);
1148 uint32_t v = (uint32_t)a0exval - (sloc + 2);
1157 AddFixup(FU_LONG | FU_PCREL | FU_SEXT, sloc, a0expr);
1165 // bfchg, bfclr, bfexts, bfextu, bfffo, bfins, bfset
1166 // (68020, 68030, 68040)
1168 int m_bfop(WORD inst, WORD siz)
1170 if ((bfval1 > 31) || (bfval1 < 0))
1171 return error("bfxxx offset: immediate value must be between 0 and 31");
1173 // First instruction word - just the opcode and first EA
1174 // Note: both am1 is ORed because solely of bfins - maybe it's a good idea
1175 // to make a dedicated function for it?
1182 if (bfval2 > 31 || bfval2 < 0)
1183 return error("bfxxx width: immediate value must be between 0 and 31");
1185 // For Dw both immediate and register number are stuffed
1186 // into the same field O_o
1187 bfparam2 = (bfval2 << 0);
1191 bfparam1 = (bfval1 << 6);
1193 bfparam1 = bfval1 << 12;
1195 //D_word((inst | am0 | a0reg | am1 | a1reg));
1196 if (inst == B16(11101111, 11000000))
1198 // bfins special case
1199 D_word((inst | am1 | a1reg));
1203 D_word((inst | am0 | a0reg));
1206 ea0gen(siz); // Generate EA
1208 // Second instruction word - Dest register (if exists), Do, Offset, Dw, Width
1209 if (inst == B16(11101111, 11000000))
1211 // bfins special case
1212 inst = bfparam1 | bfparam2;
1215 inst |= a0reg << 12;
1221 inst = bfparam1 | bfparam2;
1227 inst |= a1reg << 12;
1237 // bkpt (68EC000, 68010, 68020, 68030, 68040, CPU32)
1239 int m_bkpt(WORD inst, WORD siz)
1243 if (a0exattr & DEFINED)
1246 return error(abs_error);
1249 return error(range_error);
1255 return error(undef_error);
1264 int m_callm(WORD inst, WORD siz)
1271 if (a0exattr & DEFINED)
1274 return error(abs_error);
1277 return error(range_error);
1279 inst = (uint16_t)a0exval;
1283 return error(undef_error);
1293 // cas (68020, 68030, 68040)
1295 int m_cas(WORD inst, WORD siz)
1301 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1302 return error(unsupport);
1317 return error("bad size suffix");
1322 if ((*tok < KW_D0) && (*tok > KW_D7))
1323 return error("CAS accepts only data registers");
1325 inst2 = (*tok++) & 7;
1328 return error("missing comma");
1331 if ((*tok < KW_D0) && (*tok > KW_D7))
1332 return error("CAS accepts only data registers");
1334 inst2 |= ((*tok++) & 7) << 6;
1337 return error("missing comma");
1340 if ((modes = amode(1)) < 0)
1344 return error("too many ea fields");
1347 return error("extra (unexpected) text found");
1349 // Reject invalid ea modes
1350 amsk = amsktab[am0];
1352 if ((amsk & (M_AIND | M_APOSTINC | M_APREDEC | M_ADISP | M_AINDEXED | M_ABSW | M_ABSL | M_ABASE | M_MEMPOST | M_MEMPRE)) == 0)
1353 return error("unsupported addressing mode");
1355 inst |= am0 | a0reg;
1365 // cas2 (68020, 68030, 68040)
1367 int m_cas2(WORD inst, WORD siz)
1371 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1372 return error(unsupport);
1387 return error("bad size suffix");
1392 if ((*tok < KW_D0) && (*tok > KW_D7))
1393 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1395 inst2 = (*tok++) & 7;
1398 return error("missing colon");
1401 if ((*tok < KW_D0) && (*tok > KW_D7))
1402 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1404 inst3 = (*tok++) & 7;
1407 return error("missing comma");
1410 if ((*tok < KW_D0) && (*tok > KW_D7))
1411 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1413 inst2 |= ((*tok++) & 7) << 6;
1416 return error("missing colon");
1419 if ((*tok < KW_D0) && (*tok > KW_D7))
1420 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1422 inst3 |= ((*tok++) & 7) << 6;
1425 return error("missing comma");
1429 return error("missing (");
1430 if ((*tok >= KW_D0) && (*tok <= KW_D7))
1431 inst2 |= (((*tok++) & 7) << 12) | (0 << 15);
1432 else if ((*tok >= KW_A0) && (*tok <= KW_A7))
1433 inst2 |= (((*tok++) & 7) << 12) | (1 << 15);
1435 return error("CAS accepts either data or address registers for Rn1:Rn2 pair");
1438 return error("missing (");
1441 return error("missing colon");
1445 return error("missing (");
1446 if ((*tok >= KW_D0) && (*tok <= KW_D7))
1447 inst3 |= (((*tok++) & 7) << 12) | (0 << 15);
1448 else if ((*tok >= KW_A0) && (*tok <= KW_A7))
1449 inst3 |= (((*tok++) & 7) << 12) | (1 << 15);
1451 return error("CAS accepts either data or address registers for Rn1:Rn2 pair");
1454 return error("missing (");
1457 return error("extra (unexpected) text found");
1468 // cmp2 (68020, 68030, 68040, CPU32)
1470 int m_cmp2(WORD inst, WORD siz)
1472 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1473 return error(unsupport);
1475 switch (siz & 0x000F)
1489 WORD flg = inst; // Save flag bits
1490 inst &= ~0x3F; // Clobber flag bits in instr
1492 // Install "standard" instr size bits
1498 // OR-in register number
1500 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1502 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1508 inst |= am1 | a1reg; // Get ea1 into instr
1509 D_word(inst); // Deposit instr
1511 // Generate ea0 if requested
1515 ea1gen(siz); // Generate ea1
1520 inst |= am0 | a0reg; // Get ea0 into instr
1521 D_word(inst); // Deposit instr
1522 ea0gen(siz); // Generate ea0
1524 // Generate ea1 if requested
1529 // If we're called from chk2 then bit 11 of size will be set. This is just
1530 // a dumb mechanism to pass this, required by the extension word. (You might
1531 // have noticed the siz & 15 thing above!)
1532 inst = (a1reg << 12) | (siz & (1 << 11));
1544 // chk2 (68020, 68030, 68040, CPU32)
1546 int m_chk2(WORD inst, WORD siz)
1548 return m_cmp2(inst, siz | (1 << 11));
1553 // cpbcc(68020, 68030, 68040 (FBcc), 68060 (FBcc)), pbcc (68851)
1555 int m_fpbr(WORD inst, WORD siz)
1558 if (a0exattr & DEFINED)
1560 if ((a0exattr & TDB) != cursect)
1561 return error(rel_error);
1563 uint32_t v = (uint32_t)a0exval - (sloc + 2);
1565 // Optimize branch instr. size
1568 if ((v != 0) && ((v + 0x8000) < 0x10000))
1578 if ((v + 0x8000) >= 0x10000)
1579 return error(range_error);
1587 else if (siz == SIZN)
1594 AddFixup(FU_LONG | FU_PCREL | FU_SEXT, sloc, a0expr);
1602 AddFixup(FU_WORD | FU_PCREL | FU_SEXT, sloc, a0expr);
1611 // cpbcc(68020, 68030, 68040 (FBcc), 68060 (FBcc))
1613 int m_cpbcc(WORD inst, WORD siz)
1615 if (!(activecpu & (CPU_68020 | CPU_68030)))
1616 return error(unsupport);
1618 return m_fpbr(inst, siz);
1623 // fbcc(6808X, 68040, 68060)
1625 int m_fbcc(WORD inst, WORD siz)
1628 return m_fpbr(inst, siz);
1633 // pbcc(68851 but let's assume 68020 only)
1635 int m_pbcc(WORD inst, WORD siz)
1638 return m_fpbr(inst, siz);
1643 // cpdbcc(68020, 68030)
1645 int m_cpdbr(WORD inst, WORD siz)
1650 WORD condition = inst & 0x1F; // Grab condition sneakily placed in the lower 5 bits of inst
1651 inst &= 0xFFE0; // And then mask them out - you ain't seen me, roit?
1653 inst |= (1 << 9); // Bolt on FPU id
1660 if (a1exattr & DEFINED)
1662 if ((a1exattr & TDB) != cursect)
1663 return error(rel_error);
1665 v = (uint32_t)a1exval - sloc;
1667 if (v + 0x8000 > 0x10000)
1668 return error(range_error);
1674 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
1684 // muls.l / divs.l / divu.l / mulu.l (68020+)
1686 int m_muls(WORD inst, WORD siz)
1688 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1689 return error(unsupport);
1691 WORD flg = inst; // Save flag bits
1692 inst &= ~0x33F; // Clobber flag and extension bits in instr
1694 // Install "standard" instr size bits
1700 // OR-in register number
1702 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1704 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1707 // Regarding extension word: bit 11 is signed/unsigned selector
1708 // bit 10 is 32/64 bit selector
1709 // Both of these are packed in bits 9 and 8 of the instruction
1710 // field in 68ktab. Extra compilcations arise from the fact we
1711 // have to distinguish between divu/s.l Dn,Dm (which is encoded
1712 // as divu/s.l Dn,Dm:Dm) and divu/s.l Dn,Dm:Dx - the first is
1713 // 32 bit while the second 64 bit
1718 inst |= am1 | a1reg; // Get ea1 into instr
1719 D_word(inst); // Deposit instr
1723 inst = a1reg + (a2reg << 12) + ((flg & 0x200) << 2);
1725 inst = a1reg + (a2reg << 12) + ((flg & 0x300) << 2);
1729 // Generate ea0 if requested
1733 ea1gen(siz); // Generate ea1
1740 inst |= am0 | a0reg; // Get ea0 into instr
1741 D_word(inst); // Deposit instr
1745 inst = a1reg + (a2reg << 12) + ((flg & 0x200) << 2);
1747 inst = a1reg + (a2reg << 12) + ((flg & 0x300) << 2);
1751 ea0gen(siz); // Generate ea0
1753 // Generate ea1 if requested
1763 // move16 (ax)+,(ay)+
1765 int m_move16a(WORD inst, WORD siz)
1767 if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1768 return error(unsupport);
1772 inst = (1 << 15) + (a1reg << 12);
1780 // move16 with absolute address
1782 int m_move16b(WORD inst, WORD siz)
1784 if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1785 return error(unsupport);
1791 if (am0 == APOSTINC)
1794 return error("Wasn't this suppose to call m_move16a???");
1797 // move16 (ax)+,(xxx).L
1802 else if (am0 == ABSL)
1806 // move16 (xxx).L,(ax)+
1812 // move16 (xxx).L,(ax)
1817 else if (am0 == AIND)
1819 // move16 (ax),(xxx).L
1832 // pack/unpack (68020/68030/68040)
1834 int m_pack(WORD inst, WORD siz)
1839 return error("bad size suffix");
1841 if (*tok >= KW_D0 && *tok <= KW_D7)
1843 // Dx,Dy,#<adjustment>
1844 inst |= (0 << 3); // R/M
1845 inst |= (*tok++ & 7);
1847 if (*tok != ',' && tok[2] != ',')
1848 return error("missing comma");
1850 if (tok[1] < KW_D0 && tok[1] > KW_D7)
1851 return error(syntax_error);
1853 inst |= ((tok[1] & 7)<<9);
1856 // Fall through for adjustment (common in both valid cases)
1858 else if (*tok == '-')
1860 // -(Ax),-(Ay),#<adjustment>
1861 inst |= (1 << 3); // R/M
1862 tok++; // eat the minus
1864 if ((*tok != '(') && (tok[2]!=')') && (tok[3]!=',') && (tok[4] != '-') && (tok[5] != '(') && (tok[7] != ')') && (tok[8] != ','))
1865 return error(syntax_error);
1867 if (tok[1] < KW_A0 && tok[1] > KW_A7)
1868 return error(syntax_error);
1870 if (tok[5] < KW_A0 && tok[6] > KW_A7)
1871 return error(syntax_error);
1873 inst |= ((tok[1] & 7) << 0);
1874 inst |= ((tok[6] & 7) << 9);
1877 // Fall through for adjustment (common in both valid cases)
1880 return error("invalid syntax");
1882 if ((*tok != CONST) && (*tok != SYMBOL) && (*tok != '-'))
1883 return error(syntax_error);
1885 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
1888 if ((a0exattr & DEFINED) == 0)
1889 return error(undef_error);
1891 if (a0exval + 0x8000 > 0x10000)
1895 return error(extra_stuff);
1897 D_word((a0exval & 0xFFFF));
1906 int m_rtm(WORD inst, WORD siz)
1914 else if (am0 == AREG)
1916 inst |= (1 << 3) + a0reg;
1919 return error("rtm only allows data or address registers.");
1930 int m_rtd(WORD inst, WORD siz)
1934 if (a0exattr & DEFINED)
1937 return error(abs_error);
1939 if ((a0exval + 0x8000) <= 0x7FFF)
1940 return error(range_error);
1946 return error(undef_error);
1955 int m_trapcc(WORD inst, WORD siz)
1963 else if (am0 == IMMED)
1967 if (a0exval < 0x10000)
1974 return error("Immediate value too big");
1984 return error("Invalid parameter for trapcc");
1991 // cinvl/p/a (68040/68060)
1993 int m_cinv(WORD inst, WORD siz)
1998 inst |= (0 << 6) | (a1reg);
2002 inst |= (2 << 6) | (a1reg);
2005 inst |= (1 << 6) | (a1reg);
2008 inst |= (3 << 6) | (a1reg);
2017 int m_fpusavrest(WORD inst, WORD siz)
2019 inst |= am0 | a0reg;
2028 // cpSAVE/cpRESTORE (68020, 68030)
2030 int m_cprest(WORD inst, WORD siz)
2032 if (activecpu & !(CPU_68020 | CPU_68030))
2033 return error(unsupport);
2035 return m_fpusavrest(inst, siz);
2041 // FSAVE/FRESTORE (68040, 68060)
2043 int m_frestore(WORD inst, WORD siz)
2045 if ((!(activecpu & (CPU_68040 | CPU_68060))) ||
2046 (activefpu&(FPU_68881 | FPU_68882)))
2047 return error(unsupport);
2049 return m_fpusavrest(inst, siz);
2054 // movec (68010, 68020, 68030, 68040, 68060, CPU32)
2056 int m_movec(WORD inst, WORD siz)
2060 if (am0 == DREG || am0 == AREG)
2068 inst = (0 << 15) + (a0reg << 12) + CREGlut[a1reg];
2073 inst = (1 << 15) + (a0reg << 12) + CREGlut[a1reg];
2084 inst = (0 << 15) + (a1reg << 12) + CREGlut[a0reg];
2089 inst = (1 << 15) + (a1reg << 12) + CREGlut[a0reg];
2099 // moves (68010, 68020, 68030, 68040, CPU32)
2101 int m_moves(WORD inst, WORD siz)
2103 if (activecpu & !(CPU_68020 | CPU_68030 | CPU_68040))
2104 return error(unsupport);
2108 else if (siz == SIZL)
2115 inst |= am1 | a1reg;
2117 inst = (a0reg << 12) | (1 << 11) | (0 << 15);
2120 else if (am0 == AREG)
2122 inst |= am1 | a1reg;
2124 inst = (a0reg << 12) | (1 << 11) | (1 << 15);
2131 inst |= am0 | a0reg;
2133 inst = (a1reg << 12) | (0 << 11) | (0 << 15);
2138 inst |= am0 | a0reg;
2140 inst = (a1reg << 12) | (0 << 11) | (1 << 15);
2150 // pflusha (68030, 68040)
2152 int m_pflusha(WORD inst, WORD siz)
2154 if (activecpu == CPU_68030)
2157 inst = (1 << 13) | (1 << 10) | (0 << 5) | 0;
2161 else if (activecpu == CPU_68040)
2163 inst = B16(11110101, 00011000);
2168 return error(unsupport);
2175 // pflush (68030, 68040, 68060)
2177 int m_pflush(WORD inst, WORD siz)
2179 if (activecpu == CPU_68030)
2182 // PFLUSH FC, MASK, < ea >
2190 if (*tok != CONST && *tok != SYMBOL)
2191 return error("function code should be an expression");
2193 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2196 if ((a0exattr & DEFINED) == 0)
2197 return error("function code immediate should be defined");
2200 return error("function code out of range (0-7)");
2202 fc = (uint16_t)a0exval;
2212 fc = (1 << 4) | (*tok++ & 7);
2223 return error(syntax_error);
2227 return error("comma exptected");
2230 return error("mask should be an immediate value");
2232 if (*tok != CONST && *tok != SYMBOL)
2233 return error("mask is supposed to be immediate");
2235 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2238 if ((a0exattr & DEFINED) == 0)
2239 return error("mask immediate value should be defined");
2242 return error("function code out of range (0-7)");
2244 mask = (uint16_t)a0exval << 5;
2250 inst = (1 << 13) | fc | mask | (4 << 10);
2254 else if (*tok == ',')
2256 // PFLUSH FC, MASK, < ea >
2259 if (amode(0) == ERROR)
2263 return error(extra_stuff);
2265 if (am0 == AIND || am0 == ABSW || am0 == ABSL || am0 == ADISP || am0 == ADISP || am0 == AINDEXED || am0 == ABASE || am0 == MEMPOST || am0 == MEMPRE)
2267 inst |= am0 | a0reg;
2269 inst = (1 << 13) | fc | mask | (6 << 10);
2275 return error("unsupported addressing mode");
2279 return error(syntax_error);
2283 else if (activecpu == CPU_68040 || activecpu == CPU_68060)
2287 if (*tok != '(' && tok[2] != ')')
2288 return error(syntax_error);
2290 if (tok[1] < KW_A0 && tok[1] > KW_A7)
2291 return error("expected (An)");
2293 if ((inst & 7) == 7)
2294 // With pflushn/pflush there's no easy way to distinguish between
2295 // the two in 68040 mode. Ideally the opcode bitfields would have
2296 // been hardcoded in 68ktab but there is aliasing between 68030
2297 // and 68040 opcode. So we just set the 3 lower bits to 1 in
2298 // pflushn inside 68ktab and detect it here.
2299 inst = (inst & 0xff8) | 8;
2301 inst |= (tok[1] & 7) | (5 << 8);
2304 return error(extra_stuff);
2309 return error(unsupport);
2316 // pflushan (68040, 68060)
2318 int m_pflushan(WORD inst, WORD siz)
2320 if (activecpu == CPU_68040 || activecpu == CPU_68060)
2330 int m_pflushr(WORD inst, WORD siz)
2334 WORD flg = inst; // Save flag bits
2335 inst &= ~0x3F; // Clobber flag bits in instr
2337 // Install "standard" instr size bits
2343 // OR-in register number
2345 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
2347 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
2353 inst |= am1 | a1reg; // Get ea1 into instr
2354 D_word(inst); // Deposit instr
2356 // Generate ea0 if requested
2360 ea1gen(siz); // Generate ea1
2365 inst |= am0 | a0reg; // Get ea0 into instr
2366 D_word(inst); // Deposit instr
2367 ea0gen(siz); // Generate ea0
2369 // Generate ea1 if requested
2374 D_word(B16(10100000, 00000000));
2380 // ploadr, ploadw (68030)
2382 int m_pload(WORD inst, WORD siz, WORD extension)
2384 // TODO: 68851 support is not added yet.
2385 // None of the ST series of computers had a 68020 + 68851 socket and since
2386 // this is an Atari targetted assembler...
2395 if (a0reg == KW_SFC - KW_SFC)
2397 else if (a0reg == KW_DFC - KW_SFC)
2400 return error("illegal control register specified");
2404 inst = (1 << 3) | a0reg;
2407 if ((a0exattr & DEFINED) == 0)
2408 return error("constant value must be defined");
2411 return error("constant value must be between 0 and 7");
2413 inst = (2 << 3) | (uint16_t)a0exval;
2417 inst |= extension | (1 << 13);
2426 int m_ploadr(WORD inst, WORD siz)
2428 return m_pload(inst, siz, 1 << 9);
2432 int m_ploadw(WORD inst, WORD siz)
2434 return m_pload(inst, siz, 0 << 9);
2439 // pmove (68030/68851)
2441 int m_pmove(WORD inst, WORD siz)
2445 // TODO: 68851 support is not added yet. None of the ST series of
2446 // computers had a 68020 + 68851 socket and since this is an Atari
2447 // targetted assembler.... (same for 68EC030)
2450 inst2 = inst & (1 << 8); // Copy the flush bit over to inst2 in case we're called from m_pmovefd
2451 inst &= ~(1 << 8); // And mask it out
2458 else if (am1 == CREG)
2464 return error("pmove sez: Wut?");
2466 // The instruction is a quad-word (8 byte) operation
2467 // for the CPU root pointer and the supervisor root pointer.
2468 // It is a long-word operation for the translation control register
2469 // and the transparent translation registers(TT0 and TT1).
2470 // It is a word operation for the MMU status register.
2472 if (((reg == (KW_URP - KW_SFC)) || (reg == (KW_SRP - KW_SFC)))
2473 && ((siz != SIZD) && (siz != SIZN)))
2474 return error(siz_error);
2476 if (((reg == (KW_TC - KW_SFC)) || (reg == (KW_TT0 - KW_SFC)) || (reg == (KW_TT1 - KW_SFC)))
2477 && ((siz != SIZL) && (siz != SIZN)))
2478 return error(siz_error);
2480 if ((reg == (KW_MMUSR - KW_SFC)) && ((siz != SIZW) && (siz != SIZN)))
2481 return error(siz_error);
2485 inst |= am1 | a1reg;
2488 else if (am1 == CREG)
2490 inst |= am0 | a0reg;
2494 switch (reg + KW_SFC)
2497 inst2 |= (0 << 10) + (1 << 14); break;
2499 inst2 |= (2 << 10) + (1 << 14); break;
2501 inst2 |= (3 << 10) + (1 << 14); break;
2503 inst2 |= (2 << 10) + (0 << 13); break;
2505 inst2 |= (3 << 10) + (0 << 13); break;
2508 inst2 |= (1 << 9) + (3 << 13);
2510 inst2 |= (0 << 9) + (3 << 13);
2513 return error("unsupported register");
2521 else if (am1 == CREG)
2531 int m_pmovefd(WORD inst, WORD siz)
2535 return m_pmove(inst | (1 << 8), siz);
2542 int m_ptrapcc(WORD inst, WORD siz)
2545 // We stash the 5 condition bits inside the opcode in 68ktab (bits 0-4),
2546 // so we need to extract them first and fill in the clobbered bits.
2547 WORD opcode = inst & 0x1F;
2548 inst = (inst & 0xFFE0) | (0x18);
2557 else if (siz == SIZL)
2564 else if (siz == SIZN)
2576 // ptestr, ptestw (68030, 68040)
2577 // TODO See comment on m_pmove about 68851 support
2578 // TODO quite a good chunk of the 030 code is copied from m_pload, perhaps merge these somehow?
2580 int m_ptest(WORD inst, WORD siz, WORD extension)
2584 if (activecpu != CPU_68030 && activecpu != CPU_68040)
2585 return error(unsupport);
2587 if (activecpu == CPU_68030)
2595 if (a0reg == KW_SFC - KW_SFC)
2597 else if (a0reg == KW_DFC - KW_SFC)
2600 return error("illegal control register specified");
2603 extension |= (1 << 3) | a0reg;
2606 if ((a0exattr & DEFINED) == 0)
2607 return error("constant value must be defined");
2610 return error("constant value must be between 0 and 7");
2612 extension |= (2 << 3) | (uint16_t)a0exval;
2616 // Operand 3 must be an immediate
2620 return error("ptest level must be immediate");
2622 // Let's be a bit inflexible here and demand that this
2623 // is fully defined at this stage. Otherwise we'd have
2624 // to arrange for a bitfield fixup, which would mean
2625 // polluting the bitfields and codebase with special
2626 // cases that might most likely never be used.
2627 // So if anyone gets bit by this: sorry for being a butt!
2628 if (abs_expr(&eval) != OK)
2629 return OK; // We're returning OK because error() has already been called and error count has been increased
2632 return error("ptest level must be between 0 and 7");
2634 extension |= eval << 10;
2636 // Operand 4 is optional and must be an address register
2642 if ((*tok >= KW_A0) && (*tok <= KW_A7))
2644 extension |= (1 << 8) | ((*tok++ & 7) << 4);
2648 return error("fourth parameter must be an address register");
2658 return error("Not implemented yet.");
2663 int m_ptestr(WORD inst, WORD siz)
2665 return m_ptest(inst, siz, (1 << 15) | (0 << 9));
2668 int m_ptestw(WORD inst, WORD siz)
2670 return m_ptest(inst, siz, (1 << 15) | (1 << 9));
2673 //////////////////////////////////////////////////////////////////////////////
2675 // 68020/30/40/60 instructions
2676 // Note: the map of which instructions are allowed on which CPUs came from the
2677 // 68060 manual, section D-1 (page 392 of the PDF). The current implementation
2678 // is missing checks for the EC models which have a simplified FPU.
2680 //////////////////////////////////////////////////////////////////////////////
2683 #define FPU_NOWARN 0
2688 // Generate a FPU opcode
2690 static inline int gen_fpu(WORD inst, WORD siz, WORD opmode, WORD emul)
2692 if (am0 < AM_NONE) // Check first operand for ea or fp - is this right?
2694 inst |= (1 << 9); // Bolt on FPU id
2697 //if (am0 == DREG || am0 == AREG)
2701 inst = 1 << 14; // R/M field (we have ea so have to set this to 1)
2705 case SIZB: inst |= (6 << 10); break;
2706 case SIZW: inst |= (4 << 10); break;
2707 case SIZL: inst |= (0 << 10); break;
2709 case SIZS: inst |= (1 << 10); break;
2710 case SIZD: inst |= (5 << 10); break;
2711 case SIZX: inst |= (2 << 10); break;
2716 warn("This encoding will cause an unimplemented data type exception in the MC68040 to allow emulation in software.");
2720 return error("Something bad happened, possibly, in gen_fpu.");
2724 inst |= (a1reg << 7);
2731 inst |= (1 << 9); // Bolt on FPU id
2735 inst |= (a1reg << 7);
2740 if ((emul & FPU_FPSP) && (activefpu == (FPU_68040 | FPU_68060)))
2741 warn("Instruction is emulated in 68040/060");
2748 // fabs (6888X, 68040FPSP, 68060FPSP)
2750 int m_fabs(WORD inst, WORD siz)
2753 return gen_fpu(inst, siz, B8(00011000), FPU_NOWARN);
2758 // fsabs (68040, 68060)
2760 int m_fsabs(WORD inst, WORD siz)
2763 if (activefpu == FPU_68040)
2764 return gen_fpu(inst, siz, B8(01011000), FPU_NOWARN);
2766 return error("Unsupported in current FPU");
2771 // fdabs (68040, 68060)
2773 int m_fdabs(WORD inst, WORD siz)
2775 if (activefpu == FPU_68040)
2776 return gen_fpu(inst, siz, B8(01011100), FPU_NOWARN);
2778 return error("Unsupported in current FPU");
2783 // facos (6888X, 68040FPSP, 68060FPSP)
2785 int m_facos(WORD inst, WORD siz)
2788 return gen_fpu(inst, siz, B8(00011100), FPU_FPSP);
2793 // fadd (6888X, 68040, 68060)
2795 int m_fadd(WORD inst, WORD siz)
2798 return gen_fpu(inst, siz, B8(00100010), FPU_NOWARN);
2803 // fsadd (68040, 68060)
2805 int m_fsadd(WORD inst, WORD siz)
2807 if (activefpu & (FPU_68040 | FPU_68060))
2808 return gen_fpu(inst, siz, B8(01100010), FPU_NOWARN);
2810 return error("Unsupported in current FPU");
2817 int m_fdadd(WORD inst, WORD siz)
2819 if (activefpu & (FPU_68040 | FPU_68060))
2820 return gen_fpu(inst, siz, B8(01100110), FPU_NOWARN);
2822 return error("Unsupported in current FPU");
2827 // fasin (6888X, 68040FPSP, 68060FPSP)
2829 int m_fasin(WORD inst, WORD siz)
2832 return gen_fpu(inst, siz, B8(00001100), FPU_FPSP);
2837 // fatan (6888X, 68040FPSP, 68060FPSP)
2839 int m_fatan(WORD inst, WORD siz)
2842 return gen_fpu(inst, siz, B8(00001010), FPU_FPSP);
2847 // fatanh (6888X, 68040FPSP, 68060FPSP)
2849 int m_fatanh(WORD inst, WORD siz)
2852 return gen_fpu(inst, siz, B8(00001101), FPU_FPSP);
2857 // fcmp (6888X, 68040, 68060)
2859 int m_fcmp(WORD inst, WORD siz)
2862 return gen_fpu(inst, siz, B8(00111000), FPU_FPSP);
2867 // fcos (6888X, 68040FPSP, 68060FPSP)
2869 int m_fcos(WORD inst, WORD siz)
2872 return gen_fpu(inst, siz, B8(00011101), FPU_FPSP);
2877 // fcosh (6888X, 68040FPSP, 68060FPSP)
2879 int m_fcosh(WORD inst, WORD siz)
2882 return gen_fpu(inst, siz, B8(00011001), FPU_FPSP);
2887 // fdbcc (6888X, 68040, 68060FPSP)
2889 int m_fdbcc(WORD inst, WORD siz)
2892 WORD opcode = inst & 0x3F; // Grab conditional bitfield
2902 if (a1exattr & DEFINED)
2904 if ((a1exattr & TDB) != cursect)
2905 return error(rel_error);
2907 uint32_t v = (uint32_t)a1exval - sloc;
2909 if ((v + 0x8000) > 0x10000)
2910 return error(range_error);
2916 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
2920 if (activefpu == FPU_68060)
2921 warn("Instruction is emulated in 68060");
2928 // fdiv (6888X, 68040, 68060)
2930 int m_fdiv(WORD inst, WORD siz)
2933 return gen_fpu(inst, siz, B8(00100000), FPU_NOWARN);
2938 // fsdiv (68040, 68060)
2940 int m_fsdiv(WORD inst, WORD siz)
2942 if (activefpu & (FPU_68040 | FPU_68060))
2943 return gen_fpu(inst, siz, B8(01100000), FPU_NOWARN);
2945 return error("Unsupported in current FPU");
2950 // fddiv (68040, 68060)
2952 int m_fddiv(WORD inst, WORD siz)
2954 if (activefpu & (FPU_68040 | FPU_68060))
2955 return gen_fpu(inst, siz, B8(01100100), FPU_NOWARN);
2957 return error("Unsupported in current FPU");
2962 // fetox (6888X, 68040FPSP, 68060FPSP)
2964 int m_fetox(WORD inst, WORD siz)
2967 return gen_fpu(inst, siz, B8(00010000), FPU_FPSP);
2972 // fetoxm1 (6888X, 68040FPSP, 68060FPSP)
2974 int m_fetoxm1(WORD inst, WORD siz)
2977 return gen_fpu(inst, siz, B8(00001000), FPU_FPSP);
2982 // fgetexp (6888X, 68040FPSP, 68060FPSP)
2984 int m_fgetexp(WORD inst, WORD siz)
2987 return gen_fpu(inst, siz, B8(00011110), FPU_FPSP);
2992 // fgetman (6888X, 68040FPSP, 68060FPSP)
2994 int m_fgetman(WORD inst, WORD siz)
2997 return gen_fpu(inst, siz, B8(00011111), FPU_FPSP);
3002 // fint (6888X, 68040FPSP, 68060)
3004 int m_fint(WORD inst, WORD siz)
3007 // special case - fint fpx = fint fpx,fpx
3010 if (activefpu == FPU_68040)
3011 warn("Instruction is emulated in 68040");
3013 return gen_fpu(inst, siz, B8(00000001), FPU_NOWARN);
3018 // fintrz (6888X, 68040FPSP, 68060)
3020 int m_fintrz(WORD inst, WORD siz)
3023 // special case - fintrz fpx = fintrz fpx,fpx
3026 if (activefpu == FPU_68040)
3027 warn("Instruction is emulated in 68040");
3029 return gen_fpu(inst, siz, B8(00000011), FPU_NOWARN);
3034 // flog10 (6888X, 68040FPSP, 68060FPSP)
3036 int m_flog10(WORD inst, WORD siz)
3039 return gen_fpu(inst, siz, B8(00010101), FPU_FPSP);
3044 // flog2 (6888X, 68040FPSP, 68060FPSP)
3046 int m_flog2(WORD inst, WORD siz)
3049 return gen_fpu(inst, siz, B8(00010110), FPU_FPSP);
3054 // flogn (6888X, 68040FPSP, 68060FPSP)
3056 int m_flogn(WORD inst, WORD siz)
3059 return gen_fpu(inst, siz, B8(00010100), FPU_FPSP);
3064 // flognp1 (6888X, 68040FPSP, 68060FPSP)
3066 int m_flognp1(WORD inst, WORD siz)
3069 return gen_fpu(inst, siz, B8(00000110), FPU_FPSP);
3074 // fmod (6888X, 68040FPSP, 68060FPSP)
3076 int m_fmod(WORD inst, WORD siz)
3079 return gen_fpu(inst, siz, B8(00100001), FPU_FPSP);
3084 // fmove (6888X, 68040, 68060)
3086 int m_fmove(WORD inst, WORD siz)
3091 if ((am0 == FREG) && (am1 < AM_USP))
3095 inst |= am1 | a1reg;
3104 case SIZB: inst |= (6 << 10); break;
3105 case SIZW: inst |= (4 << 10); break;
3106 case SIZL: inst |= (0 << 10); break;
3108 case SIZS: inst |= (1 << 10); break;
3109 case SIZD: inst |= (5 << 10); break;
3110 case SIZX: inst |= (2 << 10); break;
3111 case SIZP: inst |= (3 << 10);
3112 // In P size we have 2 cases: {#k} where k is immediate
3113 // and {Dn} where Dn=Data register
3118 inst |= bfval1 << 4;
3123 if (bfval1 > 63 && bfval1 < -64)
3124 return error("K-factor must be between -64 and 63");
3126 inst |= bfval1 & 127;
3131 return error("Something bad happened, possibly.");
3135 // Destination specifier
3136 inst |= (a0reg << 7);
3144 else if ((am0 < AM_USP) && (am1 == FREG))
3149 inst |= am0 | a0reg;
3158 case SIZB: inst |= (6 << 10); break;
3159 case SIZW: inst |= (4 << 10); break;
3160 case SIZL: inst |= (0 << 10); break;
3162 case SIZS: inst |= (1 << 10); break;
3163 case SIZD: inst |= (5 << 10); break;
3164 case SIZX: inst |= (2 << 10); break;
3165 case SIZP: inst |= (3 << 10); break;
3167 return error("Something bad happened, possibly.");
3171 // Destination specifier
3172 inst |= (a1reg << 7);
3180 else if ((am0 == FREG) && (am1 == FREG))
3182 // register-to-register
3183 // Essentially ea to register with R/0=0
3192 if (siz != SIZX && siz != SIZN)
3193 return error("Invalid size");
3196 inst |= (a0reg << 10);
3198 // Destination register
3199 inst |= (a1reg << 7);
3209 // fmove (6888X, 68040, 68060)
3211 int m_fmovescr(WORD inst, WORD siz)
3215 // Move Floating-Point System Control Register (FPCR)
3219 if ((am0 == FPSCR) && (am1 < AM_USP))
3221 inst |= am1 | a1reg;
3223 inst = (1 << 13) + (1 << 15);
3229 else if ((am1 == FPSCR) && (am0 < AM_USP))
3231 inst |= am0 | a0reg;
3233 inst = (0 << 13) + (1 << 15);
3240 return error("m_fmovescr says: wut?");
3244 // fsmove/fdmove (68040, 68060)
3246 int m_fsmove(WORD inst, WORD siz)
3248 if (!(activefpu & (FPU_68040 | FPU_68060)))
3249 return error("Unsupported in current FPU");
3251 return gen_fpu(inst, siz, B8(01100100), FPU_FPSP);
3255 int m_fdmove(WORD inst, WORD siz)
3257 if (!(activefpu & (FPU_68040 | FPU_68060)))
3258 return error("Unsupported in current FPU");
3260 return gen_fpu(inst, siz, B8(01100100), FPU_FPSP);
3265 // fmovecr (6888X, 68040FPSP, 68060FPSP)
3267 int m_fmovecr(WORD inst, WORD siz)
3277 if (activefpu == FPU_68040)
3278 warn("Instruction is emulated in 68040/060");
3285 // fmovem (6888X, 68040, 68060FPSP)
3287 int m_fmovem(WORD inst, WORD siz)
3294 if (siz == SIZX || siz == SIZN)
3296 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
3298 // fmovem.x <rlist>,ea
3299 if (fpu_reglist_left(®mask) < 0)
3303 return error("missing comma");
3308 inst |= am0 | a0reg;
3310 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3311 return error("invalid addressing mode");
3314 inst = (1 << 15) | (1 << 14) | (1 << 13) | (0 << 11) | regmask;
3319 else if ((*tok >= KW_D0) && (*tok <= KW_D7))
3322 datareg = (*tok++ & 7) << 10;
3325 return error("missing comma");
3330 inst |= am0 | a0reg;
3332 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3333 return error("invalid addressing mode");
3335 // Quote from the 060 manual:
3336 // "[..] when the processor attempts an FMOVEM.X instruction using a dynamic register list."
3337 if (activefpu == FPU_68060)
3338 warn("Instruction is emulated in 68060");
3341 inst = (1 << 15) | (1 << 14) | (1 << 13) | (1 << 11) | (datareg << 4);
3352 inst |= am0 | a0reg;
3355 return error("missing comma");
3357 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
3359 // fmovem.x ea,<rlist>
3360 if (fpu_reglist_right(®mask) < 0)
3364 inst = (1 << 15) | (1 << 14) | (0 << 13) | (2 << 11) | regmask;
3372 datareg = (*tok++ & 7) << 10;
3374 // Quote from the 060 manual:
3375 // "[..] when the processor attempts an FMOVEM.X instruction using a dynamic register list."
3376 if (activefpu == FPU_68060)
3377 warn("Instruction is emulated in 68060");
3380 inst = (1 << 15) | (1 << 14) | (0 << 13) | (3 << 11) | (datareg << 4);
3387 else if (siz == SIZL)
3389 if ((*tok == KW_FPCR) || (*tok == KW_FPSR) || (*tok == KW_FPIAR))
3391 // fmovem.l <rlist>,ea
3392 regmask = (1 << 15) | (1 << 13);
3393 int no_control_regs = 0;
3396 if (*tok == KW_FPCR)
3398 regmask |= (1 << 12);
3404 if (*tok == KW_FPSR)
3406 regmask |= (1 << 11);
3412 if (*tok == KW_FPIAR)
3414 regmask |= (1 << 10);
3420 if ((*tok == '/') || (*tok == '-'))
3427 return error("missing comma");
3432 // Quote from the 060 manual:
3433 // "[..] when the processor attempts to execute an FMOVEM.L instruction with
3434 // an immediate addressing mode to more than one floating - point
3435 // control register (FPCR, FPSR, FPIAR)[..]"
3436 if (activefpu == FPU_68060)
3437 if (no_control_regs > 1 && am0 == IMMED)
3438 warn("Instruction is emulated in 68060");
3440 inst |= am0 | a0reg;
3447 // fmovem.l ea,<rlist>
3451 inst |= am0 | a0reg;
3454 return error("missing comma");
3456 regmask = (1 << 15) | (0 << 13);
3459 if (*tok == KW_FPCR)
3461 regmask |= (1 << 12);
3466 if (*tok == KW_FPSR)
3468 regmask |= (1 << 11);
3473 if (*tok == KW_FPIAR)
3475 regmask |= (1 << 10);
3480 if ((*tok == '/') || (*tok == '-'))
3487 return error("extra (unexpected) text found");
3489 inst |= am0 | a0reg;
3496 return error("bad size suffix");
3503 // fmul (6888X, 68040, 68060)
3505 int m_fmul(WORD inst, WORD siz)
3508 return gen_fpu(inst, siz, B8(00100011), FPU_NOWARN);
3513 // fsmul (68040, 68060)
3515 int m_fsmul(WORD inst, WORD siz)
3517 if (activefpu & (FPU_68040 | FPU_68060))
3518 return gen_fpu(inst, siz, B8(01100011), FPU_NOWARN);
3520 return error("Unsupported in current FPU");
3527 int m_fdmul(WORD inst, WORD siz)
3529 if (activefpu & (FPU_68040 | FPU_68060))
3530 return gen_fpu(inst, siz, B8(01100111), FPU_NOWARN);
3532 return error("Unsupported in current FPU");
3537 // fneg (6888X, 68040, 68060)
3539 int m_fneg(WORD inst, WORD siz)
3546 return gen_fpu(inst, siz, B8(00011010), FPU_NOWARN);
3549 return gen_fpu(inst, siz, B8(00011010), FPU_NOWARN);
3554 // fsneg (68040, 68060)
3556 int m_fsneg(WORD inst, WORD siz)
3558 if (activefpu & (FPU_68040 | FPU_68060))
3563 return gen_fpu(inst, siz, B8(01011010), FPU_NOWARN);
3566 return gen_fpu(inst, siz, B8(01011010), FPU_NOWARN);
3569 return error("Unsupported in current FPU");
3574 // fdneg (68040, 68060)
3576 int m_fdneg(WORD inst, WORD siz)
3578 if (activefpu & (FPU_68040 | FPU_68060))
3583 return gen_fpu(inst, siz, B8(01011110), FPU_NOWARN);
3586 return gen_fpu(inst, siz, B8(01011110), FPU_NOWARN);
3589 return error("Unsupported in current FPU");
3594 // fnop (6888X, 68040, 68060)
3596 int m_fnop(WORD inst, WORD siz)
3599 return gen_fpu(inst, siz, B8(00000000), FPU_NOWARN);
3604 // frem (6888X, 68040FPSP, 68060FPSP)
3606 int m_frem(WORD inst, WORD siz)
3609 return gen_fpu(inst, siz, B8(00100101), FPU_FPSP);
3614 // fscale (6888X, 68040FPSP, 68060FPSP)
3616 int m_fscale(WORD inst, WORD siz)
3619 return gen_fpu(inst, siz, B8(00100110), FPU_FPSP);
3624 // FScc (6888X, 68040, 68060), cpScc (68851, 68030), PScc (68851)
3625 // TODO: Add check for PScc to ensure 68020+68851 active
3626 // TODO: Add check for cpScc to ensure 68020+68851, 68030
3628 int m_fscc(WORD inst, WORD siz)
3632 // We stash the 5 condition bits inside the opcode in 68ktab (bits 4-0),
3633 // so we need to extract them first and fill in the clobbered bits.
3634 WORD opcode = inst & 0x1F;
3636 inst |= am0 | a0reg;
3640 if (activefpu == FPU_68060)
3641 warn("Instruction is emulated in 68060");
3647 // fsgldiv (6888X, 68040FPSP, 68060FPSP)
3649 int m_fsgldiv(WORD inst, WORD siz)
3652 return gen_fpu(inst, siz, B8(00100100), FPU_FPSP);
3657 // fsglmul (6888X, 68040, 68060FPSP)
3659 int m_fsglmul(WORD inst, WORD siz)
3662 return gen_fpu(inst, siz, B8(00100111), FPU_FPSP);
3667 // fsin (6888X, 68040FPSP, 68060FPSP)
3669 int m_fsin(WORD inst, WORD siz)
3672 return gen_fpu(inst, siz, B8(00001110), FPU_FPSP);
3677 // fsincos (6888X, 68040FPSP, 68060FPSP)
3679 int m_fsincos(WORD inst, WORD siz)
3683 // Swap a1reg, a2reg as a2reg should be stored in the bitfield gen_fpu
3690 if (gen_fpu(inst, siz, B8(00110000), FPU_FPSP) == OK)
3701 // fsinh (6888X, 68040FPSP, 68060FPSP)
3703 int m_fsinh(WORD inst, WORD siz)
3706 return gen_fpu(inst, siz, B8(00000010), FPU_FPSP);
3711 // fsqrt (6888X, 68040, 68060)
3713 int m_fsqrt(WORD inst, WORD siz)
3716 return gen_fpu(inst, siz, B8(00000100), FPU_NOWARN);
3721 // fsfsqrt (68040, 68060)
3723 int m_fsfsqrt(WORD inst, WORD siz)
3725 if (activefpu & (FPU_68040 | FPU_68060))
3726 return gen_fpu(inst, siz, B8(01000001), FPU_NOWARN);
3728 return error("Unsupported in current FPU");
3733 // fdfsqrt (68040, 68060)
3735 int m_fdfsqrt(WORD inst, WORD siz)
3737 if (activefpu & (FPU_68040 | FPU_68060))
3738 return gen_fpu(inst, siz, B8(01000101), FPU_NOWARN);
3740 return error("Unsupported in current FPU");
3745 // fsub (6888X, 68040, 68060)
3747 int m_fsub(WORD inst, WORD siz)
3750 return gen_fpu(inst, siz, B8(00101000), FPU_NOWARN);
3755 // fsfsub (68040, 68060)
3757 int m_fsfsub(WORD inst, WORD siz)
3759 if (activefpu & (FPU_68040 | FPU_68060))
3760 return gen_fpu(inst, siz, B8(01101000), FPU_NOWARN);
3762 return error("Unsupported in current FPU");
3767 // fdfsub (68040, 68060)
3769 int m_fdsub(WORD inst, WORD siz)
3771 if (activefpu & (FPU_68040 | FPU_68060))
3772 return gen_fpu(inst, siz, B8(01101100), FPU_NOWARN);
3774 return error("Unsupported in current FPU");
3779 // ftan (6888X, 68040FPSP, 68060FPSP)
3781 int m_ftan(WORD inst, WORD siz)
3784 return gen_fpu(inst, siz, B8(00001111), FPU_FPSP);
3789 // ftanh (6888X, 68040FPSP, 68060FPSP)
3791 int m_ftanh(WORD inst, WORD siz)
3794 return gen_fpu(inst, siz, B8(00001001), FPU_FPSP);
3799 // ftentox (6888X, 68040FPSP, 68060FPSP)
3801 int m_ftentox(WORD inst, WORD siz)
3804 return gen_fpu(inst, siz, B8(00010010), FPU_FPSP);
3809 // FTRAPcc (6888X, 68040, 68060FPSP)
3811 int m_ftrapcc(WORD inst, WORD siz)
3815 // We stash the 5 condition bits inside the opcode in 68ktab (bits 3-7),
3816 // so we need to extract them first and fill in the clobbered bits.
3817 WORD opcode = (inst >> 3) & 0x1F;
3818 inst = (inst & 0xFF07) | (0xF << 3);
3827 else if (siz == SIZL)
3834 else if (siz == SIZN)
3842 if (activefpu == FPU_68060)
3843 warn("Instruction is emulated in 68060");
3850 // ftst (6888X, 68040, 68060)
3852 int m_ftst(WORD inst, WORD siz)
3855 return gen_fpu(inst, siz, B8(00111010), FPU_NOWARN);
3860 // ftwotox (6888X, 68040FPSP, 68060FPSP)
3862 int m_ftwotox(WORD inst, WORD siz)
3865 return gen_fpu(inst, siz, B8(00010001), FPU_FPSP);
3869 /////////////////////////////////
3871 // 68060 specific instructions //
3873 /////////////////////////////////
3879 int m_lpstop(WORD inst, WORD siz)
3882 D_word(B16(00000001, 11000000));
3884 if (a0exattr & DEFINED)
3890 AddFixup(FU_WORD, sloc, a0expr);
3901 int m_plpa(WORD inst, WORD siz)
3904 inst |= a0reg; // Install register