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))
470 // Immediate is larger than 8 so let's convert to lea
471 am0 = ADISP; // Change addressing mode
472 a0reg = a1reg; // In ADISP a0reg is used instead of a1reg!
473 return m_lea(B16(01000001, 11011000), SIZW);
477 inst |= am0 | a0reg | lwsiz_8[siz] | reg_9[a1reg];
479 ea0gen(siz); // Generate EA
486 // If bit 0 of `inst' is 1, install size bits in bits 6..7 of instr.
487 // If bit 1 of `inst' is 1, install a1reg in bits 9..11 of instr.
489 int m_reg(WORD inst, WORD siz)
496 // Install other register (9..11)
497 inst |= reg_9[a1reg];
499 inst &= ~7; // Clear off crufty bits
500 inst |= a0reg; // Install first register
510 int m_imm(WORD inst, WORD siz)
522 int m_imm8(WORD inst, WORD siz)
535 int m_shr(WORD inst, WORD siz)
537 inst |= reg_9[a0reg] | a1reg | siz_6[siz];
547 int m_shi(WORD inst, WORD siz)
549 inst |= a1reg | siz_6[siz];
551 if (a0exattr & DEFINED)
554 return error(range_error);
556 inst |= (a0exval & 7) << 9;
561 AddFixup(FU_QUICK, sloc, a0expr);
570 // {bset, btst, bchg, bclr} -- #immed,ea -- Dn,ea
572 int m_bitop(WORD inst, WORD siz)
574 // Enforce instruction sizes
576 { // X,Dn must be .n or .l
577 if (siz & (SIZB | SIZW))
578 return error(siz_error);
580 else if (siz & (SIZW | SIZL)) // X,ea must be .n or .b
581 return error(siz_error);
583 // Construct instr and EAs
589 ea0gen(SIZB); // Immediate bit number
593 inst |= reg_9[a0reg];
604 int m_dbra(WORD inst, WORD siz)
610 if (a1exattr & DEFINED)
612 if ((a1exattr & TDB) != cursect)
613 return error(rel_error);
615 uint32_t v = (uint32_t)a1exval - sloc;
617 if (v + 0x8000 > 0x10000)
618 return error(range_error);
624 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
635 int m_exg(WORD inst, WORD siz)
641 if (am0 == DREG && am1 == DREG)
643 else if (am0 == AREG && am1 == AREG)
649 m = a1reg; // Get AREG into a1reg
657 inst |= m | reg_9[a0reg] | a1reg;
667 int m_link(WORD inst, WORD siz)
671 // Is this an error condition???
676 inst &= ~((3 << 9) | (1 << 6) | (1 << 4));
688 WORD extra_addressing[16]=
690 0x30, // 0100 (bd,An,Xn)
691 0x30, // 0101 ([bd,An],Xn,od)
692 0x30, // 0102 ([bc,An,Xn],od)
693 0x30, // 0103 (bd,PC,Xn)
694 0x30, // 0104 ([bd,PC],Xn,od)
695 0x30, // 0105 ([bc,PC,Xn],od)
710 // Handle MOVE <C_ALL> <C_ALTDATA>
711 // MOVE <C_ALL> <M_AREG>
713 // Optimize MOVE.L #<smalldata>,D0 to a MOVEQ
715 int m_move(WORD inst, WORD size)
717 // Cast the passed in value to an int
720 // Try to optimize to MOVEQ
721 // N.B.: We can get away with casting the uint64_t to a 32-bit value
722 // because it checks for a SIZL (i.e., a 32-bit value).
723 if (CHECK_OPTS(OPT_MOVEL_MOVEQ)
724 && (siz == SIZL) && (am0 == IMMED) && (am1 == DREG)
725 && ((a0exattr & (TDB | DEFINED)) == DEFINED)
726 && ((uint32_t)a0exval + 0x80 < 0x100))
728 m_moveq((WORD)0x7000, (WORD)0);
731 warn("move.l #size,dx converted to moveq");
735 if ((am0 < ABASE) && (am1 < ABASE)) // 68000 modes
737 inst |= siz_12[siz] | am_6[am1] | reg_9[a1reg] | am0 | a0reg;
745 ea1gen((WORD)siz | 0x8000); // Tell ea1gen we're move ea,ea
749 inst |= siz_12[siz] | reg_9[a1reg] | extra_addressing[am0 - ABASE];
766 // Handle MOVE <C_ALL030> <C_ALTDATA>
767 // MOVE <C_ALL030> <M_AREG>
769 int m_move30(WORD inst, WORD size)
772 inst |= siz_12[siz] | reg_9[a1reg & 7] | a0reg | extra_addressing[am0 - ABASE];
787 // move USP,An -- move An,USP
789 int m_usp(WORD inst, WORD siz)
794 inst |= a1reg; // USP, An
796 inst |= a0reg; // An, USP
807 int m_moveq(WORD inst, WORD siz)
811 // Arrange for future fixup
812 if (!(a0exattr & DEFINED))
814 AddFixup(FU_BYTE | FU_SEXT, sloc + 1, a0expr);
817 else if ((uint32_t)a0exval + 0x100 >= 0x200)
818 return error(range_error);
820 inst |= reg_9[a1reg] | (a0exval & 0xFF);
828 // movep Dn, disp(An) -- movep disp(An), Dn
830 int m_movep(WORD inst, WORD siz)
832 // Tell ea0gen to lay off the 0(a0) optimisations on this one
840 inst |= reg_9[a0reg] | a1reg;
850 inst |= reg_9[a1reg] | a0reg;
867 int m_br(WORD inst, WORD siz)
869 if (a0exattr & DEFINED)
871 if ((a0exattr & TDB) != cursect)
873 //printf("m_br(): a0exattr = %X, cursect = %X, a0exval = %X, sloc = %X\n", a0exattr, cursect, a0exval, sloc);
874 return error(rel_error);
877 uint32_t v = (uint32_t)a0exval - (sloc + 2);
879 // Optimize branch instr. size
882 if (CHECK_OPTS(OPT_BSR_BCC_S) && (v != 0) && ((v + 0x80) < 0x100))
889 warn("Bcc.w/BSR.w converted to .s");
896 if ((v + 0x8000) > 0x10000)
897 return error(range_error);
905 if (siz == SIZB || siz == SIZS)
907 if ((v + 0x80) >= 0x100)
908 return error(range_error);
915 if ((v + 0x8000) >= 0x10000)
916 return error(range_error);
924 else if (siz == SIZN)
927 if (siz == SIZB || siz == SIZS)
930 AddFixup(FU_BBRA | FU_PCREL | FU_SEXT, sloc, a0expr);
938 AddFixup(FU_WORD | FU_PCREL | FU_LBRA | FU_ISBRA, sloc, a0expr);
949 int m_addq(WORD inst, WORD siz)
951 inst |= siz_6[siz] | am1 | a1reg;
953 if (a0exattr & DEFINED)
955 if ((a0exval > 8) || (a0exval == 0)) // Range in 1..8
956 return error(range_error);
958 inst |= (a0exval & 7) << 9;
963 AddFixup(FU_QUICK, sloc, a0expr);
976 int m_trap(WORD inst, WORD siz)
980 if (a0exattr & DEFINED)
983 return error(abs_error);
986 return error(range_error);
992 return error(undef_error);
999 // movem <rlist>,ea -- movem ea,<rlist>
1001 int m_movem(WORD inst, WORD siz)
1009 return error("bad size suffix");
1016 // Handle #<expr>, ea
1019 if (abs_expr(&eval) != OK)
1022 if (eval >= 0x10000L)
1023 return error(range_error);
1029 if ((*tok >= KW_D0) && (*tok <= KW_A7))
1032 if (reglist(&rmask) < 0)
1037 return error("missing comma");
1042 inst |= am0 | a0reg;
1044 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
1045 return error("invalid addressing mode");
1047 // If APREDEC, reverse register mask
1053 for(i=0x8000; i; i>>=1, w>>=1)
1054 rmask = (WORD)((rmask << 1) | (w & 1));
1063 inst |= 0x0400 | am0 | a0reg;
1066 return error("missing comma");
1069 return error("missing register list");
1076 if (abs_expr(&eval) != OK)
1079 if (eval >= 0x10000)
1080 return error(range_error);
1084 else if (reglist(&rmask) < 0)
1087 if (!(amsktab[am0] & (C_CTRL | M_APOSTINC)))
1088 return error("invalid addressing mode");
1100 // CLR.x An ==> SUBA.x An,An
1102 int m_clra(WORD inst, WORD siz)
1104 inst |= a0reg | reg_9[a0reg] | lwsiz_8[siz];
1112 // CLR.L Dn ==> CLR.L An or MOVEQ #0,Dx
1114 int m_clrd(WORD inst, WORD siz)
1116 if (!CHECK_OPTS(OPT_CLR_DX))
1119 inst = (a0reg << 9) | B16(01110000, 00000000);
1127 ////////////////////////////////////////
1129 // 68020/30/40/60 instructions
1131 ////////////////////////////////////////
1136 int m_br30(WORD inst, WORD siz)
1138 if (a0exattr & DEFINED)
1140 if ((a0exattr & TDB) != cursect)
1141 return error(rel_error);
1143 uint32_t v = (uint32_t)a0exval - (sloc + 2);
1152 AddFixup(FU_LONG | FU_PCREL | FU_SEXT, sloc, a0expr);
1160 // bfchg, bfclr, bfexts, bfextu, bfffo, bfins, bfset
1161 // (68020, 68030, 68040)
1163 int m_bfop(WORD inst, WORD siz)
1165 if ((bfval1 > 31) || (bfval1 < 0))
1166 return error("bfxxx offset: immediate value must be between 0 and 31");
1168 // First instruction word - just the opcode and first EA
1169 // Note: both am1 is ORed because solely of bfins - maybe it's a good idea
1170 // to make a dedicated function for it?
1177 if (bfval2 > 31 || bfval2 < 0)
1178 return error("bfxxx width: immediate value must be between 0 and 31");
1180 // For Dw both immediate and register number are stuffed
1181 // into the same field O_o
1182 bfparam2 = (bfval2 << 0);
1186 bfparam1 = (bfval1 << 6);
1188 bfparam1 = bfval1 << 12;
1190 //D_word((inst | am0 | a0reg | am1 | a1reg));
1191 if (inst == B16(11101111, 11000000))
1193 // bfins special case
1194 D_word((inst | am1 | a1reg));
1198 D_word((inst | am0 | a0reg));
1201 ea0gen(siz); // Generate EA
1203 // Second instruction word - Dest register (if exists), Do, Offset, Dw, Width
1204 if (inst == B16(11101111, 11000000))
1206 // bfins special case
1207 inst = bfparam1 | bfparam2;
1210 inst |= a0reg << 12;
1216 inst = bfparam1 | bfparam2;
1222 inst |= a1reg << 12;
1232 // bkpt (68EC000, 68010, 68020, 68030, 68040, CPU32)
1234 int m_bkpt(WORD inst, WORD siz)
1238 if (a0exattr & DEFINED)
1241 return error(abs_error);
1244 return error(range_error);
1250 return error(undef_error);
1259 int m_callm(WORD inst, WORD siz)
1266 if (a0exattr & DEFINED)
1269 return error(abs_error);
1272 return error(range_error);
1274 inst = (uint16_t)a0exval;
1278 return error(undef_error);
1288 // cas (68020, 68030, 68040)
1290 int m_cas(WORD inst, WORD siz)
1296 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1297 return error(unsupport);
1312 return error("bad size suffix");
1317 if ((*tok < KW_D0) && (*tok > KW_D7))
1318 return error("CAS accepts only data registers");
1320 inst2 = (*tok++) & 7;
1323 return error("missing comma");
1326 if ((*tok < KW_D0) && (*tok > KW_D7))
1327 return error("CAS accepts only data registers");
1329 inst2 |= ((*tok++) & 7) << 6;
1332 return error("missing comma");
1335 if ((modes = amode(1)) < 0)
1339 return error("too many ea fields");
1342 return error("extra (unexpected) text found");
1344 // Reject invalid ea modes
1345 amsk = amsktab[am0];
1347 if ((amsk & (M_AIND | M_APOSTINC | M_APREDEC | M_ADISP | M_AINDEXED | M_ABSW | M_ABSL | M_ABASE | M_MEMPOST | M_MEMPRE)) == 0)
1348 return error("unsupported addressing mode");
1350 inst |= am0 | a0reg;
1360 // cas2 (68020, 68030, 68040)
1362 int m_cas2(WORD inst, WORD siz)
1366 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1367 return error(unsupport);
1382 return error("bad size suffix");
1387 if ((*tok < KW_D0) && (*tok > KW_D7))
1388 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1390 inst2 = (*tok++) & 7;
1393 return error("missing colon");
1396 if ((*tok < KW_D0) && (*tok > KW_D7))
1397 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1399 inst3 = (*tok++) & 7;
1402 return error("missing comma");
1405 if ((*tok < KW_D0) && (*tok > KW_D7))
1406 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1408 inst2 |= ((*tok++) & 7) << 6;
1411 return error("missing colon");
1414 if ((*tok < KW_D0) && (*tok > KW_D7))
1415 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1417 inst3 |= ((*tok++) & 7) << 6;
1420 return error("missing comma");
1424 return error("missing (");
1425 if ((*tok >= KW_D0) && (*tok <= KW_D7))
1426 inst2 |= (((*tok++) & 7) << 12) | (0 << 15);
1427 else if ((*tok >= KW_A0) && (*tok <= KW_A7))
1428 inst2 |= (((*tok++) & 7) << 12) | (1 << 15);
1430 return error("CAS accepts either data or address registers for Rn1:Rn2 pair");
1433 return error("missing (");
1436 return error("missing colon");
1440 return error("missing (");
1441 if ((*tok >= KW_D0) && (*tok <= KW_D7))
1442 inst3 |= (((*tok++) & 7) << 12) | (0 << 15);
1443 else if ((*tok >= KW_A0) && (*tok <= KW_A7))
1444 inst3 |= (((*tok++) & 7) << 12) | (1 << 15);
1446 return error("CAS accepts either data or address registers for Rn1:Rn2 pair");
1449 return error("missing (");
1452 return error("extra (unexpected) text found");
1463 // cmp2 (68020, 68030, 68040, CPU32)
1465 int m_cmp2(WORD inst, WORD siz)
1467 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1468 return error(unsupport);
1470 switch (siz & 0x000F)
1484 WORD flg = inst; // Save flag bits
1485 inst &= ~0x3F; // Clobber flag bits in instr
1487 // Install "standard" instr size bits
1493 // OR-in register number
1495 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1497 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1503 inst |= am1 | a1reg; // Get ea1 into instr
1504 D_word(inst); // Deposit instr
1506 // Generate ea0 if requested
1510 ea1gen(siz); // Generate ea1
1515 inst |= am0 | a0reg; // Get ea0 into instr
1516 D_word(inst); // Deposit instr
1517 ea0gen(siz); // Generate ea0
1519 // Generate ea1 if requested
1524 // If we're called from chk2 then bit 11 of size will be set. This is just
1525 // a dumb mechanism to pass this, required by the extension word. (You might
1526 // have noticed the siz & 15 thing above!)
1527 inst = (a1reg << 12) | (siz & (1 << 11));
1539 // chk2 (68020, 68030, 68040, CPU32)
1541 int m_chk2(WORD inst, WORD siz)
1543 return m_cmp2(inst, siz | (1 << 11));
1548 // cpbcc(68020, 68030, 68040 (FBcc), 68060 (FBcc)), pbcc (68851)
1550 int m_fpbr(WORD inst, WORD siz)
1553 if (a0exattr & DEFINED)
1555 if ((a0exattr & TDB) != cursect)
1556 return error(rel_error);
1558 uint32_t v = (uint32_t)a0exval - (sloc + 2);
1560 // Optimize branch instr. size
1563 if ((v != 0) && ((v + 0x8000) < 0x10000))
1573 if ((v + 0x8000) >= 0x10000)
1574 return error(range_error);
1582 else if (siz == SIZN)
1589 AddFixup(FU_LONG | FU_PCREL | FU_SEXT, sloc, a0expr);
1597 AddFixup(FU_WORD | FU_PCREL | FU_SEXT, sloc, a0expr);
1606 // cpbcc(68020, 68030, 68040 (FBcc), 68060 (FBcc))
1608 int m_cpbcc(WORD inst, WORD siz)
1610 if (!(activecpu & (CPU_68020 | CPU_68030)))
1611 return error(unsupport);
1613 return m_fpbr(inst, siz);
1618 // fbcc(6808X, 68040, 68060)
1620 int m_fbcc(WORD inst, WORD siz)
1623 return m_fpbr(inst, siz);
1628 // pbcc(68851 but let's assume 68020 only)
1630 int m_pbcc(WORD inst, WORD siz)
1633 return m_fpbr(inst, siz);
1638 // cpdbcc(68020, 68030)
1640 int m_cpdbr(WORD inst, WORD siz)
1645 WORD condition = inst & 0x1F; // Grab condition sneakily placed in the lower 5 bits of inst
1646 inst &= 0xFFE0; // And then mask them out - you ain't seen me, roit?
1648 inst |= (1 << 9); // Bolt on FPU id
1655 if (a1exattr & DEFINED)
1657 if ((a1exattr & TDB) != cursect)
1658 return error(rel_error);
1660 v = (uint32_t)a1exval - sloc;
1662 if (v + 0x8000 > 0x10000)
1663 return error(range_error);
1669 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
1679 // muls.l / divs.l / divu.l / mulu.l (68020+)
1681 int m_muls(WORD inst, WORD siz)
1683 if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1684 return error(unsupport);
1686 WORD flg = inst; // Save flag bits
1687 inst &= ~0x33F; // Clobber flag and extension bits in instr
1689 // Install "standard" instr size bits
1695 // OR-in register number
1697 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
1699 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
1702 // Regarding extension word: bit 11 is signed/unsigned selector
1703 // bit 10 is 32/64 bit selector
1704 // Both of these are packed in bits 9 and 8 of the instruction
1705 // field in 68ktab. Extra compilcations arise from the fact we
1706 // have to distinguish between divu/s.l Dn,Dm (which is encoded
1707 // as divu/s.l Dn,Dm:Dm) and divu/s.l Dn,Dm:Dx - the first is
1708 // 32 bit while the second 64 bit
1713 inst |= am1 | a1reg; // Get ea1 into instr
1714 D_word(inst); // Deposit instr
1718 inst = a1reg + (a2reg << 12) + ((flg & 0x200) << 2);
1720 inst = a1reg + (a2reg << 12) + ((flg & 0x300) << 2);
1724 // Generate ea0 if requested
1728 ea1gen(siz); // Generate ea1
1735 inst |= am0 | a0reg; // Get ea0 into instr
1736 D_word(inst); // Deposit instr
1740 inst = a1reg + (a2reg << 12) + ((flg & 0x200) << 2);
1742 inst = a1reg + (a2reg << 12) + ((flg & 0x300) << 2);
1746 ea0gen(siz); // Generate ea0
1748 // Generate ea1 if requested
1758 // move16 (ax)+,(ay)+
1760 int m_move16a(WORD inst, WORD siz)
1762 if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1763 return error(unsupport);
1767 inst = (1 << 15) + (a1reg << 12);
1775 // move16 with absolute address
1777 int m_move16b(WORD inst, WORD siz)
1779 if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1780 return error(unsupport);
1786 if (am0 == APOSTINC)
1789 return error("Wasn't this suppose to call m_move16a???");
1792 // move16 (ax)+,(xxx).L
1797 else if (am0 == ABSL)
1801 // move16 (xxx).L,(ax)+
1807 // move16 (xxx).L,(ax)
1812 else if (am0 == AIND)
1814 // move16 (ax),(xxx).L
1827 // pack/unpack (68020/68030/68040)
1829 int m_pack(WORD inst, WORD siz)
1834 return error("bad size suffix");
1836 if (*tok >= KW_D0 && *tok <= KW_D7)
1838 // Dx,Dy,#<adjustment>
1839 inst |= (0 << 3); // R/M
1840 inst |= (*tok++ & 7);
1842 if (*tok != ',' && tok[2] != ',')
1843 return error("missing comma");
1845 if (tok[1] < KW_D0 && tok[1] > KW_D7)
1846 return error(syntax_error);
1848 inst |= ((tok[1] & 7)<<9);
1851 // Fall through for adjustment (common in both valid cases)
1853 else if (*tok == '-')
1855 // -(Ax),-(Ay),#<adjustment>
1856 inst |= (1 << 3); // R/M
1857 tok++; // eat the minus
1859 if ((*tok != '(') && (tok[2]!=')') && (tok[3]!=',') && (tok[4] != '-') && (tok[5] != '(') && (tok[7] != ')') && (tok[8] != ','))
1860 return error(syntax_error);
1862 if (tok[1] < KW_A0 && tok[1] > KW_A7)
1863 return error(syntax_error);
1865 if (tok[5] < KW_A0 && tok[6] > KW_A7)
1866 return error(syntax_error);
1868 inst |= ((tok[1] & 7) << 0);
1869 inst |= ((tok[6] & 7) << 9);
1872 // Fall through for adjustment (common in both valid cases)
1875 return error("invalid syntax");
1877 if ((*tok != CONST) && (*tok != SYMBOL) && (*tok != '-'))
1878 return error(syntax_error);
1880 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
1883 if ((a0exattr & DEFINED) == 0)
1884 return error(undef_error);
1886 if (a0exval + 0x8000 > 0x10000)
1890 return error(extra_stuff);
1892 D_word((a0exval & 0xFFFF));
1901 int m_rtm(WORD inst, WORD siz)
1909 else if (am0 == AREG)
1911 inst |= (1 << 3) + a0reg;
1914 return error("rtm only allows data or address registers.");
1925 int m_rtd(WORD inst, WORD siz)
1929 if (a0exattr & DEFINED)
1932 return error(abs_error);
1934 if ((a0exval + 0x8000) <= 0x7FFF)
1935 return error(range_error);
1941 return error(undef_error);
1950 int m_trapcc(WORD inst, WORD siz)
1958 else if (am0 == IMMED)
1962 if (a0exval < 0x10000)
1969 return error("Immediate value too big");
1979 return error("Invalid parameter for trapcc");
1986 // cinvl/p/a (68040/68060)
1988 int m_cinv(WORD inst, WORD siz)
1993 inst |= (0 << 6) | (a1reg);
1997 inst |= (2 << 6) | (a1reg);
2000 inst |= (1 << 6) | (a1reg);
2003 inst |= (3 << 6) | (a1reg);
2012 int m_fpusavrest(WORD inst, WORD siz)
2014 inst |= am0 | a0reg;
2023 // cpSAVE/cpRESTORE (68020, 68030)
2025 int m_cprest(WORD inst, WORD siz)
2027 if (activecpu & !(CPU_68020 | CPU_68030))
2028 return error(unsupport);
2030 return m_fpusavrest(inst, siz);
2036 // FSAVE/FRESTORE (68040, 68060)
2038 int m_frestore(WORD inst, WORD siz)
2040 if ((!(activecpu & (CPU_68040 | CPU_68060))) ||
2041 (activefpu&(FPU_68881 | FPU_68882)))
2042 return error(unsupport);
2044 return m_fpusavrest(inst, siz);
2049 // movec (68010, 68020, 68030, 68040, 68060, CPU32)
2051 int m_movec(WORD inst, WORD siz)
2055 if (am0 == DREG || am0 == AREG)
2063 inst = (0 << 15) + (a0reg << 12) + CREGlut[a1reg];
2068 inst = (1 << 15) + (a0reg << 12) + CREGlut[a1reg];
2079 inst = (0 << 15) + (a1reg << 12) + CREGlut[a0reg];
2084 inst = (1 << 15) + (a1reg << 12) + CREGlut[a0reg];
2094 // moves (68010, 68020, 68030, 68040, CPU32)
2096 int m_moves(WORD inst, WORD siz)
2098 if (activecpu & !(CPU_68020 | CPU_68030 | CPU_68040))
2099 return error(unsupport);
2103 else if (siz == SIZL)
2110 inst |= am1 | a1reg;
2112 inst = (a0reg << 12) | (1 << 11) | (0 << 15);
2115 else if (am0 == AREG)
2117 inst |= am1 | a1reg;
2119 inst = (a0reg << 12) | (1 << 11) | (1 << 15);
2126 inst |= am0 | a0reg;
2128 inst = (a1reg << 12) | (0 << 11) | (0 << 15);
2133 inst |= am0 | a0reg;
2135 inst = (a1reg << 12) | (0 << 11) | (1 << 15);
2145 // pflusha (68030, 68040)
2147 int m_pflusha(WORD inst, WORD siz)
2149 if (activecpu == CPU_68030)
2152 inst = (1 << 13) | (1 << 10) | (0 << 5) | 0;
2156 else if (activecpu == CPU_68040)
2158 inst = B16(11110101, 00011000);
2163 return error(unsupport);
2170 // pflush (68030, 68040, 68060)
2172 int m_pflush(WORD inst, WORD siz)
2174 if (activecpu == CPU_68030)
2177 // PFLUSH FC, MASK, < ea >
2185 if (*tok != CONST && *tok != SYMBOL)
2186 return error("function code should be an expression");
2188 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2191 if ((a0exattr & DEFINED) == 0)
2192 return error("function code immediate should be defined");
2195 return error("function code out of range (0-7)");
2197 fc = (uint16_t)a0exval;
2207 fc = (1 << 4) | (*tok++ & 7);
2218 return error(syntax_error);
2222 return error("comma exptected");
2225 return error("mask should be an immediate value");
2227 if (*tok != CONST && *tok != SYMBOL)
2228 return error("mask is supposed to be immediate");
2230 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2233 if ((a0exattr & DEFINED) == 0)
2234 return error("mask immediate value should be defined");
2237 return error("function code out of range (0-7)");
2239 mask = (uint16_t)a0exval << 5;
2245 inst = (1 << 13) | fc | mask | (4 << 10);
2249 else if (*tok == ',')
2251 // PFLUSH FC, MASK, < ea >
2254 if (amode(0) == ERROR)
2258 return error(extra_stuff);
2260 if (am0 == AIND || am0 == ABSW || am0 == ABSL || am0 == ADISP || am0 == ADISP || am0 == AINDEXED || am0 == ABASE || am0 == MEMPOST || am0 == MEMPRE)
2262 inst |= am0 | a0reg;
2264 inst = (1 << 13) | fc | mask | (6 << 10);
2270 return error("unsupported addressing mode");
2274 return error(syntax_error);
2278 else if (activecpu == CPU_68040 || activecpu == CPU_68060)
2282 if (*tok != '(' && tok[2] != ')')
2283 return error(syntax_error);
2285 if (tok[1] < KW_A0 && tok[1] > KW_A7)
2286 return error("expected (An)");
2288 if ((inst & 7) == 7)
2289 // With pflushn/pflush there's no easy way to distinguish between
2290 // the two in 68040 mode. Ideally the opcode bitfields would have
2291 // been hardcoded in 68ktab but there is aliasing between 68030
2292 // and 68040 opcode. So we just set the 3 lower bits to 1 in
2293 // pflushn inside 68ktab and detect it here.
2294 inst = (inst & 0xff8) | 8;
2296 inst |= (tok[1] & 7) | (5 << 8);
2299 return error(extra_stuff);
2304 return error(unsupport);
2311 // pflushan (68040, 68060)
2313 int m_pflushan(WORD inst, WORD siz)
2315 if (activecpu == CPU_68040 || activecpu == CPU_68060)
2325 int m_pflushr(WORD inst, WORD siz)
2329 WORD flg = inst; // Save flag bits
2330 inst &= ~0x3F; // Clobber flag bits in instr
2332 // Install "standard" instr size bits
2338 // OR-in register number
2340 inst |= reg_9[a1reg]; // ea1reg in bits 9..11
2342 inst |= reg_9[a0reg]; // ea0reg in bits 9..11
2348 inst |= am1 | a1reg; // Get ea1 into instr
2349 D_word(inst); // Deposit instr
2351 // Generate ea0 if requested
2355 ea1gen(siz); // Generate ea1
2360 inst |= am0 | a0reg; // Get ea0 into instr
2361 D_word(inst); // Deposit instr
2362 ea0gen(siz); // Generate ea0
2364 // Generate ea1 if requested
2369 D_word(B16(10100000, 00000000));
2375 // ploadr, ploadw (68030)
2377 int m_pload(WORD inst, WORD siz, WORD extension)
2379 // TODO: 68851 support is not added yet.
2380 // None of the ST series of computers had a 68020 + 68851 socket and since
2381 // this is an Atari targetted assembler...
2390 if (a0reg == KW_SFC - KW_SFC)
2392 else if (a0reg == KW_DFC - KW_SFC)
2395 return error("illegal control register specified");
2399 inst = (1 << 3) | a0reg;
2402 if ((a0exattr & DEFINED) == 0)
2403 return error("constant value must be defined");
2406 return error("constant value must be between 0 and 7");
2408 inst = (2 << 3) | (uint16_t)a0exval;
2412 inst |= extension | (1 << 13);
2421 int m_ploadr(WORD inst, WORD siz)
2423 return m_pload(inst, siz, 1 << 9);
2427 int m_ploadw(WORD inst, WORD siz)
2429 return m_pload(inst, siz, 0 << 9);
2434 // pmove (68030/68851)
2436 int m_pmove(WORD inst, WORD siz)
2440 // TODO: 68851 support is not added yet. None of the ST series of
2441 // computers had a 68020 + 68851 socket and since this is an Atari
2442 // targetted assembler.... (same for 68EC030)
2445 inst2 = inst & (1 << 8); // Copy the flush bit over to inst2 in case we're called from m_pmovefd
2446 inst &= ~(1 << 8); // And mask it out
2453 else if (am1 == CREG)
2459 return error("pmove sez: Wut?");
2461 // The instruction is a quad-word (8 byte) operation
2462 // for the CPU root pointer and the supervisor root pointer.
2463 // It is a long-word operation for the translation control register
2464 // and the transparent translation registers(TT0 and TT1).
2465 // It is a word operation for the MMU status register.
2467 if (((reg == (KW_URP - KW_SFC)) || (reg == (KW_SRP - KW_SFC)))
2468 && ((siz != SIZD) && (siz != SIZN)))
2469 return error(siz_error);
2471 if (((reg == (KW_TC - KW_SFC)) || (reg == (KW_TT0 - KW_SFC)) || (reg == (KW_TT1 - KW_SFC)))
2472 && ((siz != SIZL) && (siz != SIZN)))
2473 return error(siz_error);
2475 if ((reg == (KW_MMUSR - KW_SFC)) && ((siz != SIZW) && (siz != SIZN)))
2476 return error(siz_error);
2480 inst |= am1 | a1reg;
2483 else if (am1 == CREG)
2485 inst |= am0 | a0reg;
2489 switch (reg + KW_SFC)
2492 inst2 |= (0 << 10) + (1 << 14); break;
2494 inst2 |= (2 << 10) + (1 << 14); break;
2496 inst2 |= (3 << 10) + (1 << 14); break;
2498 inst2 |= (2 << 10) + (0 << 13); break;
2500 inst2 |= (3 << 10) + (0 << 13); break;
2503 inst2 |= (1 << 9) + (3 << 13);
2505 inst2 |= (0 << 9) + (3 << 13);
2508 return error("unsupported register");
2516 else if (am1 == CREG)
2526 int m_pmovefd(WORD inst, WORD siz)
2530 return m_pmove(inst | (1 << 8), siz);
2537 int m_ptrapcc(WORD inst, WORD siz)
2540 // We stash the 5 condition bits inside the opcode in 68ktab (bits 0-4),
2541 // so we need to extract them first and fill in the clobbered bits.
2542 WORD opcode = inst & 0x1F;
2543 inst = (inst & 0xFFE0) | (0x18);
2552 else if (siz == SIZL)
2559 else if (siz == SIZN)
2571 // ptestr, ptestw (68030, 68040)
2572 // TODO See comment on m_pmove about 68851 support
2573 // TODO quite a good chunk of the 030 code is copied from m_pload, perhaps merge these somehow?
2575 int m_ptest(WORD inst, WORD siz, WORD extension)
2579 if (activecpu != CPU_68030 && activecpu != CPU_68040)
2580 return error(unsupport);
2582 if (activecpu == CPU_68030)
2590 if (a0reg == KW_SFC - KW_SFC)
2592 else if (a0reg == KW_DFC - KW_SFC)
2595 return error("illegal control register specified");
2598 extension |= (1 << 3) | a0reg;
2601 if ((a0exattr & DEFINED) == 0)
2602 return error("constant value must be defined");
2605 return error("constant value must be between 0 and 7");
2607 extension |= (2 << 3) | (uint16_t)a0exval;
2611 // Operand 3 must be an immediate
2615 return error("ptest level must be immediate");
2617 // Let's be a bit inflexible here and demand that this
2618 // is fully defined at this stage. Otherwise we'd have
2619 // to arrange for a bitfield fixup, which would mean
2620 // polluting the bitfields and codebase with special
2621 // cases that might most likely never be used.
2622 // So if anyone gets bit by this: sorry for being a butt!
2623 if (abs_expr(&eval) != OK)
2624 return OK; // We're returning OK because error() has already been called and error count has been increased
2627 return error("ptest level must be between 0 and 7");
2629 extension |= eval << 10;
2631 // Operand 4 is optional and must be an address register
2637 if ((*tok >= KW_A0) && (*tok <= KW_A7))
2639 extension |= (1 << 8) | ((*tok++ & 7) << 4);
2643 return error("fourth parameter must be an address register");
2653 return error("Not implemented yet.");
2658 int m_ptestr(WORD inst, WORD siz)
2660 return m_ptest(inst, siz, (1 << 15) | (0 << 9));
2663 int m_ptestw(WORD inst, WORD siz)
2665 return m_ptest(inst, siz, (1 << 15) | (1 << 9));
2668 //////////////////////////////////////////////////////////////////////////////
2670 // 68020/30/40/60 instructions
2671 // Note: the map of which instructions are allowed on which CPUs came from the
2672 // 68060 manual, section D-1 (page 392 of the PDF). The current implementation
2673 // is missing checks for the EC models which have a simplified FPU.
2675 //////////////////////////////////////////////////////////////////////////////
2678 #define FPU_NOWARN 0
2683 // Generate a FPU opcode
2685 static inline int gen_fpu(WORD inst, WORD siz, WORD opmode, WORD emul)
2687 if (am0 < AM_NONE) // Check first operand for ea or fp - is this right?
2689 inst |= (1 << 9); // Bolt on FPU id
2692 //if (am0 == DREG || am0 == AREG)
2696 inst = 1 << 14; // R/M field (we have ea so have to set this to 1)
2700 case SIZB: inst |= (6 << 10); break;
2701 case SIZW: inst |= (4 << 10); break;
2702 case SIZL: inst |= (0 << 10); break;
2704 case SIZS: inst |= (1 << 10); break;
2705 case SIZD: inst |= (5 << 10); break;
2706 case SIZX: inst |= (2 << 10); break;
2711 warn("This encoding will cause an unimplemented data type exception in the MC68040 to allow emulation in software.");
2715 return error("Something bad happened, possibly, in gen_fpu.");
2719 inst |= (a1reg << 7);
2726 inst |= (1 << 9); // Bolt on FPU id
2730 inst |= (a1reg << 7);
2735 if ((emul & FPU_FPSP) && (activefpu == (FPU_68040 | FPU_68060)))
2736 warn("Instruction is emulated in 68040/060");
2743 // fabs (6888X, 68040FPSP, 68060FPSP)
2745 int m_fabs(WORD inst, WORD siz)
2748 return gen_fpu(inst, siz, B8(00011000), FPU_NOWARN);
2753 // fsabs (68040, 68060)
2755 int m_fsabs(WORD inst, WORD siz)
2758 if (activefpu == FPU_68040)
2759 return gen_fpu(inst, siz, B8(01011000), FPU_NOWARN);
2761 return error("Unsupported in current FPU");
2766 // fdabs (68040, 68060)
2768 int m_fdabs(WORD inst, WORD siz)
2770 if (activefpu == FPU_68040)
2771 return gen_fpu(inst, siz, B8(01011100), FPU_NOWARN);
2773 return error("Unsupported in current FPU");
2778 // facos (6888X, 68040FPSP, 68060FPSP)
2780 int m_facos(WORD inst, WORD siz)
2783 return gen_fpu(inst, siz, B8(00011100), FPU_FPSP);
2788 // fadd (6888X, 68040, 68060)
2790 int m_fadd(WORD inst, WORD siz)
2793 return gen_fpu(inst, siz, B8(00100010), FPU_NOWARN);
2798 // fsadd (68040, 68060)
2800 int m_fsadd(WORD inst, WORD siz)
2802 if (activefpu & (FPU_68040 | FPU_68060))
2803 return gen_fpu(inst, siz, B8(01100010), FPU_NOWARN);
2805 return error("Unsupported in current FPU");
2812 int m_fdadd(WORD inst, WORD siz)
2814 if (activefpu & (FPU_68040 | FPU_68060))
2815 return gen_fpu(inst, siz, B8(01100110), FPU_NOWARN);
2817 return error("Unsupported in current FPU");
2822 // fasin (6888X, 68040FPSP, 68060FPSP)
2824 int m_fasin(WORD inst, WORD siz)
2827 return gen_fpu(inst, siz, B8(00001100), FPU_FPSP);
2832 // fatan (6888X, 68040FPSP, 68060FPSP)
2834 int m_fatan(WORD inst, WORD siz)
2837 return gen_fpu(inst, siz, B8(00001010), FPU_FPSP);
2842 // fatanh (6888X, 68040FPSP, 68060FPSP)
2844 int m_fatanh(WORD inst, WORD siz)
2847 return gen_fpu(inst, siz, B8(00001101), FPU_FPSP);
2852 // fcmp (6888X, 68040, 68060)
2854 int m_fcmp(WORD inst, WORD siz)
2857 return gen_fpu(inst, siz, B8(00111000), FPU_FPSP);
2862 // fcos (6888X, 68040FPSP, 68060FPSP)
2864 int m_fcos(WORD inst, WORD siz)
2867 return gen_fpu(inst, siz, B8(00011101), FPU_FPSP);
2872 // fcosh (6888X, 68040FPSP, 68060FPSP)
2874 int m_fcosh(WORD inst, WORD siz)
2877 return gen_fpu(inst, siz, B8(00011001), FPU_FPSP);
2882 // fdbcc (6888X, 68040, 68060FPSP)
2884 int m_fdbcc(WORD inst, WORD siz)
2887 WORD opcode = inst & 0x3F; // Grab conditional bitfield
2897 if (a1exattr & DEFINED)
2899 if ((a1exattr & TDB) != cursect)
2900 return error(rel_error);
2902 uint32_t v = (uint32_t)a1exval - sloc;
2904 if ((v + 0x8000) > 0x10000)
2905 return error(range_error);
2911 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
2915 if (activefpu == FPU_68060)
2916 warn("Instruction is emulated in 68060");
2923 // fdiv (6888X, 68040, 68060)
2925 int m_fdiv(WORD inst, WORD siz)
2928 return gen_fpu(inst, siz, B8(00100000), FPU_NOWARN);
2933 // fsdiv (68040, 68060)
2935 int m_fsdiv(WORD inst, WORD siz)
2937 if (activefpu & (FPU_68040 | FPU_68060))
2938 return gen_fpu(inst, siz, B8(01100000), FPU_NOWARN);
2940 return error("Unsupported in current FPU");
2945 // fddiv (68040, 68060)
2947 int m_fddiv(WORD inst, WORD siz)
2949 if (activefpu & (FPU_68040 | FPU_68060))
2950 return gen_fpu(inst, siz, B8(01100100), FPU_NOWARN);
2952 return error("Unsupported in current FPU");
2957 // fetox (6888X, 68040FPSP, 68060FPSP)
2959 int m_fetox(WORD inst, WORD siz)
2962 return gen_fpu(inst, siz, B8(00010000), FPU_FPSP);
2967 // fetoxm1 (6888X, 68040FPSP, 68060FPSP)
2969 int m_fetoxm1(WORD inst, WORD siz)
2972 return gen_fpu(inst, siz, B8(00001000), FPU_FPSP);
2977 // fgetexp (6888X, 68040FPSP, 68060FPSP)
2979 int m_fgetexp(WORD inst, WORD siz)
2982 return gen_fpu(inst, siz, B8(00011110), FPU_FPSP);
2987 // fgetman (6888X, 68040FPSP, 68060FPSP)
2989 int m_fgetman(WORD inst, WORD siz)
2992 return gen_fpu(inst, siz, B8(00011111), FPU_FPSP);
2997 // fint (6888X, 68040FPSP, 68060)
2999 int m_fint(WORD inst, WORD siz)
3002 // special case - fint fpx = fint fpx,fpx
3005 if (activefpu == FPU_68040)
3006 warn("Instruction is emulated in 68040");
3008 return gen_fpu(inst, siz, B8(00000001), FPU_NOWARN);
3013 // fintrz (6888X, 68040FPSP, 68060)
3015 int m_fintrz(WORD inst, WORD siz)
3018 // special case - fintrz fpx = fintrz fpx,fpx
3021 if (activefpu == FPU_68040)
3022 warn("Instruction is emulated in 68040");
3024 return gen_fpu(inst, siz, B8(00000011), FPU_NOWARN);
3029 // flog10 (6888X, 68040FPSP, 68060FPSP)
3031 int m_flog10(WORD inst, WORD siz)
3034 return gen_fpu(inst, siz, B8(00010101), FPU_FPSP);
3039 // flog2 (6888X, 68040FPSP, 68060FPSP)
3041 int m_flog2(WORD inst, WORD siz)
3044 return gen_fpu(inst, siz, B8(00010110), FPU_FPSP);
3049 // flogn (6888X, 68040FPSP, 68060FPSP)
3051 int m_flogn(WORD inst, WORD siz)
3054 return gen_fpu(inst, siz, B8(00010100), FPU_FPSP);
3059 // flognp1 (6888X, 68040FPSP, 68060FPSP)
3061 int m_flognp1(WORD inst, WORD siz)
3064 return gen_fpu(inst, siz, B8(00000110), FPU_FPSP);
3069 // fmod (6888X, 68040FPSP, 68060FPSP)
3071 int m_fmod(WORD inst, WORD siz)
3074 return gen_fpu(inst, siz, B8(00100001), FPU_FPSP);
3079 // fmove (6888X, 68040, 68060)
3081 int m_fmove(WORD inst, WORD siz)
3086 if ((am0 == FREG) && (am1 < AM_USP))
3090 inst |= am1 | a1reg;
3099 case SIZB: inst |= (6 << 10); break;
3100 case SIZW: inst |= (4 << 10); break;
3101 case SIZL: inst |= (0 << 10); break;
3103 case SIZS: inst |= (1 << 10); break;
3104 case SIZD: inst |= (5 << 10); break;
3105 case SIZX: inst |= (2 << 10); break;
3106 case SIZP: inst |= (3 << 10);
3107 // In P size we have 2 cases: {#k} where k is immediate
3108 // and {Dn} where Dn=Data register
3113 inst |= bfval1 << 4;
3118 if (bfval1 > 63 && bfval1 < -64)
3119 return error("K-factor must be between -64 and 63");
3121 inst |= bfval1 & 127;
3126 return error("Something bad happened, possibly.");
3130 // Destination specifier
3131 inst |= (a0reg << 7);
3139 else if ((am0 < AM_USP) && (am1 == FREG))
3144 inst |= am0 | a0reg;
3153 case SIZB: inst |= (6 << 10); break;
3154 case SIZW: inst |= (4 << 10); break;
3155 case SIZL: inst |= (0 << 10); break;
3157 case SIZS: inst |= (1 << 10); break;
3158 case SIZD: inst |= (5 << 10); break;
3159 case SIZX: inst |= (2 << 10); break;
3160 case SIZP: inst |= (3 << 10); break;
3162 return error("Something bad happened, possibly.");
3166 // Destination specifier
3167 inst |= (a1reg << 7);
3175 else if ((am0 == FREG) && (am1 == FREG))
3177 // register-to-register
3178 // Essentially ea to register with R/0=0
3187 if (siz != SIZX && siz != SIZN)
3188 return error("Invalid size");
3191 inst |= (a0reg << 10);
3193 // Destination register
3194 inst |= (a1reg << 7);
3204 // fmove (6888X, 68040, 68060)
3206 int m_fmovescr(WORD inst, WORD siz)
3210 // Move Floating-Point System Control Register (FPCR)
3214 if ((am0 == FPSCR) && (am1 < AM_USP))
3216 inst |= am1 | a1reg;
3218 inst = (1 << 13) + (1 << 15);
3224 else if ((am1 == FPSCR) && (am0 < AM_USP))
3226 inst |= am0 | a0reg;
3228 inst = (0 << 13) + (1 << 15);
3235 return error("m_fmovescr says: wut?");
3239 // fsmove/fdmove (68040, 68060)
3241 int m_fsmove(WORD inst, WORD siz)
3243 if (!(activefpu & (FPU_68040 | FPU_68060)))
3244 return error("Unsupported in current FPU");
3246 return gen_fpu(inst, siz, B8(01100100), FPU_FPSP);
3250 int m_fdmove(WORD inst, WORD siz)
3252 if (!(activefpu & (FPU_68040 | FPU_68060)))
3253 return error("Unsupported in current FPU");
3255 return gen_fpu(inst, siz, B8(01100100), FPU_FPSP);
3260 // fmovecr (6888X, 68040FPSP, 68060FPSP)
3262 int m_fmovecr(WORD inst, WORD siz)
3272 if (activefpu == FPU_68040)
3273 warn("Instruction is emulated in 68040/060");
3280 // fmovem (6888X, 68040, 68060FPSP)
3282 int m_fmovem(WORD inst, WORD siz)
3289 if (siz == SIZX || siz == SIZN)
3291 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
3293 // fmovem.x <rlist>,ea
3294 if (fpu_reglist_left(®mask) < 0)
3298 return error("missing comma");
3303 inst |= am0 | a0reg;
3305 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3306 return error("invalid addressing mode");
3309 inst = (1 << 15) | (1 << 14) | (1 << 13) | (0 << 11) | regmask;
3314 else if ((*tok >= KW_D0) && (*tok <= KW_D7))
3317 datareg = (*tok++ & 7) << 10;
3320 return error("missing comma");
3325 inst |= am0 | a0reg;
3327 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3328 return error("invalid addressing mode");
3330 // Quote from the 060 manual:
3331 // "[..] when the processor attempts an FMOVEM.X instruction using a dynamic register list."
3332 if (activefpu == FPU_68060)
3333 warn("Instruction is emulated in 68060");
3336 inst = (1 << 15) | (1 << 14) | (1 << 13) | (1 << 11) | (datareg << 4);
3347 inst |= am0 | a0reg;
3350 return error("missing comma");
3352 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
3354 // fmovem.x ea,<rlist>
3355 if (fpu_reglist_right(®mask) < 0)
3359 inst = (1 << 15) | (1 << 14) | (0 << 13) | (2 << 11) | regmask;
3367 datareg = (*tok++ & 7) << 10;
3369 // Quote from the 060 manual:
3370 // "[..] when the processor attempts an FMOVEM.X instruction using a dynamic register list."
3371 if (activefpu == FPU_68060)
3372 warn("Instruction is emulated in 68060");
3375 inst = (1 << 15) | (1 << 14) | (0 << 13) | (3 << 11) | (datareg << 4);
3382 else if (siz == SIZL)
3384 if ((*tok == KW_FPCR) || (*tok == KW_FPSR) || (*tok == KW_FPIAR))
3386 // fmovem.l <rlist>,ea
3387 regmask = (1 << 15) | (1 << 13);
3388 int no_control_regs = 0;
3391 if (*tok == KW_FPCR)
3393 regmask |= (1 << 12);
3399 if (*tok == KW_FPSR)
3401 regmask |= (1 << 11);
3407 if (*tok == KW_FPIAR)
3409 regmask |= (1 << 10);
3415 if ((*tok == '/') || (*tok == '-'))
3422 return error("missing comma");
3427 // Quote from the 060 manual:
3428 // "[..] when the processor attempts to execute an FMOVEM.L instruction with
3429 // an immediate addressing mode to more than one floating - point
3430 // control register (FPCR, FPSR, FPIAR)[..]"
3431 if (activefpu == FPU_68060)
3432 if (no_control_regs > 1 && am0 == IMMED)
3433 warn("Instruction is emulated in 68060");
3435 inst |= am0 | a0reg;
3442 // fmovem.l ea,<rlist>
3446 inst |= am0 | a0reg;
3449 return error("missing comma");
3451 regmask = (1 << 15) | (0 << 13);
3454 if (*tok == KW_FPCR)
3456 regmask |= (1 << 12);
3461 if (*tok == KW_FPSR)
3463 regmask |= (1 << 11);
3468 if (*tok == KW_FPIAR)
3470 regmask |= (1 << 10);
3475 if ((*tok == '/') || (*tok == '-'))
3482 return error("extra (unexpected) text found");
3484 inst |= am0 | a0reg;
3491 return error("bad size suffix");
3498 // fmul (6888X, 68040, 68060)
3500 int m_fmul(WORD inst, WORD siz)
3503 return gen_fpu(inst, siz, B8(00100011), FPU_NOWARN);
3508 // fsmul (68040, 68060)
3510 int m_fsmul(WORD inst, WORD siz)
3512 if (activefpu & (FPU_68040 | FPU_68060))
3513 return gen_fpu(inst, siz, B8(01100011), FPU_NOWARN);
3515 return error("Unsupported in current FPU");
3522 int m_fdmul(WORD inst, WORD siz)
3524 if (activefpu & (FPU_68040 | FPU_68060))
3525 return gen_fpu(inst, siz, B8(01100111), FPU_NOWARN);
3527 return error("Unsupported in current FPU");
3532 // fneg (6888X, 68040, 68060)
3534 int m_fneg(WORD inst, WORD siz)
3541 return gen_fpu(inst, siz, B8(00011010), FPU_NOWARN);
3544 return gen_fpu(inst, siz, B8(00011010), FPU_NOWARN);
3549 // fsneg (68040, 68060)
3551 int m_fsneg(WORD inst, WORD siz)
3553 if (activefpu & (FPU_68040 | FPU_68060))
3558 return gen_fpu(inst, siz, B8(01011010), FPU_NOWARN);
3561 return gen_fpu(inst, siz, B8(01011010), FPU_NOWARN);
3564 return error("Unsupported in current FPU");
3569 // fdneg (68040, 68060)
3571 int m_fdneg(WORD inst, WORD siz)
3573 if (activefpu & (FPU_68040 | FPU_68060))
3578 return gen_fpu(inst, siz, B8(01011110), FPU_NOWARN);
3581 return gen_fpu(inst, siz, B8(01011110), FPU_NOWARN);
3584 return error("Unsupported in current FPU");
3589 // fnop (6888X, 68040, 68060)
3591 int m_fnop(WORD inst, WORD siz)
3594 return gen_fpu(inst, siz, B8(00000000), FPU_NOWARN);
3599 // frem (6888X, 68040FPSP, 68060FPSP)
3601 int m_frem(WORD inst, WORD siz)
3604 return gen_fpu(inst, siz, B8(00100101), FPU_FPSP);
3609 // fscale (6888X, 68040FPSP, 68060FPSP)
3611 int m_fscale(WORD inst, WORD siz)
3614 return gen_fpu(inst, siz, B8(00100110), FPU_FPSP);
3619 // FScc (6888X, 68040, 68060), cpScc (68851, 68030), PScc (68851)
3620 // TODO: Add check for PScc to ensure 68020+68851 active
3621 // TODO: Add check for cpScc to ensure 68020+68851, 68030
3623 int m_fscc(WORD inst, WORD siz)
3627 // We stash the 5 condition bits inside the opcode in 68ktab (bits 4-0),
3628 // so we need to extract them first and fill in the clobbered bits.
3629 WORD opcode = inst & 0x1F;
3631 inst |= am0 | a0reg;
3635 if (activefpu == FPU_68060)
3636 warn("Instruction is emulated in 68060");
3642 // fsgldiv (6888X, 68040FPSP, 68060FPSP)
3644 int m_fsgldiv(WORD inst, WORD siz)
3647 return gen_fpu(inst, siz, B8(00100100), FPU_FPSP);
3652 // fsglmul (6888X, 68040, 68060FPSP)
3654 int m_fsglmul(WORD inst, WORD siz)
3657 return gen_fpu(inst, siz, B8(00100111), FPU_FPSP);
3662 // fsin (6888X, 68040FPSP, 68060FPSP)
3664 int m_fsin(WORD inst, WORD siz)
3667 return gen_fpu(inst, siz, B8(00001110), FPU_FPSP);
3672 // fsincos (6888X, 68040FPSP, 68060FPSP)
3674 int m_fsincos(WORD inst, WORD siz)
3678 // Swap a1reg, a2reg as a2reg should be stored in the bitfield gen_fpu
3685 if (gen_fpu(inst, siz, B8(00110000), FPU_FPSP) == OK)
3696 // fsinh (6888X, 68040FPSP, 68060FPSP)
3698 int m_fsinh(WORD inst, WORD siz)
3701 return gen_fpu(inst, siz, B8(00000010), FPU_FPSP);
3706 // fsqrt (6888X, 68040, 68060)
3708 int m_fsqrt(WORD inst, WORD siz)
3711 return gen_fpu(inst, siz, B8(00000100), FPU_NOWARN);
3716 // fsfsqrt (68040, 68060)
3718 int m_fsfsqrt(WORD inst, WORD siz)
3720 if (activefpu & (FPU_68040 | FPU_68060))
3721 return gen_fpu(inst, siz, B8(01000001), FPU_NOWARN);
3723 return error("Unsupported in current FPU");
3728 // fdfsqrt (68040, 68060)
3730 int m_fdfsqrt(WORD inst, WORD siz)
3732 if (activefpu & (FPU_68040 | FPU_68060))
3733 return gen_fpu(inst, siz, B8(01000101), FPU_NOWARN);
3735 return error("Unsupported in current FPU");
3740 // fsub (6888X, 68040, 68060)
3742 int m_fsub(WORD inst, WORD siz)
3745 return gen_fpu(inst, siz, B8(00101000), FPU_NOWARN);
3750 // fsfsub (68040, 68060)
3752 int m_fsfsub(WORD inst, WORD siz)
3754 if (activefpu & (FPU_68040 | FPU_68060))
3755 return gen_fpu(inst, siz, B8(01101000), FPU_NOWARN);
3757 return error("Unsupported in current FPU");
3762 // fdfsub (68040, 68060)
3764 int m_fdsub(WORD inst, WORD siz)
3766 if (activefpu & (FPU_68040 | FPU_68060))
3767 return gen_fpu(inst, siz, B8(01101100), FPU_NOWARN);
3769 return error("Unsupported in current FPU");
3774 // ftan (6888X, 68040FPSP, 68060FPSP)
3776 int m_ftan(WORD inst, WORD siz)
3779 return gen_fpu(inst, siz, B8(00001111), FPU_FPSP);
3784 // ftanh (6888X, 68040FPSP, 68060FPSP)
3786 int m_ftanh(WORD inst, WORD siz)
3789 return gen_fpu(inst, siz, B8(00001001), FPU_FPSP);
3794 // ftentox (6888X, 68040FPSP, 68060FPSP)
3796 int m_ftentox(WORD inst, WORD siz)
3799 return gen_fpu(inst, siz, B8(00010010), FPU_FPSP);
3804 // FTRAPcc (6888X, 68040, 68060FPSP)
3806 int m_ftrapcc(WORD inst, WORD siz)
3810 // We stash the 5 condition bits inside the opcode in 68ktab (bits 3-7),
3811 // so we need to extract them first and fill in the clobbered bits.
3812 WORD opcode = (inst >> 3) & 0x1F;
3813 inst = (inst & 0xFF07) | (0xF << 3);
3822 else if (siz == SIZL)
3829 else if (siz == SIZN)
3837 if (activefpu == FPU_68060)
3838 warn("Instruction is emulated in 68060");
3845 // ftst (6888X, 68040, 68060)
3847 int m_ftst(WORD inst, WORD siz)
3850 return gen_fpu(inst, siz, B8(00111010), FPU_NOWARN);
3855 // ftwotox (6888X, 68040FPSP, 68060FPSP)
3857 int m_ftwotox(WORD inst, WORD siz)
3860 return gen_fpu(inst, siz, B8(00010001), FPU_FPSP);
3864 /////////////////////////////////
3866 // 68060 specific instructions //
3868 /////////////////////////////////
3874 int m_lpstop(WORD inst, WORD siz)
3877 D_word(B16(00000001, 11000000));
3879 if (a0exattr & DEFINED)
3885 AddFixup(FU_WORD, sloc, a0expr);
3896 int m_plpa(WORD inst, WORD siz)
3899 inst |= a0reg; // Install register