EOY minor update.
[rmac] / mach.c
1 //
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
7 //
8
9 #include "mach.h"
10 #include "amode.h"
11 #include "direct.h"
12 #include "eagen.h"
13 #include "error.h"
14 #include "expr.h"
15 #include "procln.h"
16 #include "riscasm.h"
17 #include "sect.h"
18 #include "token.h"
19
20 #define DEF_KW
21 #include "kwtab.h"
22
23 // Exported variables
24 int movep = 0; // Global flag to indicate we're generating a movep instruction
25
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);
37 int m_ea(WORD, WORD);
38 int m_lea(WORD, WORD);
39 int m_br(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);
52
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);
78
79 // PMMU
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);
89 int m_ptrapcc(WORD inst, WORD siz);
90 int m_ploadr(WORD inst, WORD siz);
91 int m_ploadw(WORD inst, WORD siz);
92
93 // FPU
94 int m_fabs(WORD inst, WORD siz);
95 int m_fbcc(WORD inst, WORD siz);
96 int m_facos(WORD inst, WORD siz);
97 int m_fadd(WORD inst, WORD siz);
98 int m_fasin(WORD inst, WORD siz);
99 int m_fatan(WORD inst, WORD siz);
100 int m_fatanh(WORD inst, WORD siz);
101 int m_fcmp(WORD inst, WORD siz);
102 int m_fcos(WORD inst, WORD siz);
103 int m_fcosh(WORD inst, WORD siz);
104 int m_fdabs(WORD inst, WORD siz);
105 int m_fdadd(WORD inst, WORD siz);
106 int m_fdbcc(WORD inst, WORD siz);
107 int m_fddiv(WORD inst, WORD siz);
108 int m_fdfsqrt(WORD inst, WORD siz);
109 int m_fdiv(WORD inst, WORD siz);
110 int m_fdmove(WORD inst, WORD siz);
111 int m_fdmul(WORD inst, WORD siz);
112 int m_fdneg(WORD inst, WORD siz);
113 int m_fdsub(WORD inst, WORD siz);
114 int m_fetox(WORD inst, WORD siz);
115 int m_fetoxm1(WORD inst, WORD siz);
116 int m_fgetexp(WORD inst, WORD siz);
117 int m_fgetman(WORD inst, WORD siz);
118 int m_fint(WORD inst, WORD siz);
119 int m_fintrz(WORD inst, WORD siz);
120 int m_flog10(WORD inst, WORD siz);
121 int m_flog2(WORD inst, WORD siz);
122 int m_flogn(WORD inst, WORD siz);
123 int m_flognp1(WORD inst, WORD siz);
124 int m_fmod(WORD inst, WORD siz);
125 int m_fmove(WORD inst, WORD siz);
126 int m_fmovescr(WORD inst, WORD siz);
127 int m_fmovecr(WORD inst, WORD siz);
128 int m_fmovem(WORD inst, WORD siz);
129 int m_fmul(WORD inst, WORD siz);
130 int m_fneg(WORD inst, WORD siz);
131 int m_fnop(WORD inst, WORD siz);
132 int m_frem(WORD inst, WORD siz);
133 int m_frestore(WORD inst, WORD siz);
134 int m_fsabs(WORD inst, WORD siz);
135 int m_fsadd(WORD inst, WORD siz);
136 int m_fscc(WORD inst, WORD siz);
137 int m_fscale(WORD inst, WORD siz);
138 int m_fsdiv(WORD inst, WORD siz);
139 int m_fsfsqrt(WORD inst, WORD siz);
140 int m_fsfsub(WORD inst, WORD siz);
141 int m_fsgldiv(WORD inst, WORD siz);
142 int m_fsglmul(WORD inst, WORD siz);
143 int m_fsin(WORD inst, WORD siz);
144 int m_fsincos(WORD inst, WORD siz);
145 int m_fsinh(WORD inst, WORD siz);
146 int m_fsmove(WORD inst, WORD siz);
147 int m_fsmul(WORD inst, WORD siz);
148 int m_fsneg(WORD inst, WORD siz);
149 int m_fsqrt(WORD inst, WORD siz);
150 int m_fsub(WORD inst, WORD siz);
151 int m_ftan(WORD inst, WORD siz);
152 int m_ftanh(WORD inst, WORD siz);
153 int m_ftentox(WORD inst, WORD siz);
154 int m_ftst(WORD inst, WORD siz);
155 int m_ftwotox(WORD inst, WORD siz);
156 int m_ftrapcc(WORD inst, WORD siz);
157
158 // Common error messages
159 char range_error[] = "expression out of range";
160 char abs_error[] = "illegal absolute expression";
161 char seg_error[] = "bad (section) expression";
162 char rel_error[] = "illegal relative address";
163 char siz_error[] = "bad size specified";
164 char undef_error[] = "undefined expression";
165 char fwd_error[] = "forward or undefined expression";
166 char unsupport[] = "unsupported for selected CPU";
167
168 // Include code tables
169 MNTAB machtab[] = {
170         { 0xFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000, 0, m_badmode }, // 0
171 #include "68ktab.h"
172         {  0,  0L,  0L, 0x0000, 0, m_unimp   }            // Last entry
173 };
174
175 // Register number << 9
176 WORD reg_9[8] = {
177         0, 1 << 9, 2 << 9, 3 << 9, 4 << 9, 5 << 9, 6 << 9, 7 << 9
178 };
179
180 // SIZB==>00, SIZW==>01, SIZL==>10, SIZN==>01 << 6
181 WORD siz_6[] = {
182         (WORD)-1,                                        // n/a
183         0,                                               // SIZB
184         1<<6, (WORD)-1,                                  // SIZW, n/a
185         2<<6, (WORD)-1, (WORD)-1, (WORD)-1,              // SIZL, n/a, n/a, n/a
186         1<<6                                             // SIZN
187 };
188
189 // Byte/word/long size for MOVE instrs
190 WORD siz_12[] = {
191    (WORD)-1,
192    0x1000,                                           // Byte
193    0x3000, (WORD)-1,                                 // Word
194    0x2000, (WORD)-1, (WORD)-1, (WORD)-1,             // Long
195    0x3000                                            // Word (SIZN)
196 };
197
198 // Word/long size (0=.w, 1=.l) in bit 8
199 WORD lwsiz_8[] = {
200    (WORD)-1,                                         // n/a
201    (WORD)-1,                                         // SIZB
202    0, (WORD)-1,                                      // SIZW, n/a
203    1<<8, (WORD)-1, (WORD)-1, (WORD)-1,               // SIZL, n/a, n/a, n/a
204    0                                                 // SIZN
205 };
206
207 // Byte/Word/long size (0=.w, 1=.l) in bit 9
208 WORD lwsiz_9[] = {
209         (WORD)-1,
210         0,                                               // Byte
211         1<<9, (WORD)-1,                                  // Word
212         1<<10, (WORD)-1, (WORD)-1, (WORD)-1,             // Long
213         1<<9                                             // Word (SIZN)
214 };
215
216 // Addressing mode in bits 6..11 (register/mode fields are reversed)
217 WORD am_6[] = {
218    00000, 01000, 02000, 03000, 04000, 05000, 06000, 07000,
219    00100, 01100, 02100, 03100, 04100, 05100, 06100, 07100,
220    00200, 01200, 02200, 03200, 04200, 05200, 06200, 07200,
221    00300, 01300, 02300, 03300, 04300, 05300, 06300, 07300,
222    00400, 01400, 02400, 03400, 04400, 05400, 06400, 07400,
223    00500, 01500, 02500, 03500, 04500, 05500, 06500, 07500,
224    00600, 01600, 02600, 03600, 04600, 05600, 06600, 07600,
225    00700, 01700, 02700, 03700, 04700, 05700, 06700, 07700
226 };
227
228 // Control registers lookup table
229 WORD CREGlut[21] = {
230         // MC68010/MC68020/MC68030/MC68040/CPU32
231         0x000,          // Source Function Code(SFC)
232         0x001,          // Destination Function Code(DFC)
233         0x800,          // User Stack Pointer(USP)
234         0x801,          // Vector Base Register(VBR)
235         // MC68020 / MC68030 / MC68040
236         0x002,          // Cache Control Register(CACR)
237         0x802,          // Cache Address Register(CAAR) (020/030 only)
238         0x803,          // Master Stack Pointer(MSP)
239         0x804,          // Interrupt Stack Pointer(ISP)
240         // MC68040 / MC68LC040
241         0x003,          // MMU Translation Control Register(TC)
242         0x004,          // Instruction Transparent Translation Register 0 (ITT0)
243         0x005,          // Instruction Transparent Translation Register 1 (ITT1)
244         0x006,          // Data Transparent Translation Register 0 (DTT0)
245         0x007,          // Data Transparent Translation Register 1 (DTT1)
246         0x805,          // MMU Status Register(MMUSR)
247         0x806,          // User Root Pointer(URP)
248         0x807,          // Supervisor Root Pointer(SRP)
249         // MC68EC040 only
250         0x004,          // Instruction Access Control Register 0 (IACR0)
251         0x005,          // Instruction Access Control Register 1 (IACR1)
252         0x006,          // Data Access Control Register 0 (DACR1)
253         0x007,          // Data Access Control Register 1 (DACR1)
254         // 68851 only
255         0xFFF           // CPU Root Pointer (CRP) - There's no movec with CRP in it, this is just a guard entry
256 };
257
258
259 // Error messages
260 int m_unimp(WORD unused1, WORD unused2)
261 {
262         return (int)error("unimplemented mnemonic");
263 }
264
265
266 //int m_badmode(void)
267 int m_badmode(WORD unused1, WORD unused2)
268 {
269         return (int)error("inappropriate addressing mode");
270 }
271
272
273 int m_self(WORD inst, WORD usused)
274 {
275         D_word(inst);
276         return OK;
277 }
278
279
280 //
281 // Do one EA in bits 0..5
282 //
283 // Bits in `inst' have the following meaning:
284 //
285 // Bit zero specifies which ea (ea0 or ea1) to generate in the lower six bits
286 // of the instr.
287 //
288 // If bit one is set, the OTHER ea (the one that wasn't generated by bit zero)
289 // is generated after the instruction. Regardless of bit 0's value, ea0 is
290 // always deposited in memory before ea1.
291 //
292 // If bit two is set, standard size bits are set in the instr in bits 6 and 7.
293 //
294 // If bit four is set, bit three specifies which eaXreg to place in bits 9..11
295 // of the instr.
296 //
297 int m_ea(WORD inst, WORD siz)
298 {
299         WORD flg = inst;                                        // Save flag bits
300         inst &= ~0x3F;                                          // Clobber flag bits in instr
301
302         // Install "standard" instr size bits
303         if (flg & 4)
304                 inst |= siz_6[siz];
305
306         if (flg & 16)
307         {
308                 // OR-in register number
309                 if (flg & 8)
310                         inst |= reg_9[a1reg];           // ea1reg in bits 9..11
311                 else
312                         inst |= reg_9[a0reg];           // ea0reg in bits 9..11
313         }
314
315         if (flg & 1)
316         {
317                 // Use am1
318                 inst |= am1 | a1reg;                    // Get ea1 into instr
319                 D_word(inst);                                   // Deposit instr
320
321                 // Generate ea0 if requested
322                 if (flg & 2)
323                         ea0gen(siz);
324
325                 ea1gen(siz);                                    // Generate ea1
326         }
327         else
328         {
329                 // Use am0
330                 inst |= am0 | a0reg;                    // Get ea0 into instr
331                 D_word(inst);                                   // Deposit instr
332                 ea0gen(siz);                                    // Generate ea0
333
334                 // Generate ea1 if requested
335                 if (flg & 2)
336                         ea1gen(siz);
337         }
338
339         return OK;
340 }
341
342
343 //
344 // Check if lea x(an),an can be optimised to addq.w #x,an--otherwise fall back
345 // to m_ea.
346 //
347 int m_lea(WORD inst, WORD siz)
348 {
349         if (CHECK_OPTS(OPT_LEA_ADDQ)
350                 && ((am0 == ADISP) && (a0reg == a1reg) && (a0exattr & DEFINED))
351                 && ((a0exval > 0) && (a0exval <= 8)))
352         {
353                 inst = B16(01010000, 01001000) | (((uint16_t)a0exval & 7) << 9) | (a0reg);
354                 D_word(inst);
355                 warn("lea size(An),An converted to addq #size,An");
356                 return OK;
357         }
358
359         return m_ea(inst, siz);
360 }
361
362
363 int m_ea030(WORD inst, WORD siz)
364 {
365         CHECK00;
366         WORD flg = inst;                                        // Save flag bits
367         inst &= ~0x3F;                                          // Clobber flag bits in instr
368
369         // Install "standard" instr size bits
370         if (flg & 4)
371                 inst |= siz_6[siz];
372
373         if (flg & 16)
374         {
375                 // OR-in register number
376                 if (flg & 8)
377                 {
378                         inst |= reg_9[a1reg];           // ea1reg in bits 9..11
379                 }
380                 else
381                 {
382                         inst |= reg_9[a0reg];           // ea0reg in bits 9..11
383                 }
384         }
385
386         if (flg & 1)
387         {
388                 // Use am1
389                 inst |= am1 | a1reg;                    // Get ea1 into instr
390                 D_word(inst);                                   // Deposit instr
391
392                 // Generate ea0 if requested
393                 if (flg & 2)
394                         ea0gen(siz);
395
396                 ea1gen(siz);                                    // Generate ea1
397         }
398         else
399         {
400                 // Use am0
401                 if (am0 == AREG)
402                         // We get here if we're doing 020+ addressing and an address
403                         // register is used. For example, something like "tst a0". A bit of
404                         // a corner case, so kludge it
405                         a0reg = a0reg + 8;
406                 else if (am0 == PCDISP)
407                         // Another corner case (possibly!), so kludge ahoy
408                         inst |= am0;                            // Get ea0 into instr
409                 else if (am0 == IMMED && am1 == MEMPOST)
410                 {
411                         // Added for addi/andi/cmpi/eori/ori/subi #xx,(bd,An,Dm)
412                         inst |= a1reg | AINDEXED;
413                 }
414                 else if (am0 == IMMED)
415                         inst |= am0 | a0reg;            // Get ea0 into instr
416                 else if (am0 == AM_CCR)
417                         inst |= am1 | a1reg;
418                 else if (am0 == AIND)
419                         inst |= am0;
420
421                 inst |= a0reg;                                  // Get ea0 into instr
422                 D_word(inst);                                   // Deposit instr
423                 ea0gen(siz);                                    // Generate ea0
424
425                 // Generate ea1 if requested
426                 if (flg & 2)
427                         ea1gen(siz);
428         }
429
430         return OK;
431 }
432
433
434 //
435 // Dx,Dy nnnnXXXnssnnnYYY If bit 0 of `inst' is set, install size bits in bits
436 // 6..7
437 //
438 int m_abcd(WORD inst, WORD siz)
439 {
440         if (inst & 1)
441         {
442                 // Install size bits
443                 inst--;
444                 inst |= siz_6[siz];
445         }
446
447         inst |= a0reg | reg_9[a1reg];
448         D_word(inst);
449
450         return OK;
451 }
452
453
454 //
455 // {adda} ea,AREG
456 //
457 int m_adda(WORD inst, WORD siz)
458 {
459         if (a0exattr & DEFINED)
460         {
461                 if (CHECK_OPTS(OPT_ADDA_ADDQ))
462                         if (a0exval > 1 && a0exval <= 8)
463                                 // Immediate is between 1 and 8 so let's convert to addq
464                                 return m_addq(B16(01010000, 00000000), siz);
465         if (CHECK_OPTS(OPT_ADDA_LEA))
466                 if (a0exval > 8)
467                 {
468                         // Immediate is larger than 8 so let's convert to lea
469                         am0 = ADISP;    // Change addressing mode
470                         a0reg = a1reg;  // In ADISP a0reg is used instead of a1reg!
471                         return m_lea(B16(01000001, 11011000), SIZW);
472                 }
473         }
474
475         inst |= am0 | a0reg | lwsiz_8[siz] | reg_9[a1reg];
476         D_word(inst);
477         ea0gen(siz);    // Generate EA
478
479         return OK;
480 }
481
482
483 //
484 // If bit 0 of `inst' is 1, install size bits in bits 6..7 of instr.
485 // If bit 1 of `inst' is 1, install a1reg in bits 9..11 of instr.
486 //
487 int m_reg(WORD inst, WORD siz)
488 {
489         if (inst & 1)
490                 // Install size bits
491                 inst |= siz_6[siz];
492
493         if (inst & 2)
494                 // Install other register (9..11)
495                 inst |= reg_9[a1reg];
496
497         inst &= ~7;                     // Clear off crufty bits
498         inst |= a0reg;          // Install first register
499         D_word(inst);
500
501         return OK;
502 }
503
504
505 //
506 // <op> #expr
507 //
508 int m_imm(WORD inst, WORD siz)
509 {
510         D_word(inst);
511         ea0gen(siz);
512
513         return OK;
514 }
515
516
517 //
518 // <op>.b #expr
519 //
520 int m_imm8(WORD inst, WORD siz)
521 {
522         siz = siz;
523         D_word(inst);
524         ea0gen(SIZB);
525
526         return OK;
527 }
528
529
530 //
531 // <shift> Dn,Dn
532 //
533 int m_shr(WORD inst, WORD siz)
534 {
535         inst |= reg_9[a0reg] | a1reg | siz_6[siz];
536         D_word(inst);
537
538         return OK;
539 }
540
541
542 //
543 // <shift> #n,Dn
544 //
545 int m_shi(WORD inst, WORD siz)
546 {
547         inst |= a1reg | siz_6[siz];
548
549         if (a0exattr & DEFINED)
550         {
551                 if (a0exval > 8)
552                         return error(range_error);
553
554                 inst |= (a0exval & 7) << 9;
555                 D_word(inst);
556         }
557         else
558         {
559                 AddFixup(FU_QUICK, sloc, a0expr);
560                 D_word(inst);
561         }
562
563         return OK;
564 }
565
566
567 //
568 // {bset, btst, bchg, bclr} -- #immed,ea -- Dn,ea
569 //
570 int m_bitop(WORD inst, WORD siz)
571 {
572         // Enforce instruction sizes
573         if (am1 == DREG)
574         {                               // X,Dn must be .n or .l
575                 if (siz & (SIZB | SIZW))
576                         return error(siz_error);
577         }
578         else if (siz & (SIZW | SIZL))   // X,ea must be .n or .b
579                 return error(siz_error);
580
581         // Construct instr and EAs
582         inst |= am1 | a1reg;
583
584         if (am0 == IMMED)
585         {
586                 D_word(inst);
587                 ea0gen(SIZB);                           // Immediate bit number
588         }
589         else
590         {
591                 inst |= reg_9[a0reg];
592                 D_word(inst);
593         }
594
595         // ea to bit-munch
596         ea1gen(SIZB);
597
598         return OK;
599 }
600
601
602 int m_dbra(WORD inst, WORD siz)
603 {
604         siz = siz;
605         inst |= a0reg;
606         D_word(inst);
607
608         if (a1exattr & DEFINED)
609         {
610                 if ((a1exattr & TDB) != cursect)
611                         return error(rel_error);
612
613                 uint32_t v = (uint32_t)a1exval - sloc;
614
615                 if (v + 0x8000 > 0x10000)
616                         return error(range_error);
617
618                 D_word(v);
619         }
620         else
621         {
622                 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
623                 D_word(0);
624         }
625
626         return OK;
627 }
628
629
630 //
631 // EXG
632 //
633 int m_exg(WORD inst, WORD siz)
634 {
635         int m;
636
637         siz = siz;
638
639         if (am0 == DREG && am1 == DREG)
640                 m = 0x0040;                      // Dn,Dn
641         else if (am0 == AREG && am1 == AREG)
642                 m = 0x0048;                      // An,An
643         else
644         {
645                 if (am0 == AREG)
646                 {                                // Dn,An or An,Dn
647                         m = a1reg;                   // Get AREG into a1reg
648                         a1reg = a0reg;
649                         a0reg = m;
650                 }
651
652                 m = 0x0088;
653         }
654
655         inst |= m | reg_9[a0reg] | a1reg;
656         D_word(inst);
657
658         return OK;
659 }
660
661
662 //
663 // LINK
664 //
665 int m_link(WORD inst, WORD siz)
666 {
667         if (siz != SIZL)
668         {
669                 // Is this an error condition???
670         }
671         else
672         {
673                 CHECK00;
674                 inst &= ~((3 << 9) | (1 << 6) | (1 << 4));
675                 inst |= 1 << 3;
676         }
677
678         inst |= a0reg;
679         D_word(inst);
680         ea1gen(siz);
681
682         return OK;
683 }
684
685
686 WORD extra_addressing[16]=
687 {
688         0x30,  // 0100 (bd,An,Xn)
689         0x30,  // 0101 ([bd,An],Xn,od)
690         0x30,  // 0102 ([bc,An,Xn],od)
691         0x30,  // 0103 (bd,PC,Xn)
692         0x30,  // 0104 ([bd,PC],Xn,od)
693         0x30,  // 0105 ([bc,PC,Xn],od)
694         0,     // 0106
695         0,     // 0107
696         0,     // 0110
697         0,     // 0111 Nothing
698         0x30,  // 0112 (Dn.w)
699         0x30,  // 0113 (Dn.l)
700         0,     // 0114
701         0,     // 0115
702         0,     // 0116
703         0      // 0117
704 };
705
706
707 //
708 // Handle MOVE <C_ALL> <C_ALTDATA>
709 //        MOVE <C_ALL> <M_AREG>
710 //
711 // Optimize MOVE.L #<smalldata>,D0 to a MOVEQ
712 //
713 int m_move(WORD inst, WORD size)
714 {
715         // Cast the passed in value to an int
716         int siz = (int)size;
717
718         // Try to optimize to MOVEQ
719         // N.B.: We can get away with casting the uint64_t to a 32-bit value
720         //       because it checks for a SIZL (i.e., a 32-bit value).
721         if (CHECK_OPTS(OPT_MOVEL_MOVEQ)
722                 && (siz == SIZL) && (am0 == IMMED) && (am1 == DREG)
723                 && ((a0exattr & (TDB | DEFINED)) == DEFINED)
724                 && ((uint32_t)a0exval + 0x80 < 0x100))
725         {
726                 m_moveq((WORD)0x7000, (WORD)0);
727
728                 if (sbra_flag)
729                         warn("move.l #size,dx converted to moveq");
730         }
731         else
732         {
733                 if ((am0 < ABASE) && (am1 < ABASE))                     // 68000 modes
734                 {
735                         inst |= siz_12[siz] | am_6[am1] | reg_9[a1reg] | am0 | a0reg;
736
737                         D_word(inst);
738
739                         if (am0 >= ADISP)
740                                 ea0gen((WORD)siz);
741
742                         if (am1 >= ADISP)
743                                 ea1gen((WORD)siz | 0x8000);   // Tell ea1gen we're move ea,ea
744                 }
745                 else                                    // 68020+ modes
746                 {
747                         inst |= siz_12[siz] | reg_9[a1reg] | extra_addressing[am0 - ABASE];
748
749                         D_word(inst);
750
751                         if (am0 >= ADISP)
752                                 ea0gen((WORD)siz);
753
754                         if (am1 >= ADISP)
755                                 ea1gen((WORD)siz);
756                 }
757         }
758
759         return OK;
760 }
761
762
763 //
764 // Handle MOVE <C_ALL030> <C_ALTDATA>
765 //              MOVE <C_ALL030> <M_AREG>
766 //
767 int m_move30(WORD inst, WORD size)
768 {
769         int siz = (int)size;
770         inst |= siz_12[siz] | reg_9[a1reg & 7] | a0reg | extra_addressing[am0 - ABASE];
771
772         D_word(inst);
773
774         if (am0 >= ADISP)
775                 ea0gen((WORD)siz);
776
777         if (am1 >= ADISP)
778                 ea1gen((WORD)siz);
779
780         return OK;
781 }
782
783
784 //
785 // move USP,An -- move An,USP
786 //
787 int m_usp(WORD inst, WORD siz)
788 {
789         siz = siz;
790
791         if (am0 == AM_USP)
792                 inst |= a1reg;          // USP, An
793         else
794                 inst |= a0reg;          // An, USP
795
796         D_word(inst);
797
798         return OK;
799 }
800
801
802 //
803 // moveq
804 //
805 int m_moveq(WORD inst, WORD siz)
806 {
807         siz = siz;
808
809         // Arrange for future fixup
810         if (!(a0exattr & DEFINED))
811         {
812                 AddFixup(FU_BYTE | FU_SEXT, sloc + 1, a0expr);
813                 a0exval = 0;
814         }
815         else if ((uint32_t)a0exval + 0x100 >= 0x200)
816                 return error(range_error);
817
818         inst |= reg_9[a1reg] | (a0exval & 0xFF);
819         D_word(inst);
820
821         return OK;
822 }
823
824
825 //
826 // movep Dn, disp(An) -- movep disp(An), Dn
827 //
828 int m_movep(WORD inst, WORD siz)
829 {
830         // Tell ea0gen to lay off the 0(a0) optimisations on this one
831         movep = 1;
832
833         if (siz == SIZL)
834                 inst |= 0x0040;
835
836         if (am0 == DREG)
837         {
838                 inst |= reg_9[a0reg] | a1reg;
839                 D_word(inst);
840
841                 if (am1 == AIND)
842                         D_word(0)
843                 else
844                         ea1gen(siz);
845         }
846         else
847         {
848                 inst |= reg_9[a1reg] | a0reg;
849                 D_word(inst);
850
851                 if (am0 == AIND)
852                         D_word(0)
853                 else
854                         ea0gen(siz);
855         }
856
857         movep = 0;
858         return 0;
859 }
860
861
862 //
863 // Bcc -- BSR
864 //
865 int m_br(WORD inst, WORD siz)
866 {
867         if (a0exattr & DEFINED)
868         {
869                 if ((a0exattr & TDB) != cursect)
870 //{
871 //printf("m_br(): a0exattr = %X, cursect = %X, a0exval = %X, sloc = %X\n", a0exattr, cursect, a0exval, sloc);
872                         return error(rel_error);
873 //}
874
875                 uint32_t v = (uint32_t)a0exval - (sloc + 2);
876
877                 // Optimize branch instr. size
878                 if (siz == SIZN)
879                 {
880                         if (CHECK_OPTS(OPT_BSR_BCC_S) && (v != 0) && ((v + 0x80) < 0x100))
881                         {
882                                 // Fits in .B
883                                 inst |= v & 0xFF;
884                                 D_word(inst);
885
886                                 if (sbra_flag)
887                                         warn("Bcc.w/BSR.w converted to .s");
888
889                                 return OK;
890                         }
891                         else
892                         {
893                                 // Fits in .W
894                                 if ((v + 0x8000) > 0x10000)
895                                         return error(range_error);
896
897                                 D_word(inst);
898                                 D_word(v);
899                                 return OK;
900                         }
901                 }
902
903                 if (siz == SIZB || siz == SIZS)
904                 {
905                         if ((v + 0x80) >= 0x100)
906                                 return error(range_error);
907
908                         inst |= v & 0xFF;
909                         D_word(inst);
910                 }
911                 else
912                 {
913                         if ((v + 0x8000) >= 0x10000)
914                                 return error(range_error);
915
916                         D_word(inst);
917                         D_word(v);
918                 }
919
920                 return OK;
921         }
922         else if (siz == SIZN)
923                 siz = SIZW;
924
925         if (siz == SIZB || siz == SIZS)
926         {
927                 // .B
928                 AddFixup(FU_BBRA | FU_PCREL | FU_SEXT, sloc, a0expr);
929                 D_word(inst);
930                 return OK;
931         }
932         else
933         {
934                 // .W
935                 D_word(inst);
936                 AddFixup(FU_WORD | FU_PCREL | FU_LBRA | FU_ISBRA, sloc, a0expr);
937                 D_word(0);
938         }
939
940         return OK;
941 }
942
943
944 //
945 // ADDQ -- SUBQ
946 //
947 int m_addq(WORD inst, WORD siz)
948 {
949         inst |= siz_6[siz] | am1 | a1reg;
950
951         if (a0exattr & DEFINED)
952         {
953                 if ((a0exval > 8) || (a0exval == 0))    // Range in 1..8
954                         return error(range_error);
955
956                 inst |= (a0exval & 7) << 9;
957                 D_word(inst);
958         }
959         else
960         {
961                 AddFixup(FU_QUICK, sloc, a0expr);
962                 D_word(inst);
963         }
964
965         ea1gen(siz);
966
967         return OK;
968 }
969
970
971 //
972 // trap #n
973 //
974 int m_trap(WORD inst, WORD siz)
975 {
976         siz = siz;
977
978         if (a0exattr & DEFINED)
979         {
980                 if (a0exattr & TDB)
981                         return error(abs_error);
982
983                 if (a0exval >= 16)
984                         return error(range_error);
985
986                 inst |= a0exval;
987                 D_word(inst);
988         }
989         else
990                 return error(undef_error);
991
992         return OK;
993 }
994
995
996 //
997 // movem <rlist>,ea -- movem ea,<rlist>
998 //
999 int m_movem(WORD inst, WORD siz)
1000 {
1001         uint64_t eval;
1002         WORD i;
1003         WORD w;
1004         WORD rmask;
1005
1006         if (siz & SIZB)
1007                 return error("bad size suffix");
1008
1009         if (siz == SIZL)
1010                 inst |= 0x0040;
1011
1012         if (*tok == '#')
1013         {
1014                 // Handle #<expr>, ea
1015                 tok++;
1016
1017                 if (abs_expr(&eval) != OK)
1018                         return OK;
1019
1020                 if (eval >= 0x10000L)
1021                         return error(range_error);
1022
1023                 rmask = (WORD)eval;
1024                 goto immed1;
1025         }
1026
1027         if ((*tok >= KW_D0) && (*tok <= KW_A7))
1028         {
1029                 // <rlist>, ea
1030                 if (reglist(&rmask) < 0)
1031                         return OK;
1032
1033 immed1:
1034                 if (*tok++ != ',')
1035                         return error("missing comma");
1036
1037                 if (amode(0) < 0)
1038                         return OK;
1039
1040                 inst |= am0 | a0reg;
1041
1042                 if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
1043                         return error("invalid addressing mode");
1044
1045                 // If APREDEC, reverse register mask
1046                 if (am0 == APREDEC)
1047                 {
1048                         w = rmask;
1049                         rmask = 0;
1050
1051                         for(i=0x8000; i; i>>=1, w>>=1)
1052                                 rmask = (WORD)((rmask << 1) | (w & 1));
1053                 }
1054         }
1055         else
1056         {
1057                 // ea, <rlist>
1058                 if (amode(0) < 0)
1059                         return OK;
1060
1061                 inst |= 0x0400 | am0 | a0reg;
1062
1063                 if (*tok++ != ',')
1064                         return error("missing comma");
1065
1066                 if (*tok == EOL)
1067                         return error("missing register list");
1068
1069                 if (*tok == '#')
1070                 {
1071                         // ea, #<expr>
1072                         tok++;
1073
1074                         if (abs_expr(&eval) != OK)
1075                                 return OK;
1076
1077                         if (eval >= 0x10000)
1078                                 return error(range_error);
1079
1080                         rmask = (WORD)eval;
1081                 }
1082                 else if (reglist(&rmask) < 0)
1083                         return OK;
1084
1085                 if (!(amsktab[am0] & (C_CTRL | M_APOSTINC)))
1086                         return error("invalid addressing mode");
1087         }
1088
1089         D_word(inst);
1090         D_word(rmask);
1091         ea0gen(siz);
1092
1093         return OK;
1094 }
1095
1096
1097 //
1098 // CLR.x An ==> SUBA.x An,An
1099 //
1100 int m_clra(WORD inst, WORD siz)
1101 {
1102         inst |= a0reg | reg_9[a0reg] | lwsiz_8[siz];
1103         D_word(inst);
1104
1105         return OK;
1106 }
1107
1108
1109 //
1110 // CLR.L Dn ==> CLR.L An or MOVEQ #0,Dx
1111 //
1112 int m_clrd(WORD inst, WORD siz)
1113 {
1114         if (!CHECK_OPTS(OPT_CLR_DX))
1115                 inst |= a0reg;
1116         else
1117                 inst = (a0reg << 9) | B16(01110000, 00000000);
1118
1119         D_word(inst);
1120
1121         return OK;
1122 }
1123
1124
1125 ////////////////////////////////////////
1126 //
1127 // 68020/30/40/60 instructions
1128 //
1129 ////////////////////////////////////////
1130
1131 //
1132 // Bcc.l -- BSR.l
1133 //
1134 int m_br30(WORD inst, WORD siz)
1135 {
1136         if (a0exattr & DEFINED)
1137         {
1138                 if ((a0exattr & TDB) != cursect)
1139                         return error(rel_error);
1140
1141                 uint32_t v = (uint32_t)a0exval - (sloc + 2);
1142                 D_word(inst);
1143                 D_long(v);
1144
1145                 return OK;
1146         }
1147         else
1148         {
1149                 // .L
1150                 AddFixup(FU_LONG | FU_PCREL | FU_SEXT, sloc, a0expr);
1151                 D_word(inst);
1152                 return OK;
1153         }
1154 }
1155
1156
1157 //
1158 // bfchg, bfclr, bfexts, bfextu, bfffo, bfins, bfset
1159 // (68020, 68030, 68040)
1160 //
1161 int m_bfop(WORD inst, WORD siz)
1162 {
1163         if ((bfval1 > 31) || (bfval1 < 0))
1164                 return error("bfxxx offset: immediate value must be between 0 and 31");
1165
1166         // First instruction word - just the opcode and first EA
1167         // Note: both am1 is ORed because solely of bfins - maybe it's a good idea
1168         // to make a dedicated function for it?
1169         if (am1 == AM_NONE)
1170         {
1171                 am1 = 0;
1172         }
1173         else
1174         {
1175                 if (bfval2 > 31 || bfval2 < 0)
1176                         return error("bfxxx width: immediate value must be between 0 and 31");
1177
1178                 // For Dw both immediate and register number are stuffed
1179                 // into the same field O_o
1180                 bfparam2 = (bfval2 << 0);
1181         }
1182
1183         if (bfparam1 == 0)
1184                 bfparam1 = (bfval1 << 6);
1185         else
1186                 bfparam1 = bfval1 << 12;
1187
1188         //D_word((inst | am0 | a0reg | am1 | a1reg));
1189         if (inst == B16(11101111, 11000000))
1190         {
1191                 // bfins special case
1192                 D_word((inst | am1 | a1reg));
1193         }
1194         else
1195         {
1196                 D_word((inst | am0 | a0reg));
1197         }
1198
1199         ea0gen(siz);    // Generate EA
1200
1201         // Second instruction word - Dest register (if exists), Do, Offset, Dw, Width
1202         if (inst == B16(11101111, 11000000))
1203         {
1204                 // bfins special case
1205                 inst = bfparam1 | bfparam2;
1206
1207                 if (am1 == DREG)
1208                         inst |= a0reg << 12;
1209
1210                 D_word(inst);
1211         }
1212         else
1213         {
1214                 inst = bfparam1 | bfparam2;
1215
1216                 if (am1 == DREG)
1217                         inst |= a0reg << 0;
1218
1219                 if (am0 == DREG)
1220                         inst |= a1reg << 12;
1221
1222                 D_word(inst);
1223         }
1224
1225         return OK;
1226 }
1227
1228
1229 //
1230 // bkpt (68EC000, 68010, 68020, 68030, 68040, CPU32)
1231 //
1232 int m_bkpt(WORD inst, WORD siz)
1233 {
1234         CHECK00;
1235
1236         if (a0exattr & DEFINED)
1237         {
1238                 if (a0exattr & TDB)
1239                         return error(abs_error);
1240
1241                 if (a0exval >= 8)
1242                         return error(range_error);
1243
1244                 inst |= a0exval;
1245                 D_word(inst);
1246         }
1247         else
1248                 return error(undef_error);
1249
1250         return OK;
1251 }
1252
1253
1254 //
1255 // callm (68020)
1256 //
1257 int m_callm(WORD inst, WORD siz)
1258 {
1259         CHECKNO20;
1260
1261         inst |= am1;
1262         D_word(inst);
1263
1264         if (a0exattr & DEFINED)
1265         {
1266                 if (a0exattr & TDB)
1267                         return error(abs_error);
1268
1269                 if (a0exval > 255)
1270                         return error(range_error);
1271
1272                 inst = (uint16_t)a0exval;
1273                 D_word(inst);
1274         }
1275         else
1276                 return error(undef_error);
1277
1278         ea1gen(siz);
1279
1280         return OK;
1281
1282 }
1283
1284
1285 //
1286 // cas (68020, 68030, 68040)
1287 //
1288 int m_cas(WORD inst, WORD siz)
1289 {
1290         WORD inst2;
1291         LONG amsk;
1292         int modes;
1293
1294         if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1295                 return error(unsupport);
1296
1297         switch (siz)
1298         {
1299         case SIZB:
1300                 inst |= 1 << 9;
1301                 break;
1302         case SIZW:
1303         case SIZN:
1304                 inst |= 2 << 9;
1305                 break;
1306         case SIZL:
1307                 inst |= 3 << 9;
1308                 break;
1309         default:
1310                 return error("bad size suffix");
1311                 break;
1312         }
1313
1314         // Dc
1315         if ((*tok < KW_D0) && (*tok > KW_D7))
1316                 return error("CAS accepts only data registers");
1317
1318         inst2 = (*tok++) & 7;
1319
1320         if (*tok++ != ',')
1321                 return error("missing comma");
1322
1323         // Du
1324         if ((*tok < KW_D0) && (*tok > KW_D7))
1325                 return error("CAS accepts only data registers");
1326
1327         inst2 |= ((*tok++) & 7) << 6;
1328
1329         if (*tok++ != ',')
1330                 return error("missing comma");
1331
1332         // ea
1333         if ((modes = amode(1)) < 0)
1334                 return OK;
1335
1336         if (modes > 1)
1337                 return error("too many ea fields");
1338
1339         if (*tok != EOL)
1340                 return error("extra (unexpected) text found");
1341
1342         // Reject invalid ea modes
1343         amsk = amsktab[am0];
1344
1345         if ((amsk & (M_AIND | M_APOSTINC | M_APREDEC | M_ADISP | M_AINDEXED | M_ABSW | M_ABSL | M_ABASE | M_MEMPOST | M_MEMPRE)) == 0)
1346                 return error("unsupported addressing mode");
1347
1348         inst |= am0 | a0reg;
1349         D_word(inst);
1350         D_word(inst2);
1351         ea0gen(siz);
1352
1353         return OK;
1354 }
1355
1356
1357 //
1358 // cas2 (68020, 68030, 68040)
1359 //
1360 int m_cas2(WORD inst, WORD siz)
1361 {
1362         WORD inst2, inst3;
1363
1364         if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1365                 return error(unsupport);
1366
1367         switch (siz)
1368         {
1369         case SIZB:
1370                 inst |= 1 << 9;
1371                 break;
1372         case SIZW:
1373         case SIZN:
1374                 inst |= 2 << 9;
1375                 break;
1376         case SIZL:
1377                 inst |= 3 << 9;
1378                 break;
1379         default:
1380                 return error("bad size suffix");
1381                 break;
1382         }
1383
1384         // Dc1
1385         if ((*tok < KW_D0) && (*tok > KW_D7))
1386                 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1387
1388         inst2 = (*tok++) & 7;
1389
1390         if (*tok++ != ':')
1391                 return error("missing colon");
1392
1393         // Dc2
1394         if ((*tok < KW_D0) && (*tok > KW_D7))
1395                 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1396
1397         inst3 = (*tok++) & 7;
1398
1399         if (*tok++ != ',')
1400                 return error("missing comma");
1401
1402         // Du1
1403         if ((*tok < KW_D0) && (*tok > KW_D7))
1404                 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1405
1406         inst2 |= ((*tok++) & 7) << 6;
1407
1408         if (*tok++ != ':')
1409                 return error("missing colon");
1410
1411         // Du2
1412         if ((*tok < KW_D0) && (*tok > KW_D7))
1413                 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1414
1415         inst3 |= ((*tok++) & 7) << 6;
1416
1417         if (*tok++ != ',')
1418                 return error("missing comma");
1419
1420         // Rn1
1421         if (*tok++ != '(')
1422                 return error("missing (");
1423         if ((*tok >= KW_D0) && (*tok <= KW_D7))
1424                 inst2 |= (((*tok++) & 7) << 12) | (0 << 15);
1425         else if ((*tok >= KW_A0) && (*tok <= KW_A7))
1426                 inst2 |= (((*tok++) & 7) << 12) | (1 << 15);
1427         else
1428                 return error("CAS accepts either data or address registers for Rn1:Rn2 pair");
1429
1430         if (*tok++ != ')')
1431                 return error("missing (");
1432
1433         if (*tok++ != ':')
1434                 return error("missing colon");
1435
1436         // Rn2
1437         if (*tok++ != '(')
1438                 return error("missing (");
1439         if ((*tok >= KW_D0) && (*tok <= KW_D7))
1440                 inst3 |= (((*tok++) & 7) << 12) | (0 << 15);
1441         else if ((*tok >= KW_A0) && (*tok <= KW_A7))
1442                 inst3 |= (((*tok++) & 7) << 12) | (1 << 15);
1443         else
1444                 return error("CAS accepts either data or address registers for Rn1:Rn2 pair");
1445
1446         if (*tok++ != ')')
1447                 return error("missing (");
1448
1449         if (*tok != EOL)
1450                 return error("extra (unexpected) text found");
1451
1452         D_word(inst);
1453         D_word(inst2);
1454         D_word(inst3);
1455
1456         return OK;
1457 }
1458
1459
1460 //
1461 // cmp2 (68020, 68030, 68040, CPU32)
1462 //
1463 int m_cmp2(WORD inst, WORD siz)
1464 {
1465         if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1466                 return error(unsupport);
1467
1468         switch (siz & 0x000F)
1469         {
1470         case SIZW:
1471         case SIZN:
1472                 inst |= 1 << 9;
1473                 break;
1474         case SIZL:
1475                 inst |= 2 << 9;
1476                 break;
1477         default:
1478                 // SIZB
1479                 break;
1480         }
1481
1482         WORD flg = inst;                                        // Save flag bits
1483         inst &= ~0x3F;                                          // Clobber flag bits in instr
1484
1485         // Install "standard" instr size bits
1486         if (flg & 4)
1487                 inst |= siz_6[siz];
1488
1489         if (flg & 16)
1490         {
1491                 // OR-in register number
1492                 if (flg & 8)
1493                         inst |= reg_9[a1reg];           // ea1reg in bits 9..11
1494                 else
1495                         inst |= reg_9[a0reg];           // ea0reg in bits 9..11
1496         }
1497
1498         if (flg & 1)
1499         {
1500                 // Use am1
1501                 inst |= am1 | a1reg;                    // Get ea1 into instr
1502                 D_word(inst);                                   // Deposit instr
1503
1504                 // Generate ea0 if requested
1505                 if (flg & 2)
1506                         ea0gen(siz);
1507
1508                 ea1gen(siz);                                    // Generate ea1
1509         }
1510         else
1511         {
1512                 // Use am0
1513                 inst |= am0 | a0reg;                    // Get ea0 into instr
1514                 D_word(inst);                                   // Deposit instr
1515                 ea0gen(siz);                                    // Generate ea0
1516
1517                 // Generate ea1 if requested
1518                 if (flg & 2)
1519                         ea1gen(siz);
1520         }
1521
1522         // If we're called from chk2 then bit 11 of size will be set. This is just
1523         // a dumb mechanism to pass this, required by the extension word. (You might
1524         // have noticed the siz & 15 thing above!)
1525         inst = (a1reg << 12) | (siz & (1 << 11));
1526
1527         if (am1 == AREG)
1528                 inst |= 1 << 15;
1529
1530         D_word(inst);
1531
1532         return OK;
1533 }
1534
1535
1536 //
1537 // chk2 (68020, 68030, 68040, CPU32)
1538 //
1539 int m_chk2(WORD inst, WORD siz)
1540 {
1541         return m_cmp2(inst, siz | (1 << 11));
1542 }
1543
1544
1545 //
1546 // cpbcc(68020, 68030, 68040 (FBcc), 68060 (FBcc)), pbcc (68851)
1547 //
1548 int m_fpbr(WORD inst, WORD siz)
1549 {
1550
1551         if (a0exattr & DEFINED)
1552         {
1553                 if ((a0exattr & TDB) != cursect)
1554                         return error(rel_error);
1555
1556                 uint32_t v = (uint32_t)a0exval - (sloc + 2);
1557
1558                 // Optimize branch instr. size
1559                 if (siz == SIZL)
1560                 {
1561                         if ((v != 0) && ((v + 0x8000) < 0x10000))
1562                         {
1563                                 inst |= (1 << 6);
1564                                 D_word(inst);
1565                                 D_long(v);
1566                                 return OK;
1567                         }
1568                 }
1569                 else // SIZW/SIZN
1570                 {
1571                         if ((v + 0x8000) >= 0x10000)
1572                                 return error(range_error);
1573
1574                         D_word(inst);
1575                         D_word(v);
1576                 }
1577
1578                 return OK;
1579         }
1580         else if (siz == SIZN)
1581                 siz = SIZW;
1582
1583         if (siz == SIZL)
1584         {
1585                 // .L
1586                 D_word(inst);
1587                 AddFixup(FU_LONG | FU_PCREL | FU_SEXT, sloc, a0expr);
1588                 D_long(0);
1589                 return OK;
1590         }
1591         else
1592         {
1593                 // .W
1594                 D_word(inst);
1595                 AddFixup(FU_WORD | FU_PCREL | FU_SEXT, sloc, a0expr);
1596                 D_word(0);
1597         }
1598
1599         return OK;
1600 }
1601
1602
1603 //
1604 // cpbcc(68020, 68030, 68040 (FBcc), 68060 (FBcc))
1605 //
1606 int m_cpbcc(WORD inst, WORD siz)
1607 {
1608         if (!(activecpu & (CPU_68020 | CPU_68030)))
1609                 return error(unsupport);
1610
1611         return m_fpbr(inst, siz);
1612 }
1613
1614
1615 //
1616 // fbcc(6808X, 68040, 68060)
1617 //
1618 int m_fbcc(WORD inst, WORD siz)
1619 {
1620         CHECKNOFPU;
1621         return m_fpbr(inst, siz);
1622 }
1623
1624
1625 //
1626 // pbcc(68851 but let's assume 68020 only)
1627 //
1628 int m_pbcc(WORD inst, WORD siz)
1629 {
1630         CHECKNO20;
1631         return m_fpbr(inst, siz);
1632 }
1633
1634
1635 //
1636 // cpdbcc(68020, 68030)
1637 //
1638 int m_cpdbr(WORD inst, WORD siz)
1639 {
1640         CHECK00;
1641
1642         uint32_t v;
1643         WORD condition = inst & 0x1F; // Grab condition sneakily placed in the lower 5 bits of inst
1644         inst &= 0xFFE0;               // And then mask them out - you ain't seen me, roit?
1645
1646         inst |= (1 << 9);       // Bolt on FPU id
1647         inst |= a0reg;
1648
1649         D_word(inst);
1650
1651         D_word(condition);
1652
1653         if (a1exattr & DEFINED)
1654         {
1655                 if ((a1exattr & TDB) != cursect)
1656                         return error(rel_error);
1657
1658                 v = (uint32_t)a1exval - sloc;
1659
1660                 if (v + 0x8000 > 0x10000)
1661                         return error(range_error);
1662
1663                 D_word(v);
1664         }
1665         else
1666         {
1667                 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
1668                 D_word(0);
1669         }
1670
1671         return OK;
1672
1673 }
1674
1675
1676 //
1677 // muls.l / divs.l / divu.l / mulu.l (68020+)
1678 //
1679 int m_muls(WORD inst, WORD siz)
1680 {
1681         if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1682                 return error(unsupport);
1683
1684         WORD flg = inst;                                        // Save flag bits
1685         inst &= ~0x33F;                                         // Clobber flag and extension bits in instr
1686
1687         // Install "standard" instr size bits
1688         if (flg & 4)
1689                 inst |= siz_6[siz];
1690
1691         if (flg & 16)
1692         {
1693                 // OR-in register number
1694                 if (flg & 8)
1695                         inst |= reg_9[a1reg];           // ea1reg in bits 9..11
1696                 else
1697                         inst |= reg_9[a0reg];           // ea0reg in bits 9..11
1698         }
1699
1700         // Regarding extension word: bit 11 is signed/unsigned selector
1701         //                           bit 10 is 32/64 bit selector
1702         // Both of these are packed in bits 9 and 8 of the instruction
1703         // field in 68ktab. Extra compilcations arise from the fact we
1704         // have to distinguish between divu/s.l Dn,Dm (which is encoded
1705         // as divu/s.l Dn,Dm:Dm) and divu/s.l Dn,Dm:Dx - the first is
1706         // 32 bit while the second 64 bit
1707
1708         if (flg & 1)
1709         {
1710                 // Use am1
1711                 inst |= am1 | a1reg;                    // Get ea1 into instr
1712                 D_word(inst);                                   // Deposit instr
1713
1714                 // Extension word
1715                 if (a1reg == a2reg)
1716                         inst = a1reg + (a2reg << 12) + ((flg & 0x200) << 2);
1717                 else
1718                         inst = a1reg + (a2reg << 12) + ((flg & 0x300) << 2);
1719
1720                  D_word(inst);
1721
1722                 // Generate ea0 if requested
1723                 if (flg & 2)
1724                         ea0gen(siz);
1725
1726                 ea1gen(siz);                                    // Generate ea1
1727
1728                 return OK;
1729         }
1730         else
1731         {
1732                 // Use am0
1733                 inst |= am0 | a0reg;                    // Get ea0 into instr
1734                 D_word(inst);                                   // Deposit instr
1735
1736                 // Extension word
1737                 if (a1reg == a2reg)
1738                         inst = a1reg + (a2reg << 12) + ((flg & 0x200) << 2);
1739                 else
1740                         inst = a1reg + (a2reg << 12) + ((flg & 0x300) << 2);
1741
1742                 D_word(inst);
1743
1744                 ea0gen(siz);                                    // Generate ea0
1745
1746                 // Generate ea1 if requested
1747                 if (flg & 2)
1748                         ea1gen(siz);
1749
1750                 return OK;
1751         }
1752 }
1753
1754
1755 //
1756 // move16 (ax)+,(ay)+
1757 //
1758 int m_move16a(WORD inst, WORD siz)
1759 {
1760         if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1761                 return error(unsupport);
1762
1763         inst |= a0reg;
1764         D_word(inst);
1765         inst = (1 << 15) + (a1reg << 12);
1766         D_word(inst);
1767
1768         return OK;
1769 }
1770
1771
1772 //
1773 // move16 with absolute address
1774 //
1775 int m_move16b(WORD inst, WORD siz)
1776 {
1777         if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1778                 return error(unsupport);
1779
1780         int v;
1781         inst |= a1reg;
1782         D_word(inst);
1783
1784         if (am0 == APOSTINC)
1785         {
1786                 if (am1 == AIND)
1787                         return error("Wasn't this suppose to call m_move16a???");
1788                 else
1789                 {
1790                         // move16 (ax)+,(xxx).L
1791                         inst |= 0 << 3;
1792                         v = (int)a1exval;
1793                 }
1794         }
1795         else if (am0 == ABSL)
1796         {
1797                 if (am1 == AIND)
1798                 {
1799                         // move16 (xxx).L,(ax)+
1800                         inst |= 1 << 3;
1801                         v = (int)a0exval;
1802                 }
1803                 else // APOSTINC
1804                 {
1805                         // move16 (xxx).L,(ax)
1806                         inst |= 3 << 3;
1807                         v = (int)a0exval;
1808                 }
1809         }
1810         else if (am0 == AIND)
1811         {
1812                 // move16 (ax),(xxx).L
1813                 inst |= 2 << 3;
1814                 v = (int)a1exval;
1815         }
1816
1817         D_word(inst);
1818         D_long(v);
1819
1820         return OK;
1821 }
1822
1823
1824 //
1825 // pack/unpack (68020/68030/68040)
1826 //
1827 int m_pack(WORD inst, WORD siz)
1828 {
1829         CHECK00;
1830
1831         if (siz != SIZN)
1832                 return error("bad size suffix");
1833
1834         if (*tok >= KW_D0 && *tok <= KW_D7)
1835         {
1836                 // Dx,Dy,#<adjustment>
1837                 inst |= (0 << 3);   // R/M
1838                 inst |= (*tok++ & 7);
1839
1840                 if (*tok != ',' && tok[2] != ',')
1841                         return error("missing comma");
1842
1843                 if (tok[1] < KW_D0 && tok[1] > KW_D7)
1844                         return error(syntax_error);
1845
1846                 inst |= ((tok[1] & 7)<<9);
1847                 tok = tok + 3;
1848                 D_word(inst);
1849                 // Fall through for adjustment (common in both valid cases)
1850         }
1851         else if (*tok == '-')
1852         {
1853                 // -(Ax),-(Ay),#<adjustment>
1854                 inst |= (1 << 3);   // R/M
1855                 tok++;  // eat the minus
1856
1857                 if ((*tok != '(') && (tok[2]!=')') && (tok[3]!=',') && (tok[4] != '-') && (tok[5] != '(') && (tok[7] != ')') && (tok[8] != ','))
1858                         return error(syntax_error);
1859
1860                 if (tok[1] < KW_A0 && tok[1] > KW_A7)
1861                         return error(syntax_error);
1862
1863                 if (tok[5] < KW_A0 && tok[6] > KW_A7)
1864                         return error(syntax_error);
1865
1866                 inst |= ((tok[1] & 7) << 0);
1867                 inst |= ((tok[6] & 7) << 9);
1868                 tok = tok + 9;
1869                 D_word(inst);
1870                 // Fall through for adjustment (common in both valid cases)
1871         }
1872         else
1873                 return error("invalid syntax");
1874
1875         if ((*tok != CONST) && (*tok != SYMBOL) && (*tok != '-'))
1876                 return error(syntax_error);
1877
1878         if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
1879                 return ERROR;
1880
1881         if ((a0exattr & DEFINED) == 0)
1882                 return error(undef_error);
1883
1884         if (a0exval + 0x8000 > 0x10000)
1885                 return error("");
1886
1887         if (*tok != EOL)
1888                 return error(extra_stuff);
1889
1890         D_word((a0exval & 0xFFFF));
1891
1892         return OK;
1893 }
1894
1895
1896 //
1897 // rtm Rn
1898 //
1899 int m_rtm(WORD inst, WORD siz)
1900 {
1901         CHECKNO20;
1902
1903         if (am0 == DREG)
1904         {
1905                 inst |= a0reg;
1906         }
1907         else if (am0 == AREG)
1908         {
1909                 inst |= (1 << 3) + a0reg;
1910         }
1911         else
1912                 return error("rtm only allows data or address registers.");
1913
1914         D_word(inst);
1915
1916         return OK;
1917 }
1918
1919
1920 //
1921 // rtd #n
1922 //
1923 int m_rtd(WORD inst, WORD siz)
1924 {
1925         CHECK00;
1926
1927         if (a0exattr & DEFINED)
1928         {
1929                 if (a0exattr & TDB)
1930                         return error(abs_error);
1931
1932                 if ((a0exval + 0x8000) <= 0x7FFF)
1933                         return error(range_error);
1934
1935                 D_word(inst);
1936                 D_word(a0exval);
1937         }
1938         else
1939                 return error(undef_error);
1940
1941         return OK;
1942 }
1943
1944
1945 //
1946 // trapcc
1947 //
1948 int m_trapcc(WORD inst, WORD siz)
1949 {
1950         CHECK00;
1951
1952         if (am0 == AM_NONE)
1953         {
1954                 D_word(inst);
1955         }
1956         else if (am0 == IMMED)
1957         {
1958                 if (siz == SIZW)
1959                 {
1960                         if (a0exval < 0x10000)
1961                         {
1962                                 inst |= 2;
1963                                 D_word(inst);
1964                                 D_word(a0exval);
1965                         }
1966                         else
1967                                 return error("Immediate value too big");
1968                 }
1969                 else //DOTL
1970                 {
1971                         inst |= 3;
1972                         D_word(inst);
1973                         D_long(a0exval);
1974                 }
1975         }
1976         else
1977                 return error("Invalid parameter for trapcc");
1978
1979         return OK;
1980 }
1981
1982
1983 //
1984 // cinvl/p/a (68040/68060)
1985 //
1986 int m_cinv(WORD inst, WORD siz)
1987 {
1988         CHECKNO40;
1989
1990         if (am1 == AM_NONE)
1991                 inst |= (0 << 6) | (a1reg);
1992         switch (a0reg)
1993         {
1994         case 0:     // KW_IC40
1995                 inst |= (2 << 6) | (a1reg);
1996                 break;
1997         case 1:     // KW_DC40
1998                 inst |= (1 << 6) | (a1reg);
1999                 break;
2000         case 2:     // KW_BC40
2001                 inst |= (3 << 6) | (a1reg);
2002                 break;
2003         }
2004
2005         D_word(inst);
2006         return OK;
2007 }
2008
2009
2010 int m_fpusavrest(WORD inst, WORD siz)
2011 {
2012         inst |= am0 | a0reg;
2013         D_word(inst);
2014         ea0gen(siz);
2015
2016         return OK;
2017 }
2018
2019
2020 //
2021 // cpSAVE/cpRESTORE (68020, 68030)
2022 //
2023 int m_cprest(WORD inst, WORD siz)
2024 {
2025         if (activecpu & !(CPU_68020 | CPU_68030))
2026                 return error(unsupport);
2027
2028         return m_fpusavrest(inst, siz);
2029
2030 }
2031
2032
2033 //
2034 // FSAVE/FRESTORE (68040, 68060)
2035 //
2036 int m_frestore(WORD inst, WORD siz)
2037 {
2038         if ((!(activecpu & (CPU_68040 | CPU_68060))) ||
2039                 (activefpu&(FPU_68881 | FPU_68882)))
2040                 return error(unsupport);
2041
2042         return m_fpusavrest(inst, siz);
2043 }
2044
2045
2046 //
2047 // movec (68010, 68020, 68030, 68040, 68060, CPU32)
2048 //
2049 int m_movec(WORD inst, WORD siz)
2050 {
2051         CHECK00;
2052
2053         if (am0 == DREG || am0 == AREG)
2054         {
2055                 // movec Rn,Rc
2056                 inst |= 1;
2057                 D_word(inst);
2058
2059                 if (am0 == DREG)
2060                 {
2061                         inst = (0 << 15) + (a0reg << 12) + CREGlut[a1reg];
2062                         D_word(inst);
2063                 }
2064                 else
2065                 {
2066                         inst = (1 << 15) + (a0reg << 12) + CREGlut[a1reg];
2067                         D_word(inst);
2068                 }
2069         }
2070         else
2071         {
2072                 // movec Rc,Rn
2073                 D_word(inst);
2074
2075                 if (am1 == DREG)
2076                 {
2077                         inst = (0 << 15) + (a1reg << 12) + CREGlut[a0reg];
2078                         D_word(inst);
2079                 }
2080                 else
2081                 {
2082                         inst = (1 << 15) + (a1reg << 12) + CREGlut[a0reg];
2083                         D_word(inst);
2084                 }
2085         }
2086
2087         return OK;
2088 }
2089
2090
2091 //
2092 // moves (68010, 68020, 68030, 68040, CPU32)
2093 //
2094 int m_moves(WORD inst, WORD siz)
2095 {
2096         if (activecpu & !(CPU_68020 | CPU_68030 | CPU_68040))
2097                 return error(unsupport);
2098
2099         if (siz == SIZB)
2100                 inst |= 0 << 6;
2101         else if (siz == SIZL)
2102                 inst |= 2 << 6;
2103         else // SIZW/SIZN
2104                 inst |= 1 << 6;
2105
2106         if (am0 == DREG)
2107         {
2108                 inst |= am1 | a1reg;
2109                 D_word(inst);
2110                 inst = (a0reg << 12) | (1 << 11) | (0 << 15);
2111                 D_word(inst);
2112         }
2113         else if (am0 == AREG)
2114         {
2115                 inst |= am1 | a1reg;
2116                 D_word(inst);
2117                 inst = (a0reg << 12) | (1 << 11) | (1 << 15);
2118                 D_word(inst);
2119         }
2120         else
2121         {
2122                 if (am1 == DREG)
2123                 {
2124                         inst |= am0 | a0reg;
2125                         D_word(inst);
2126                         inst = (a1reg << 12) | (0 << 11) | (0 << 15);
2127                         D_word(inst);
2128                 }
2129                 else
2130                 {
2131                         inst |= am0 | a0reg;
2132                         D_word(inst);
2133                         inst = (a1reg << 12) | (0 << 11) | (1 << 15);
2134                         D_word(inst);
2135                 }
2136         }
2137
2138         return OK;
2139 }
2140
2141
2142 //
2143 // pflusha (68030, 68040)
2144 //
2145 int m_pflusha(WORD inst, WORD siz)
2146 {
2147         if (activecpu == CPU_68030)
2148         {
2149                 D_word(inst);
2150                 inst = (1 << 13) | (1 << 10) | (0 << 5) | 0;
2151                 D_word(inst);
2152                 return OK;
2153         }
2154         else if (activecpu == CPU_68040)
2155         {
2156                 inst = B16(11110101, 00011000);
2157                 D_word(inst);
2158                 return OK;
2159         }
2160         else
2161                 return error(unsupport);
2162
2163         return OK;
2164 }
2165
2166
2167 //
2168 // pflush (68030, 68040, 68060)
2169 //
2170 int m_pflush(WORD inst, WORD siz)
2171 {
2172         if (activecpu == CPU_68030)
2173         {
2174                 // PFLUSH FC, MASK
2175                 // PFLUSH FC, MASK, < ea >
2176                 WORD mask, fc;
2177
2178                 switch ((int)*tok)
2179                 {
2180                 case '#':
2181                         tok++;
2182
2183                         if (*tok != CONST && *tok != SYMBOL)
2184                                 return error("function code should be an expression");
2185
2186                         if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2187                                 return ERROR;
2188
2189                         if ((a0exattr & DEFINED) == 0)
2190                                 return error("function code immediate should be defined");
2191
2192                         if (a0exval > 7)
2193                                 return error("function code out of range (0-7)");
2194
2195                         fc = (uint16_t)a0exval;
2196                         break;
2197                 case KW_D0:
2198                 case KW_D1:
2199                 case KW_D2:
2200                 case KW_D3:
2201                 case KW_D4:
2202                 case KW_D5:
2203                 case KW_D6:
2204                 case KW_D7:
2205                         fc = (1 << 4) | (*tok++ & 7);
2206                         break;
2207                 case KW_SFC:
2208                         fc = 0;
2209                         tok++;
2210                         break;
2211                 case KW_DFC:
2212                         fc = 1;
2213                         tok++;
2214                         break;
2215                 default:
2216                         return error(syntax_error);
2217                 }
2218
2219                 if (*tok++ != ',')
2220                         return error("comma exptected");
2221
2222                 if (*tok++ != '#')
2223                         return error("mask should be an immediate value");
2224
2225                 if (*tok != CONST && *tok != SYMBOL)
2226                         return error("mask is supposed to be immediate");
2227
2228                 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2229                         return ERROR;
2230
2231                 if ((a0exattr & DEFINED) == 0)
2232                         return error("mask immediate value should be defined");
2233
2234                 if (a0exval > 7)
2235                         return error("function code out of range (0-7)");
2236
2237                 mask = (uint16_t)a0exval << 5;
2238
2239                 if (*tok == EOL)
2240                 {
2241                         // PFLUSH FC, MASK
2242                         D_word(inst);
2243                         inst = (1 << 13) | fc | mask | (4 << 10);
2244                         D_word(inst);
2245                         return OK;
2246                 }
2247                 else if (*tok == ',')
2248                 {
2249                         // PFLUSH FC, MASK, < ea >
2250                         tok++;
2251
2252                         if (amode(0) == ERROR)
2253                                 return ERROR;
2254
2255                         if (*tok != EOL)
2256                                 return error(extra_stuff);
2257
2258                         if (am0 == AIND || am0 == ABSW || am0 == ABSL || am0 == ADISP || am0 == ADISP || am0 == AINDEXED || am0 == ABASE || am0 == MEMPOST || am0 == MEMPRE)
2259                         {
2260                                 inst |= am0 | a0reg;
2261                                 D_word(inst);
2262                                 inst = (1 << 13) | fc | mask | (6 << 10);
2263                                 D_word(inst);
2264                                 ea0gen(siz);
2265                                 return OK;
2266                         }
2267                         else
2268                                 return error("unsupported addressing mode");
2269
2270                 }
2271                 else
2272                         return error(syntax_error);
2273
2274                 return OK;
2275         }
2276         else if (activecpu == CPU_68040 || activecpu == CPU_68060)
2277         {
2278                 // PFLUSH(An)
2279                 // PFLUSHN(An)
2280                 if (*tok != '(' && tok[2] != ')')
2281                         return error(syntax_error);
2282
2283                 if (tok[1] < KW_A0 && tok[1] > KW_A7)
2284                         return error("expected (An)");
2285
2286                 if ((inst & 7) == 7)
2287                         // With pflushn/pflush there's no easy way to distinguish between
2288                         // the two in 68040 mode. Ideally the opcode bitfields would have
2289                         // been hardcoded in 68ktab but there is aliasing between 68030
2290                         // and 68040 opcode. So we just set the 3 lower bits to 1 in
2291                         // pflushn inside 68ktab and detect it here.
2292                         inst = (inst & 0xff8) | 8;
2293
2294                 inst |= (tok[1] & 7) | (5 << 8);
2295
2296                 if (tok[3] != EOL)
2297                         return error(extra_stuff);
2298
2299                 D_word(inst);
2300         }
2301         else
2302                 return error(unsupport);
2303
2304         return OK;
2305 }
2306
2307
2308 //
2309 // pflushan (68040, 68060)
2310 //
2311 int m_pflushan(WORD inst, WORD siz)
2312 {
2313         if (activecpu == CPU_68040 || activecpu == CPU_68060)
2314                 D_word(inst);
2315
2316         return OK;
2317 }
2318
2319
2320 //
2321 // pflushr (68851)
2322 //
2323 int m_pflushr(WORD inst, WORD siz)
2324 {
2325         CHECKNO20;
2326
2327         WORD flg = inst;                                        // Save flag bits
2328         inst &= ~0x3F;                                          // Clobber flag bits in instr
2329
2330         // Install "standard" instr size bits
2331         if (flg & 4)
2332                 inst |= siz_6[siz];
2333
2334         if (flg & 16)
2335         {
2336                 // OR-in register number
2337                 if (flg & 8)
2338                         inst |= reg_9[a1reg];           // ea1reg in bits 9..11
2339                 else
2340                         inst |= reg_9[a0reg];           // ea0reg in bits 9..11
2341         }
2342
2343         if (flg & 1)
2344         {
2345                 // Use am1
2346                 inst |= am1 | a1reg;                    // Get ea1 into instr
2347                 D_word(inst);                                   // Deposit instr
2348
2349                 // Generate ea0 if requested
2350                 if (flg & 2)
2351                         ea0gen(siz);
2352
2353                 ea1gen(siz);                                    // Generate ea1
2354         }
2355         else
2356         {
2357                 // Use am0
2358                 inst |= am0 | a0reg;                    // Get ea0 into instr
2359                 D_word(inst);                                   // Deposit instr
2360                 ea0gen(siz);                                    // Generate ea0
2361
2362                 // Generate ea1 if requested
2363                 if (flg & 2)
2364                         ea1gen(siz);
2365         }
2366
2367         D_word(B16(10100000, 00000000));
2368         return OK;
2369 }
2370
2371
2372 //
2373 // ploadr, ploadw (68030)
2374 //
2375 int m_pload(WORD inst, WORD siz, WORD extension)
2376 {
2377         // TODO: 68851 support is not added yet.
2378         // None of the ST series of computers had a 68020 + 68851 socket and since
2379         // this is an Atari targetted assembler...
2380         CHECKNO30;
2381
2382         inst |= am1;
2383         D_word(inst);
2384
2385         switch (am0)
2386         {
2387         case CREG:
2388                 if (a0reg == KW_SFC - KW_SFC)
2389                         inst = 0;
2390                 else if (a0reg == KW_DFC - KW_SFC)
2391                         inst = 1;
2392                 else
2393                         return error("illegal control register specified");
2394
2395                 break;
2396         case DREG:
2397                 inst = (1 << 3) | a0reg;
2398                 break;
2399         case IMMED:
2400                 if ((a0exattr & DEFINED) == 0)
2401                         return error("constant value must be defined");
2402
2403                 inst = (2 << 3) | (uint16_t)a0exval;
2404                 break;
2405         }
2406
2407         inst |= extension | (1 << 13);
2408         D_word(inst);
2409
2410         ea1gen(siz);
2411
2412         return OK;
2413 }
2414
2415
2416 int m_ploadr(WORD inst, WORD siz)
2417 {
2418         return m_pload(inst, siz, 1 << 9);
2419 }
2420
2421
2422 int m_ploadw(WORD inst, WORD siz)
2423 {
2424         return m_pload(inst, siz, 0 << 9);
2425 }
2426
2427
2428 //
2429 // pmove (68030/68851)
2430 //
2431 int m_pmove(WORD inst, WORD siz)
2432 {
2433         int inst2,reg;
2434
2435         // TODO: 68851 support is not added yet. None of the ST series of
2436         // computers had a 68020 + 68851 socket and since this is an Atari
2437         // targetted assembler.... (same for 68EC030)
2438         CHECKNO30;
2439
2440         inst2 = inst & (1 << 8);        // Copy the flush bit over to inst2 in case we're called from m_pmovefd
2441         inst &= ~(1 << 8);                      // And mask it out
2442
2443         if (am0 == CREG)
2444         {
2445                 reg = a0reg;
2446                 inst2 |= (1 << 9);
2447         }
2448         else if (am1 == CREG)
2449         {
2450                 reg = a1reg;
2451                 inst2 |= 0;
2452         }
2453         else
2454                 return error("pmove sez: Wut?");
2455
2456         // The instruction is a quad-word (8 byte) operation
2457         // for the CPU root pointer and the supervisor root pointer.
2458         // It is a long-word operation for the translation control register
2459         // and the transparent translation registers(TT0 and TT1).
2460         // It is a word operation for the MMU status register.
2461
2462         if (((reg == (KW_URP - KW_SFC)) || (reg == (KW_SRP - KW_SFC)))
2463                 && ((siz != SIZD) && (siz != SIZN)))
2464                 return error(siz_error);
2465
2466         if (((reg == (KW_TC - KW_SFC)) || (reg == (KW_TT0 - KW_SFC)) || (reg == (KW_TT1 - KW_SFC)))
2467                 && ((siz != SIZL) && (siz != SIZN)))
2468                 return error(siz_error);
2469
2470         if ((reg == (KW_MMUSR - KW_SFC)) && ((siz != SIZW) && (siz != SIZN)))
2471                 return error(siz_error);
2472
2473         if (am0 == CREG)
2474         {
2475                 inst |= am1 | a1reg;
2476                 D_word(inst);
2477         }
2478         else if (am1 == CREG)
2479         {
2480                 inst |= am0 | a0reg;
2481                 D_word(inst);
2482         }
2483
2484         switch (reg + KW_SFC)
2485         {
2486         case KW_TC:
2487                 inst2 |= (0 << 10) + (1 << 14); break;
2488         case KW_SRP:
2489                 inst2 |= (2 << 10) + (1 << 14); break;
2490         case KW_CRP:
2491                 inst2 |= (3 << 10) + (1 << 14); break;
2492         case KW_TT0:
2493                 inst2 |= (2 << 10) + (0 << 13); break;
2494         case KW_TT1:
2495                 inst2 |= (3 << 10) + (0 << 13); break;
2496         case KW_MMUSR:
2497                 if (am0 == CREG)
2498                         inst2 |= (1 << 9) + (3 << 13);
2499                 else
2500                         inst2 |= (0 << 9) + (3 << 13);
2501                 break;
2502         default:
2503                 return error("unsupported register");
2504                 break;
2505         }
2506
2507         D_word(inst2);
2508
2509         if (am0 == CREG)
2510                 ea1gen(siz);
2511         else if (am1 == CREG)
2512                 ea0gen(siz);
2513
2514         return OK;
2515 }
2516
2517
2518 //
2519 // pmovefd (68030)
2520 //
2521 int m_pmovefd(WORD inst, WORD siz)
2522 {
2523         CHECKNO30;
2524
2525         return m_pmove(inst | (1 << 8), siz);
2526 }
2527
2528
2529 //
2530 // ptrapcc (68851)
2531 //
2532 int m_ptrapcc(WORD inst, WORD siz)
2533 {
2534         CHECKNO20;
2535         // We stash the 5 condition bits inside the opcode in 68ktab (bits 0-4),
2536         // so we need to extract them first and fill in the clobbered bits.
2537         WORD opcode = inst & 0x1F;
2538         inst = (inst & 0xFFE0) | (0x18);
2539
2540         if (siz == SIZW)
2541         {
2542                 inst |= 2;
2543                 D_word(inst);
2544                 D_word(opcode);
2545                 D_word(a0exval);
2546         }
2547         else if (siz == SIZL)
2548         {
2549                 inst |= 3;
2550                 D_word(inst);
2551                 D_word(opcode);
2552                 D_long(a0exval);
2553         }
2554         else if (siz == SIZN)
2555         {
2556                 inst |= 4;
2557                 D_word(inst);
2558                 D_word(opcode);
2559         }
2560
2561         return OK;
2562 }
2563
2564
2565 //
2566 // ptestr, ptestw (68030)
2567 //
2568 int m_ptest(WORD inst, WORD siz)
2569 {
2570         CHECKNO30;
2571
2572         if (activecpu == CPU_68030)
2573                 return error("Not implemented yet.");
2574         else if (activecpu == CPU_68040)
2575                 return error("Not implemented yet.");
2576
2577         return ERROR;
2578 }
2579
2580 //////////////////////////////////////////////////////////////////////////////
2581 //
2582 // 68020/30/40/60 instructions
2583 // Note: the map of which instructions are allowed on which CPUs came from the
2584 // 68060 manual, section D-1 (page 392 of the PDF). The current implementation
2585 // is missing checks for the EC models which have a simplified FPU.
2586 //
2587 //////////////////////////////////////////////////////////////////////////////
2588
2589
2590 #define FPU_NOWARN 0
2591 #define FPU_FPSP   1
2592
2593
2594 //
2595 // Generate a FPU opcode
2596 //
2597 static inline int gen_fpu(WORD inst, WORD siz, WORD opmode, WORD emul)
2598 {
2599         if (am0 < AM_NONE)      // Check first operand for ea or fp - is this right?
2600         {
2601                 inst |= (1 << 9);       // Bolt on FPU id
2602                 inst |= am0;
2603
2604                 //if (am0 == DREG || am0 == AREG)
2605                         inst |= a0reg;
2606
2607                 D_word(inst);
2608                 inst = 1 << 14; // R/M field (we have ea so have to set this to 1)
2609
2610                 switch (siz)
2611                 {
2612                 case SIZB:      inst |= (6 << 10); break;
2613                 case SIZW:      inst |= (4 << 10); break;
2614                 case SIZL:      inst |= (0 << 10); break;
2615                 case SIZN:
2616                 case SIZS:      inst |= (1 << 10); break;
2617                 case SIZD:      inst |= (5 << 10); break;
2618                 case SIZX:      inst |= (2 << 10); break;
2619                 case SIZP:
2620                         inst |= (3 << 10);
2621
2622                         if (emul)
2623                                 warn("This encoding will cause an unimplemented data type exception in the MC68040 to allow emulation in software.");
2624
2625                         break;
2626                 default:
2627                         return error("Something bad happened, possibly, in gen_fpu.");
2628                         break;
2629                 }
2630
2631                 inst |= (a1reg << 7);
2632                 inst |= opmode;
2633                 D_word(inst);
2634                 ea0gen(siz);
2635         }
2636         else
2637         {
2638                 inst |= (1 << 9);       // Bolt on FPU id
2639                 D_word(inst);
2640                 inst = 0;
2641                 inst = a0reg << 10;
2642                 inst |= (a1reg << 7);
2643                 inst |= opmode;
2644                 D_word(inst);
2645         }
2646
2647         if ((emul & FPU_FPSP) && (activefpu == (FPU_68040 | FPU_68060)))
2648                 warn("Instruction is emulated in 68040/060");
2649
2650         return OK;
2651 }
2652
2653
2654 //
2655 // fabs (6888X, 68040FPSP, 68060FPSP)
2656 //
2657 int m_fabs(WORD inst, WORD siz)
2658 {
2659         CHECKNOFPU;
2660         return gen_fpu(inst, siz, B8(00011000), FPU_NOWARN);
2661 }
2662
2663
2664 //
2665 // fsabs (68040, 68060)
2666 //
2667 int m_fsabs(WORD inst, WORD siz)
2668 {
2669         CHECKNO40;
2670         if (activefpu == FPU_68040)
2671                 return gen_fpu(inst, siz, B8(01011000), FPU_NOWARN);
2672
2673         return error("Unsupported in current FPU");
2674 }
2675
2676
2677 //
2678 // fdabs (68040, 68060)
2679 //
2680 int m_fdabs(WORD inst, WORD siz)
2681 {
2682         if (activefpu == FPU_68040)
2683                 return gen_fpu(inst, siz, B8(01011100), FPU_NOWARN);
2684
2685         return error("Unsupported in current FPU");
2686 }
2687
2688
2689 //
2690 // facos (6888X, 68040FPSP, 68060FPSP)
2691 //
2692 int m_facos(WORD inst, WORD siz)
2693 {
2694         CHECKNOFPU;
2695         return gen_fpu(inst, siz, B8(00011100), FPU_FPSP);
2696 }
2697
2698
2699 //
2700 // fadd (6888X, 68040, 68060)
2701 //
2702 int m_fadd(WORD inst, WORD siz)
2703 {
2704         CHECKNOFPU;
2705         return gen_fpu(inst, siz, B8(00100010), FPU_NOWARN);
2706 }
2707
2708
2709 //
2710 // fsadd (68040, 68060)
2711 //
2712 int m_fsadd(WORD inst, WORD siz)
2713 {
2714         if (activefpu & (FPU_68040 | FPU_68060))
2715                 return gen_fpu(inst, siz, B8(01100010), FPU_NOWARN);
2716
2717         return error("Unsupported in current FPU");
2718 }
2719
2720
2721 //
2722 // fxadd (68040)
2723 //
2724 int m_fdadd(WORD inst, WORD siz)
2725 {
2726         if (activefpu & (FPU_68040 | FPU_68060))
2727                 return gen_fpu(inst, siz, B8(01100110), FPU_NOWARN);
2728
2729         return error("Unsupported in current FPU");
2730 }
2731
2732
2733 //
2734 // fasin (6888X, 68040FPSP, 68060FPSP)
2735 //
2736 int m_fasin(WORD inst, WORD siz)
2737 {
2738         CHECKNOFPU;
2739         return gen_fpu(inst, siz, B8(00001100), FPU_FPSP);
2740 }
2741
2742
2743 //
2744 // fatan (6888X, 68040FPSP, 68060FPSP)
2745 //
2746 int m_fatan(WORD inst, WORD siz)
2747 {
2748         CHECKNOFPU;
2749         return gen_fpu(inst, siz, B8(00001010), FPU_FPSP);
2750 }
2751
2752
2753 //
2754 // fatanh (6888X, 68040FPSP, 68060FPSP)
2755 //
2756 int m_fatanh(WORD inst, WORD siz)
2757 {
2758         CHECKNOFPU;
2759         return gen_fpu(inst, siz, B8(00001101), FPU_FPSP);
2760 }
2761
2762
2763 //
2764 // fcmp (6888X, 68040, 68060)
2765 //
2766 int m_fcmp(WORD inst, WORD siz)
2767 {
2768         CHECKNOFPU;
2769         return gen_fpu(inst, siz, B8(00111000), FPU_FPSP);
2770 }
2771
2772
2773 //
2774 // fcos (6888X, 68040FPSP, 68060FPSP)
2775 //
2776 int m_fcos(WORD inst, WORD siz)
2777 {
2778         CHECKNOFPU;
2779         return gen_fpu(inst, siz, B8(00011101), FPU_FPSP);
2780 }
2781
2782
2783 //
2784 // fcosh (6888X, 68040FPSP, 68060FPSP)
2785 //
2786 int m_fcosh(WORD inst, WORD siz)
2787 {
2788         CHECKNOFPU;
2789         return gen_fpu(inst, siz, B8(00011001), FPU_FPSP);
2790 }
2791
2792
2793 //
2794 // fdbcc (6888X, 68040, 68060FPSP)
2795 //
2796 int m_fdbcc(WORD inst, WORD siz)
2797 {
2798         CHECKNOFPU;
2799         WORD opcode = inst & 0x3F;      // Grab conditional bitfield
2800
2801         inst &= ~0x3F;
2802         inst |= 1 << 3;
2803
2804         siz = siz;
2805         inst |= a0reg;
2806         D_word(inst);
2807         D_word(opcode);
2808
2809         if (a1exattr & DEFINED)
2810         {
2811                 if ((a1exattr & TDB) != cursect)
2812                         return error(rel_error);
2813
2814                 uint32_t v = (uint32_t)a1exval - sloc;
2815
2816                 if ((v + 0x8000) > 0x10000)
2817                         return error(range_error);
2818
2819                 D_word(v);
2820         }
2821         else
2822         {
2823                 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
2824                 D_word(0);
2825         }
2826
2827         if (activefpu == FPU_68060)
2828                 warn("Instruction is emulated in 68060");
2829
2830         return OK;
2831 }
2832
2833
2834 //
2835 // fdiv (6888X, 68040, 68060)
2836 //
2837 int m_fdiv(WORD inst, WORD siz)
2838 {
2839         CHECKNOFPU;
2840         return gen_fpu(inst, siz, B8(00100000), FPU_NOWARN);
2841 }
2842
2843
2844 //
2845 // fsdiv (68040, 68060)
2846 //
2847 int m_fsdiv(WORD inst, WORD siz)
2848 {
2849         if (activefpu & (FPU_68040 | FPU_68060))
2850                 return gen_fpu(inst, siz, B8(01100000), FPU_NOWARN);
2851
2852         return error("Unsupported in current FPU");
2853 }
2854
2855
2856 //
2857 // fddiv (68040, 68060)
2858 //
2859 int m_fddiv(WORD inst, WORD siz)
2860 {
2861         if (activefpu & (FPU_68040 | FPU_68060))
2862                 return gen_fpu(inst, siz, B8(01100100), FPU_NOWARN);
2863
2864         return error("Unsupported in current FPU");
2865 }
2866
2867
2868 //
2869 // fetox (6888X, 68040FPSP, 68060FPSP)
2870 //
2871 int m_fetox(WORD inst, WORD siz)
2872 {
2873         CHECKNOFPU;
2874         return gen_fpu(inst, siz, B8(00010000), FPU_FPSP);
2875 }
2876
2877
2878 //
2879 // fetoxm1 (6888X, 68040FPSP, 68060FPSP)
2880 //
2881 int m_fetoxm1(WORD inst, WORD siz)
2882 {
2883         CHECKNOFPU;
2884         return gen_fpu(inst, siz, B8(00001000), FPU_FPSP);
2885 }
2886
2887
2888 //
2889 // fgetexp (6888X, 68040FPSP, 68060FPSP)
2890 //
2891 int m_fgetexp(WORD inst, WORD siz)
2892 {
2893         CHECKNOFPU;
2894         return gen_fpu(inst, siz, B8(00011110), FPU_FPSP);
2895 }
2896
2897
2898 //
2899 // fgetman (6888X, 68040FPSP, 68060FPSP)
2900 //
2901 int m_fgetman(WORD inst, WORD siz)
2902 {
2903         CHECKNOFPU;
2904         return gen_fpu(inst, siz, B8(00011111), FPU_FPSP);
2905 }
2906
2907
2908 //
2909 // fint (6888X, 68040FPSP, 68060)
2910 //
2911 int m_fint(WORD inst, WORD siz)
2912 {
2913         if (am1 == AM_NONE)
2914                 // special case - fint fpx = fint fpx,fpx
2915                 a1reg = a0reg;
2916
2917         if (activefpu == FPU_68040)
2918                 warn("Instruction is emulated in 68040");
2919
2920         return gen_fpu(inst, siz, B8(00000001), FPU_NOWARN);
2921 }
2922
2923
2924 //
2925 // fintrz (6888X, 68040FPSP, 68060)
2926 //
2927 int m_fintrz(WORD inst, WORD siz)
2928 {
2929         if (am1 == AM_NONE)
2930                 // special case - fintrz fpx = fintrz fpx,fpx
2931                 a1reg = a0reg;
2932
2933         if (activefpu == FPU_68040)
2934                 warn("Instruction is emulated in 68040");
2935
2936         return gen_fpu(inst, siz, B8(00000011), FPU_NOWARN);
2937 }
2938
2939
2940 //
2941 // flog10 (6888X, 68040FPSP, 68060FPSP)
2942 //
2943 int m_flog10(WORD inst, WORD siz)
2944 {
2945         CHECKNOFPU;
2946         return gen_fpu(inst, siz, B8(00010101), FPU_FPSP);
2947 }
2948
2949
2950 //
2951 // flog2 (6888X, 68040FPSP, 68060FPSP)
2952 //
2953 int m_flog2(WORD inst, WORD siz)
2954 {
2955         CHECKNOFPU;
2956         return gen_fpu(inst, siz, B8(00010110), FPU_FPSP);
2957 }
2958
2959
2960 //
2961 // flogn (6888X, 68040FPSP, 68060FPSP)
2962 //
2963 int m_flogn(WORD inst, WORD siz)
2964 {
2965         CHECKNOFPU;
2966         return gen_fpu(inst, siz, B8(00010100), FPU_FPSP);
2967 }
2968
2969
2970 //
2971 // flognp1 (6888X, 68040FPSP, 68060FPSP)
2972 //
2973 int m_flognp1(WORD inst, WORD siz)
2974 {
2975         CHECKNOFPU;
2976         return gen_fpu(inst, siz, B8(00000110), FPU_FPSP);
2977 }
2978
2979
2980 //
2981 // fmod (6888X, 68040FPSP, 68060FPSP)
2982 //
2983 int m_fmod(WORD inst, WORD siz)
2984 {
2985         CHECKNOFPU;
2986         return gen_fpu(inst, siz, B8(00100001), FPU_FPSP);
2987 }
2988
2989
2990 //
2991 // fmove (6888X, 68040, 68060)
2992 //
2993 int m_fmove(WORD inst, WORD siz)
2994 {
2995         CHECKNOFPU;
2996
2997         // EA to register
2998         if ((am0 == FREG) && (am1 < AM_USP))
2999         {
3000                 // fpx->ea
3001                 // EA
3002                 inst |= am1 | a1reg;
3003                 D_word(inst);
3004
3005                 // R/M
3006                 inst = 3 << 13;
3007
3008                 // Source specifier
3009                 switch (siz)
3010                 {
3011                 case SIZB:      inst |= (6 << 10); break;
3012                 case SIZW:      inst |= (4 << 10); break;
3013                 case SIZL:      inst |= (0 << 10); break;
3014                 case SIZN:
3015                 case SIZS:      inst |= (1 << 10); break;
3016                 case SIZD:      inst |= (5 << 10); break;
3017                 case SIZX:      inst |= (2 << 10); break;
3018                 case SIZP:      inst |= (3 << 10);
3019                         // In P size we have 2 cases: {#k} where k is immediate
3020                         // and {Dn} where Dn=Data register
3021                         if (bfparam1)
3022                         {
3023                                 // Dn
3024                                 inst |= 1 << 12;
3025                                 inst |= bfval1 << 4;
3026                         }
3027                         else
3028                         {
3029                                 // #k
3030                                 if (bfval1 > 63 && bfval1 < -64)
3031                                         return error("K-factor must be between -64 and 63");
3032
3033                                 inst |= bfval1 & 127;
3034                         }
3035
3036                         break;
3037                 default:
3038                         return error("Something bad happened, possibly.");
3039                         break;
3040                 }
3041
3042                 // Destination specifier
3043                 inst |= (a0reg << 7);
3044
3045                 // Opmode
3046                 inst |= 0;
3047
3048                 D_word(inst);
3049                 ea1gen(siz);
3050         }
3051         else if ((am0 < AM_USP) && (am1 == FREG))
3052         {
3053                 // ea->fpx
3054
3055                 // EA
3056                 inst |= am0 | a0reg;
3057                 D_word(inst);
3058
3059                 // R/M
3060                 inst = 1 << 14;
3061
3062                 // Source specifier
3063                 switch (siz)
3064                 {
3065                 case SIZB:      inst |= (6 << 10); break;
3066                 case SIZW:      inst |= (4 << 10); break;
3067                 case SIZL:      inst |= (0 << 10); break;
3068                 case SIZN:
3069                 case SIZS:      inst |= (1 << 10); break;
3070                 case SIZD:      inst |= (5 << 10); break;
3071                 case SIZX:      inst |= (2 << 10); break;
3072                 case SIZP:      inst |= (3 << 10); break;
3073                 default:
3074                         return error("Something bad happened, possibly.");
3075                         break;
3076                 }
3077
3078                 // Destination specifier
3079                 inst |= (a1reg << 7);
3080
3081                 // Opmode
3082                 inst |= 0;
3083
3084                 D_word(inst);
3085                 ea0gen(siz);
3086         }
3087         else if ((am0 == FREG) && (am1 == FREG))
3088         {
3089                 // register-to-register
3090                 // Essentially ea to register with R/0=0
3091
3092                 // EA
3093                 D_word(inst);
3094
3095                 // R/M
3096                 inst = 0 << 14;
3097
3098                 // Source specifier
3099                 if (siz != SIZX && siz != SIZN)
3100                         return error("Invalid size");
3101
3102                 // Source register
3103                 inst |= (a0reg << 10);
3104
3105                 // Destination register
3106                 inst |= (a1reg << 7);
3107
3108                 D_word(inst);
3109         }
3110
3111         return OK;
3112 }
3113
3114
3115 //
3116 // fmove (6888X, 68040, 68060)
3117 //
3118 int m_fmovescr(WORD inst, WORD siz)
3119 {
3120         CHECKNOFPU;
3121
3122         // Move Floating-Point System Control Register (FPCR)
3123         // ea
3124         // dr
3125         // Register select
3126         if ((am0 == FPSCR) && (am1 < AM_USP))
3127         {
3128                 inst |= am1 | a1reg;
3129                 D_word(inst);
3130                 inst = (1 << 13) + (1 << 15);
3131                 inst |= a0reg;
3132                 D_word(inst);
3133                 ea1gen(siz);
3134                 return OK;
3135         }
3136         else if ((am1 == FPSCR) && (am0 < AM_USP))
3137         {
3138                 inst |= am0 | a0reg;
3139                 D_word(inst);
3140                 inst = (0 << 13) + (1 << 15);
3141                 inst |= a1reg;
3142                 D_word(inst);
3143                 ea0gen(siz);
3144                 return OK;
3145         }
3146
3147         return error("m_fmovescr says: wut?");
3148 }
3149
3150 //
3151 // fsmove/fdmove (68040, 68060)
3152 //
3153 int m_fsmove(WORD inst, WORD siz)
3154 {
3155         if (!(activefpu & (FPU_68040 | FPU_68060)))
3156                 return error("Unsupported in current FPU");
3157
3158         return error("Not implemented yet.");
3159
3160 #if 0
3161         if (activefpu == FPU_68040)
3162                 return gen_fpu(inst, siz, B8(01100100), FPU_P_EMUL);
3163         else
3164                 return error("Unsupported in current FPU");
3165 #endif
3166 }
3167
3168
3169 int m_fdmove(WORD inst, WORD siz)
3170 {
3171         if (!(activefpu & (FPU_68040 | FPU_68060)))
3172                 return error("Unsupported in current FPU");
3173
3174         return error("Not implemented yet.");
3175
3176 #if 0
3177         if (activefpu == FPU_68040)
3178                 return gen_fpu(inst, siz, B8(01100100), FPU_P_EMUL);
3179         else
3180                 return error("Unsupported in current FPU");
3181 #endif
3182 }
3183
3184
3185 //
3186 // fmovecr (6888X, 68040FPSP, 68060FPSP)
3187 //
3188 int m_fmovecr(WORD inst, WORD siz)
3189 {
3190         CHECKNOFPU;
3191
3192         D_word(inst);
3193         inst = 0x5c00;
3194         inst |= a1reg << 7;
3195         inst |= a0exval;
3196         D_word(inst);
3197
3198         if (activefpu == FPU_68040)
3199                 warn("Instruction is emulated in 68040/060");
3200
3201         return OK;
3202 }
3203
3204
3205 //
3206 // fmovem (6888X, 68040, 68060FPSP)
3207 //
3208 int m_fmovem(WORD inst, WORD siz)
3209 {
3210         CHECKNOFPU;
3211
3212         WORD regmask;
3213         WORD datareg;
3214
3215         if (siz == SIZX || siz == SIZN)
3216         {
3217                 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
3218                 {
3219                         // fmovem.x <rlist>,ea
3220                         if (fpu_reglist_left(&regmask) < 0)
3221                                 return OK;
3222
3223                         if (*tok++ != ',')
3224                                 return error("missing comma");
3225
3226                         if (amode(0) < 0)
3227                                 return OK;
3228
3229                         inst |= am0 | a0reg;
3230
3231                         if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3232                                 return error("invalid addressing mode");
3233
3234                         D_word(inst);
3235                         inst = (1 << 15) | (1 << 14) | (1 << 13) | (0 << 11) | regmask;
3236                         D_word(inst);
3237                         ea0gen(siz);
3238                         return OK;
3239                 }
3240                 else if ((*tok >= KW_D0) && (*tok <= KW_D7))
3241                 {
3242                         // fmovem.x Dn,ea
3243                         datareg = (*tok++ & 7) << 10;
3244
3245                         if (*tok++ != ',')
3246                                 return error("missing comma");
3247
3248                         if (amode(0) < 0)
3249                                 return OK;
3250
3251                         inst |= am0 | a0reg;
3252
3253                         if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3254                                 return error("invalid addressing mode");
3255
3256                         // Quote from the 060 manual:
3257                         // "[..] when the processor attempts an FMOVEM.X instruction using a dynamic register list."
3258                         if (activefpu == FPU_68060)
3259                                 warn("Instruction is emulated in 68060");
3260
3261                         D_word(inst);
3262                         inst = (1 << 15) | (1 << 14) | (1 << 13) | (1 << 11) | (datareg << 4);
3263                         D_word(inst);
3264                         ea0gen(siz);
3265                         return OK;
3266                 }
3267                 else
3268                 {
3269                         // fmovem.x ea,...
3270                         if (amode(0) < 0)
3271                                 return OK;
3272
3273                         inst |= am0 | a0reg;
3274
3275                         if (*tok++ != ',')
3276                                 return error("missing comma");
3277
3278                         if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
3279                         {
3280                                 // fmovem.x ea,<rlist>
3281                                 if (fpu_reglist_right(&regmask) < 0)
3282                                         return OK;
3283
3284                                 D_word(inst);
3285                                 inst = (1 << 15) | (1 << 14) | (0 << 13) | (2 << 11) | regmask;
3286                                 D_word(inst);
3287                                 ea0gen(siz);
3288                                 return OK;
3289                         }
3290                         else
3291                         {
3292                                 // fmovem.x ea,Dn
3293                                 datareg = (*tok++ & 7) << 10;
3294
3295                                 // Quote from the 060 manual:
3296                                 // "[..] when the processor attempts an FMOVEM.X instruction using a dynamic register list."
3297                                 if (activefpu == FPU_68060)
3298                                         warn("Instruction is emulated in 68060");
3299
3300                                 D_word(inst);
3301                                 inst = (1 << 15) | (1 << 14) | (0 << 13) | (3 << 11) | (datareg << 4);
3302                                 D_word(inst);
3303                                 ea0gen(siz);
3304                                 return OK;
3305                         }
3306                 }
3307         }
3308         else if (siz == SIZL)
3309         {
3310                 if ((*tok == KW_FPCR) || (*tok == KW_FPSR) || (*tok == KW_FPIAR))
3311                 {
3312                         // fmovem.l <rlist>,ea
3313                         regmask = (1 << 15) | (1 << 13);
3314                         int no_control_regs = 0;
3315
3316 fmovem_loop_1:
3317                         if (*tok == KW_FPCR)
3318                         {
3319                                 regmask |= (1 << 12);
3320                                 tok++;
3321                                 no_control_regs++;
3322                                 goto fmovem_loop_1;
3323                         }
3324
3325                         if (*tok == KW_FPSR)
3326                         {
3327                                 regmask |= (1 << 11);
3328                                 tok++;
3329                                 no_control_regs++;
3330                                 goto fmovem_loop_1;
3331                         }
3332
3333                         if (*tok == KW_FPIAR)
3334                         {
3335                                 regmask |= (1 << 10);
3336                                 tok++;
3337                                 no_control_regs++;
3338                                 goto fmovem_loop_1;
3339                         }
3340
3341                         if ((*tok == '/') || (*tok == '-'))
3342                         {
3343                                 tok++;
3344                                 goto fmovem_loop_1;
3345                         }
3346
3347                         if (*tok++ != ',')
3348                                 return error("missing comma");
3349
3350                         if (amode(0) < 0)
3351                                 return OK;
3352
3353                         // Quote from the 060 manual:
3354                         // "[..] when the processor attempts to execute an FMOVEM.L instruction with
3355                         // an immediate addressing mode to more than one floating - point
3356                         // control register (FPCR, FPSR, FPIAR)[..]"
3357                         if (activefpu == FPU_68060)
3358                                 if (no_control_regs > 1 && am0 == IMMED)
3359                                         warn("Instruction is emulated in 68060");
3360
3361                         inst |= am0 | a0reg;
3362                         D_word(inst);
3363                         D_word(regmask);
3364                         ea0gen(siz);
3365                 }
3366                 else
3367                 {
3368                         // fmovem.l ea,<rlist>
3369                         if (amode(0) < 0)
3370                                 return OK;
3371
3372                         inst |= am0 | a0reg;
3373
3374                         if (*tok++ != ',')
3375                                 return error("missing comma");
3376
3377                         regmask = (1 << 15) | (0 << 13);
3378
3379 fmovem_loop_2:
3380                         if (*tok == KW_FPCR)
3381                         {
3382                                 regmask |= (1 << 12);
3383                                 tok++;
3384                                 goto fmovem_loop_2;
3385                         }
3386
3387                         if (*tok == KW_FPSR)
3388                         {
3389                                 regmask |= (1 << 11);
3390                                 tok++;
3391                                 goto fmovem_loop_2;
3392                         }
3393
3394                         if (*tok == KW_FPIAR)
3395                         {
3396                                 regmask |= (1 << 10);
3397                                 tok++;
3398                                 goto fmovem_loop_2;
3399                         }
3400
3401                         if ((*tok == '/') || (*tok == '-'))
3402                         {
3403                                 tok++;
3404                                 goto fmovem_loop_2;
3405                         }
3406
3407                         if (*tok != EOL)
3408                                 return error("extra (unexpected) text found");
3409
3410                         inst |= am0 | a0reg;
3411                         D_word(inst);
3412                         D_word(regmask);
3413                         ea0gen(siz);
3414                 }
3415         }
3416         else
3417                 return error("bad size suffix");
3418
3419         return OK;
3420 }
3421
3422
3423 //
3424 // fmul (6888X, 68040, 68060)
3425 //
3426 int m_fmul(WORD inst, WORD siz)
3427 {
3428         CHECKNOFPU;
3429         return gen_fpu(inst, siz, B8(00100011), FPU_NOWARN);
3430 }
3431
3432
3433 //
3434 // fsmul (68040, 68060)
3435 //
3436 int m_fsmul(WORD inst, WORD siz)
3437 {
3438         if (activefpu & (FPU_68040 | FPU_68060))
3439                 return gen_fpu(inst, siz, B8(01100011), FPU_NOWARN);
3440
3441         return error("Unsupported in current FPU");
3442 }
3443
3444
3445 //
3446 // fdmul (68040)
3447 //
3448 int m_fdmul(WORD inst, WORD siz)
3449 {
3450         if (activefpu & (FPU_68040 | FPU_68060))
3451                 return gen_fpu(inst, siz, B8(01100111), FPU_NOWARN);
3452
3453         return error("Unsupported in current FPU");
3454 }
3455
3456
3457 //
3458 // fneg (6888X, 68040, 68060)
3459 //
3460 int m_fneg(WORD inst, WORD siz)
3461 {
3462         CHECKNOFPU;
3463
3464         if (am1 == AM_NONE)
3465         {
3466                 a1reg = a0reg;
3467                 return gen_fpu(inst, siz, B8(00011010), FPU_NOWARN);
3468         }
3469
3470         return gen_fpu(inst, siz, B8(00011010), FPU_NOWARN);
3471 }
3472
3473
3474 //
3475 // fsneg (68040, 68060)
3476 //
3477 int m_fsneg(WORD inst, WORD siz)
3478 {
3479         if (activefpu & (FPU_68040 | FPU_68060))
3480         {
3481                 if (am1 == AM_NONE)
3482                 {
3483                         a1reg = a0reg;
3484                         return gen_fpu(inst, siz, B8(01011010), FPU_NOWARN);
3485                 }
3486
3487                 return gen_fpu(inst, siz, B8(01011010), FPU_NOWARN);
3488         }
3489
3490         return error("Unsupported in current FPU");
3491 }
3492
3493
3494 //
3495 // fdneg (68040, 68060)
3496 //
3497 int m_fdneg(WORD inst, WORD siz)
3498 {
3499         if (activefpu & (FPU_68040 | FPU_68060))
3500         {
3501                 if (am1 == AM_NONE)
3502                 {
3503                                 a1reg = a0reg;
3504                                 return gen_fpu(inst, siz, B8(01011110), FPU_NOWARN);
3505                 }
3506
3507                 return gen_fpu(inst, siz, B8(01011110), FPU_NOWARN);
3508         }
3509
3510         return error("Unsupported in current FPU");
3511 }
3512
3513
3514 //
3515 // fnop (6888X, 68040, 68060)
3516 //
3517 int m_fnop(WORD inst, WORD siz)
3518 {
3519         CHECKNOFPU;
3520         return gen_fpu(inst, siz, B8(00000000), FPU_NOWARN);
3521 }
3522
3523
3524 //
3525 // frem (6888X, 68040FPSP, 68060FPSP)
3526 //
3527 int m_frem(WORD inst, WORD siz)
3528 {
3529         CHECKNOFPU;
3530         return gen_fpu(inst, siz, B8(00100101), FPU_FPSP);
3531 }
3532
3533
3534 //
3535 // fscale (6888X, 68040FPSP, 68060FPSP)
3536 //
3537 int m_fscale(WORD inst, WORD siz)
3538 {
3539         CHECKNOFPU;
3540         return gen_fpu(inst, siz, B8(00100110), FPU_FPSP);
3541 }
3542
3543
3544 //
3545 // FScc (6888X, 68040, 68060), cpScc (68851, 68030), PScc (68851)
3546 // TODO: Add check for PScc to ensure 68020+68851 active
3547 // TODO: Add check for cpScc to ensure 68020+68851, 68030
3548 //
3549 int m_fscc(WORD inst, WORD siz)
3550 {
3551         CHECKNOFPU;
3552
3553         // We stash the 5 condition bits inside the opcode in 68ktab (bits 4-0),
3554         // so we need to extract them first and fill in the clobbered bits.
3555         WORD opcode = inst & 0x1F;
3556         inst &= 0xFFE0;
3557         inst |= am0 | a0reg;
3558         D_word(inst);
3559         ea0gen(siz);
3560         D_word(opcode);
3561         if (activefpu == FPU_68060)
3562                 warn("Instruction is emulated in 68060");
3563         return OK;
3564 }
3565
3566
3567 //
3568 // fsgldiv (6888X, 68040FPSP, 68060FPSP)
3569 //
3570 int m_fsgldiv(WORD inst, WORD siz)
3571 {
3572         CHECKNOFPU;
3573         return gen_fpu(inst, siz, B8(00100100), FPU_FPSP);
3574 }
3575
3576
3577 //
3578 // fsglmul (6888X, 68040, 68060FPSP)
3579 //
3580 int m_fsglmul(WORD inst, WORD siz)
3581 {
3582         CHECKNOFPU;
3583         return gen_fpu(inst, siz, B8(00100111), FPU_FPSP);
3584 }
3585
3586
3587 //
3588 // fsin (6888X, 68040FPSP, 68060FPSP)
3589 //
3590 int m_fsin(WORD inst, WORD siz)
3591 {
3592         CHECKNOFPU;
3593         return gen_fpu(inst, siz, B8(00001110), FPU_FPSP);
3594 }
3595
3596
3597 //
3598 // fsincos (6888X, 68040FPSP, 68060FPSP)
3599 //
3600 int m_fsincos(WORD inst, WORD siz)
3601 {
3602         CHECKNOFPU;
3603
3604         // Swap a1reg, a2reg as a2reg should be stored in the bitfield gen_fpu
3605         // generates
3606         int temp;
3607         temp = a2reg;
3608         a2reg = a1reg;
3609         a1reg = temp;
3610
3611         if (gen_fpu(inst, siz, B8(00110000), FPU_FPSP) == OK)
3612         {
3613                 chptr[-1] |= a2reg;
3614                 return OK;
3615         }
3616
3617         return ERROR;
3618 }
3619
3620
3621 //
3622 // fsinh (6888X, 68040FPSP, 68060FPSP)
3623 //
3624 int m_fsinh(WORD inst, WORD siz)
3625 {
3626         CHECKNOFPU;
3627         return gen_fpu(inst, siz, B8(00000010), FPU_FPSP);
3628 }
3629
3630
3631 //
3632 // fsqrt (6888X, 68040, 68060)
3633 //
3634 int m_fsqrt(WORD inst, WORD siz)
3635 {
3636         CHECKNOFPU;
3637         return gen_fpu(inst, siz, B8(00000100), FPU_NOWARN);
3638 }
3639
3640
3641 //
3642 // fsfsqrt (68040, 68060)
3643 //
3644 int m_fsfsqrt(WORD inst, WORD siz)
3645 {
3646         if (activefpu & (FPU_68040 | FPU_68060))
3647                 return gen_fpu(inst, siz, B8(01000001), FPU_NOWARN);
3648
3649         return error("Unsupported in current FPU");
3650 }
3651
3652
3653 //
3654 // fdfsqrt (68040, 68060)
3655 //
3656 int m_fdfsqrt(WORD inst, WORD siz)
3657 {
3658         if (activefpu & (FPU_68040 | FPU_68060))
3659                 return gen_fpu(inst, siz, B8(01000101), FPU_NOWARN);
3660