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