64061dc4cef46cf97d152b777f97bbdb1207b450
[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-2017 Reboot and Friends
5 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
6 // Source utilised with the kind permission of Landon Dyer
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                 // bfins special case
1190                 D_word((inst | am1 | a1reg));
1191         else
1192                 D_word((inst | am0 | a0reg));
1193
1194         ea0gen(siz);    // Generate EA
1195
1196         // Second instruction word - Dest register (if exists), Do, Offset, Dw, Width
1197         if (inst == B16(11101111, 11000000))
1198         {
1199                 // bfins special case
1200                 inst = bfparam1 | bfparam2;
1201
1202                 if (am1 == DREG)
1203                         inst |= a0reg << 12;
1204
1205                 D_word(inst);
1206         }
1207         else
1208         {
1209                 inst = bfparam1 | bfparam2;
1210
1211                 if (am1 == DREG)
1212                         inst |= a0reg << 0;
1213
1214                 if (am0 == DREG)
1215                         inst |= a1reg << 12;
1216
1217                 D_word(inst);
1218         }
1219
1220         return OK;
1221 }
1222
1223
1224 //
1225 // bkpt (68EC000, 68010, 68020, 68030, 68040, CPU32)
1226 //
1227 int m_bkpt(WORD inst, WORD siz)
1228 {
1229         CHECK00;
1230
1231         if (a0exattr & DEFINED)
1232         {
1233                 if (a0exattr & TDB)
1234                         return error(abs_error);
1235
1236                 if (a0exval >= 8)
1237                         return error(range_error);
1238
1239                 inst |= a0exval;
1240                 D_word(inst);
1241         }
1242         else
1243                 return error(undef_error);
1244
1245         return OK;
1246 }
1247
1248
1249 //
1250 // callm (68020)
1251 //
1252 int m_callm(WORD inst, WORD siz)
1253 {
1254         CHECKNO20;
1255
1256         inst |= am1;
1257         D_word(inst);
1258
1259         if (a0exattr & DEFINED)
1260         {
1261                 if (a0exattr & TDB)
1262                         return error(abs_error);
1263
1264                 if (a0exval > 255)
1265                         return error(range_error);
1266
1267                 inst = (uint16_t)a0exval;
1268                 D_word(inst);
1269         }
1270         else
1271                 return error(undef_error);
1272
1273         ea1gen(siz);
1274
1275         return OK;
1276
1277 }
1278
1279
1280 //
1281 // cas (68020, 68030, 68040)
1282 //
1283 int m_cas(WORD inst, WORD siz)
1284 {
1285         WORD inst2;
1286         LONG amsk;
1287         int modes;
1288
1289         if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1290                 return error(unsupport);
1291
1292         switch (siz)
1293         {
1294         case SIZB:
1295                 inst |= 1 << 9;
1296                 break;
1297         case SIZW:
1298         case SIZN:
1299                 inst |= 2 << 9;
1300                 break;
1301         case SIZL:
1302                 inst |= 3 << 9;
1303                 break;
1304         default:
1305                 return error("bad size suffix");
1306                 break;
1307         }
1308
1309         // Dc
1310         if ((*tok < KW_D0) && (*tok > KW_D7))
1311                 return error("CAS accepts only data registers");
1312
1313         inst2 = (*tok++) & 7;
1314
1315         if (*tok++ != ',')
1316                 return error("missing comma");
1317
1318         // Du
1319         if ((*tok < KW_D0) && (*tok > KW_D7))
1320                 return error("CAS accepts only data registers");
1321
1322         inst2 |= ((*tok++) & 7) << 6;
1323
1324         if (*tok++ != ',')
1325                 return error("missing comma");
1326
1327         // ea
1328         if ((modes = amode(1)) < 0)
1329                 return OK;
1330
1331         if (modes > 1)
1332                 return error("too many ea fields");
1333
1334         if (*tok != EOL)
1335                 return error("extra (unexpected) text found");
1336
1337         // Reject invalid ea modes
1338         amsk = amsktab[am0];
1339
1340         if ((amsk & (M_AIND | M_APOSTINC | M_APREDEC | M_ADISP | M_AINDEXED | M_ABSW | M_ABSL | M_ABASE | M_MEMPOST | M_MEMPRE)) == 0)
1341                 return error("unsupported addressing mode");
1342
1343         inst |= am0 | a0reg;
1344         D_word(inst);
1345         D_word(inst2);
1346         ea0gen(siz);
1347
1348         return OK;
1349 }
1350
1351
1352 //
1353 // cas2 (68020, 68030, 68040)
1354 //
1355 int m_cas2(WORD inst, WORD siz)
1356 {
1357         WORD inst2, inst3;
1358
1359         if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1360                 return error(unsupport);
1361
1362         switch (siz)
1363         {
1364         case SIZB:
1365                 inst |= 1 << 9;
1366                 break;
1367         case SIZW:
1368         case SIZN:
1369                 inst |= 2 << 9;
1370                 break;
1371         case SIZL:
1372                 inst |= 3 << 9;
1373                 break;
1374         default:
1375                 return error("bad size suffix");
1376                 break;
1377         }
1378
1379         // Dc1
1380         if ((*tok < KW_D0) && (*tok > KW_D7))
1381                 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1382
1383         inst2 = (*tok++) & 7;
1384
1385         if (*tok++ != ':')
1386                 return error("missing colon");
1387
1388         // Dc2
1389         if ((*tok < KW_D0) && (*tok > KW_D7))
1390                 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1391
1392         inst3 = (*tok++) & 7;
1393
1394         if (*tok++ != ',')
1395                 return error("missing comma");
1396
1397         // Du1
1398         if ((*tok < KW_D0) && (*tok > KW_D7))
1399                 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1400
1401         inst2 |= ((*tok++) & 7) << 6;
1402
1403         if (*tok++ != ':')
1404                 return error("missing colon");
1405
1406         // Du2
1407         if ((*tok < KW_D0) && (*tok > KW_D7))
1408                 return error("CAS2 accepts only data registers for Dx1:Dx2 pairs");
1409
1410         inst3 |= ((*tok++) & 7) << 6;
1411
1412         if (*tok++ != ',')
1413                 return error("missing comma");
1414
1415         // Rn1
1416         if (*tok++ != '(')
1417                 return error("missing (");
1418         if ((*tok >= KW_D0) && (*tok <= KW_D7))
1419                 inst2 |= (((*tok++) & 7) << 12) | (0 << 15);
1420         else if ((*tok >= KW_A0) && (*tok <= KW_A7))
1421                 inst2 |= (((*tok++) & 7) << 12) | (1 << 15);
1422         else
1423                 return error("CAS accepts either data or address registers for Rn1:Rn2 pair");
1424
1425         if (*tok++ != ')')
1426                 return error("missing (");
1427
1428         if (*tok++ != ':')
1429                 return error("missing colon");
1430
1431         // Rn2
1432         if (*tok++ != '(')
1433                 return error("missing (");
1434         if ((*tok >= KW_D0) && (*tok <= KW_D7))
1435                 inst3 |= (((*tok++) & 7) << 12) | (0 << 15);
1436         else if ((*tok >= KW_A0) && (*tok <= KW_A7))
1437                 inst3 |= (((*tok++) & 7) << 12) | (1 << 15);
1438         else
1439                 return error("CAS accepts either data or address registers for Rn1:Rn2 pair");
1440
1441         if (*tok++ != ')')
1442                 return error("missing (");
1443
1444         if (*tok != EOL)
1445                 return error("extra (unexpected) text found");
1446
1447         D_word(inst);
1448         D_word(inst2);
1449         D_word(inst3);
1450
1451         return OK;
1452 }
1453
1454
1455 //
1456 // cmp2 (68020, 68030, 68040, CPU32)
1457 //
1458 int m_cmp2(WORD inst, WORD siz)
1459 {
1460         if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1461                 return error(unsupport);
1462
1463         switch (siz & 0x000F)
1464         {
1465         case SIZW:
1466         case SIZN:
1467                 inst |= 1 << 9;
1468                 break;
1469         case SIZL:
1470                 inst |= 2 << 9;
1471                 break;
1472         default:
1473                 // SIZB
1474                 break;
1475         }
1476
1477         WORD flg = inst;                                        // Save flag bits
1478         inst &= ~0x3F;                                          // Clobber flag bits in instr
1479
1480         // Install "standard" instr size bits
1481         if (flg & 4)
1482                 inst |= siz_6[siz];
1483
1484         if (flg & 16)
1485         {
1486                 // OR-in register number
1487                 if (flg & 8)
1488                         inst |= reg_9[a1reg];           // ea1reg in bits 9..11
1489                 else
1490                         inst |= reg_9[a0reg];           // ea0reg in bits 9..11
1491         }
1492
1493         if (flg & 1)
1494         {
1495                 // Use am1
1496                 inst |= am1 | a1reg;                    // Get ea1 into instr
1497                 D_word(inst);                                   // Deposit instr
1498
1499                 // Generate ea0 if requested
1500                 if (flg & 2)
1501                         ea0gen(siz);
1502
1503                 ea1gen(siz);                                    // Generate ea1
1504         }
1505         else
1506         {
1507                 // Use am0
1508                 inst |= am0 | a0reg;                    // Get ea0 into instr
1509                 D_word(inst);                                   // Deposit instr
1510                 ea0gen(siz);                                    // Generate ea0
1511
1512                 // Generate ea1 if requested
1513                 if (flg & 2)
1514                         ea1gen(siz);
1515         }
1516
1517         // If we're called from chk2 then bit 11 of size will be set. This is just
1518         // a dumb mechanism to pass this, required by the extension word. (You might
1519         // have noticed the siz & 15 thing above!)
1520         inst = (a1reg << 12) | (siz & (1 << 11));
1521
1522         if (am1 == AREG)
1523                 inst |= 1 << 15;
1524
1525         D_word(inst);
1526
1527         return OK;
1528 }
1529
1530
1531 //
1532 // chk2 (68020, 68030, 68040, CPU32)
1533 //
1534 int m_chk2(WORD inst, WORD siz)
1535 {
1536         return m_cmp2(inst, siz | (1 << 11));
1537 }
1538
1539
1540 //
1541 // cpbcc(68020, 68030, 68040 (FBcc), 68060 (FBcc))
1542 // TODO: Better checks for different instructions?
1543 //
1544 int m_cpbr(WORD inst, WORD siz)
1545 {
1546         if ((activecpu & (CPU_68020 | CPU_68030)) && (!activefpu == 0))
1547                 return error(unsupport);
1548
1549         if (a0exattr & DEFINED)
1550         {
1551                 if ((a0exattr & TDB) != cursect)
1552                         return error(rel_error);
1553
1554                 uint32_t v = (uint32_t)a0exval - (sloc + 2);
1555
1556                 // Optimize branch instr. size
1557                 if (siz == SIZL)
1558                 {
1559                         if ((v != 0) && ((v + 0x8000) < 0x10000))
1560                         {
1561                                 inst |= (1 << 6);
1562                                 D_word(inst);
1563                                 D_long(v);
1564                                 return OK;
1565                         }
1566                 }
1567                 else // SIZW/SIZN
1568                 {
1569                         if ((v + 0x8000) >= 0x10000)
1570                                 return error(range_error);
1571
1572                         D_word(inst);
1573                         D_word(v);
1574                 }
1575
1576                 return OK;
1577         }
1578         else if (siz == SIZN)
1579                 siz = SIZW;
1580
1581         if (siz == SIZL)
1582         {
1583                 // .L
1584                 D_word(inst);
1585                 AddFixup(FU_LONG | FU_PCREL | FU_SEXT, sloc, a0expr);
1586                 D_long(0);
1587                 return OK;
1588         }
1589         else
1590         {
1591                 // .W
1592                 D_word(inst);
1593                 AddFixup(FU_WORD | FU_PCREL | FU_SEXT, sloc, a0expr);
1594                 D_word(0);
1595         }
1596
1597         return OK;
1598 }
1599
1600
1601 //
1602 // cpdbcc(68020, 68030)
1603 //
1604 int m_cpdbr(WORD inst, WORD siz)
1605 {
1606         CHECK00;
1607
1608         uint32_t v;
1609         WORD condition = inst & 0x1F; // Grab condition sneakily placed in the lower 5 bits of inst
1610         inst &= 0xFFE0;               // And then mask them out - you ain't seen me, roit?
1611
1612         inst |= (1 << 9);       // Bolt on FPU id
1613         inst |= a0reg;
1614
1615         D_word(inst);
1616
1617         D_word(condition);
1618
1619         if (a1exattr & DEFINED)
1620         {
1621                 if ((a1exattr & TDB) != cursect)
1622                         return error(rel_error);
1623
1624                 v = (uint32_t)a1exval - sloc;
1625
1626                 if (v + 0x8000 > 0x10000)
1627                         return error(range_error);
1628
1629                 D_word(v);
1630         }
1631         else
1632         {
1633                 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
1634                 D_word(0);
1635         }
1636
1637         return OK;
1638
1639 }
1640
1641
1642 //
1643 // muls.l / divs.l / divu.l / mulu.l (68020+)
1644 //
1645 int m_muls(WORD inst, WORD siz)
1646 {
1647         if ((activecpu & (CPU_68020 | CPU_68030 | CPU_68040)) == 0)
1648                 return error(unsupport);
1649
1650         WORD flg = inst;                                        // Save flag bits
1651         inst &= ~0x33F;                                         // Clobber flag and extension bits in instr
1652
1653         // Install "standard" instr size bits
1654         if (flg & 4)
1655                 inst |= siz_6[siz];
1656
1657         if (flg & 16)
1658         {
1659                 // OR-in register number 
1660                 if (flg & 8)
1661                         inst |= reg_9[a1reg];           // ea1reg in bits 9..11
1662                 else
1663                         inst |= reg_9[a0reg];           // ea0reg in bits 9..11
1664         }
1665
1666         // Regarding extension word: bit 11 is signed/unsigned selector
1667         //                           bit 10 is 32/64 bit selector
1668         // Both of these are packed in bits 9 and 8 of the instruction
1669         // field in 68ktab. Extra compilcations arise from the fact we
1670         // have to distinguish between divu/s.l Dn,Dm (which is encoded
1671         // as divu/s.l Dn,Dm:Dm) and divu/s.l Dn,Dm:Dx - the first is
1672         // 32 bit while the second 64 bit
1673
1674         if (flg & 1)
1675         {
1676                 // Use am1
1677                 inst |= am1 | a1reg;                    // Get ea1 into instr
1678                 D_word(inst);                                   // Deposit instr
1679
1680                 // Extension word
1681                 if (a1reg == a2reg)
1682                         inst = a1reg + (a2reg << 12) + ((flg & 0x200) << 2);
1683                 else
1684                         inst = a1reg + (a2reg << 12) + ((flg & 0x300) << 2);
1685
1686                  D_word(inst);
1687
1688                 // Generate ea0 if requested 
1689                 if (flg & 2)
1690                         ea0gen(siz);
1691
1692                 ea1gen(siz);                                    // Generate ea1
1693
1694                 return OK;
1695         }
1696         else
1697         {
1698                 // Use am0
1699                 inst |= am0 | a0reg;                    // Get ea0 into instr
1700                 D_word(inst);                                   // Deposit instr
1701
1702                 // Extension word
1703                 if (a1reg == a2reg)
1704                         inst = a1reg + (a2reg << 12) + ((flg & 0x200) << 2);
1705                 else
1706                         inst = a1reg + (a2reg << 12) + ((flg & 0x300) << 2);
1707
1708                 D_word(inst);
1709
1710                 ea0gen(siz);                                    // Generate ea0
1711
1712                 // Generate ea1 if requested
1713                 if (flg & 2)
1714                         ea1gen(siz);
1715
1716                 return OK;
1717         }
1718 }
1719
1720
1721 //
1722 // move16 (ax)+,(ay)+
1723 //
1724 int m_move16a(WORD inst, WORD siz)
1725 {
1726         if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1727                 return error(unsupport);
1728
1729         inst |= a0reg;
1730         D_word(inst);
1731         inst = (1 << 15) + (a1reg << 12);
1732         D_word(inst);
1733
1734         return OK;
1735 }
1736
1737
1738 //
1739 // move16 with absolute address
1740 //
1741 int m_move16b(WORD inst, WORD siz)
1742 {
1743         if ((activecpu & (CPU_68040 | CPU_68060)) == 0)
1744                 return error(unsupport);
1745
1746         int v;
1747         inst |= a1reg;
1748         D_word(inst);
1749
1750         if (am0 == APOSTINC)
1751         {
1752                 if (am1 == AIND)
1753                         return error("Wasn't this suppose to call m_move16a???");
1754                 else
1755                 {
1756                         // move16 (ax)+,(xxx).L
1757                         inst |= 0 << 3;
1758                         v = (int)a1exval;
1759                 }
1760         }
1761         else if (am0 == ABSL)
1762         {
1763                 if (am1 == AIND)
1764                 {
1765                         // move16 (xxx).L,(ax)+
1766                         inst |= 1 << 3;
1767                         v = (int)a0exval;
1768                 }
1769                 else // APOSTINC
1770                 {
1771                         // move16 (xxx).L,(ax)
1772                         inst |= 3 << 3;
1773                         v = (int)a0exval;
1774                 }
1775         }
1776         else if (am0 == AIND)
1777         {
1778                 // move16 (ax),(xxx).L
1779                 inst |= 2 << 3;
1780                 v = (int)a1exval;
1781         }
1782
1783         D_word(inst);
1784         D_long(v);
1785
1786         return OK;
1787 }
1788
1789
1790 //
1791 // pack/unpack (68020/68030/68040)
1792 //
1793 int m_pack(WORD inst, WORD siz)
1794 {
1795         CHECK00;
1796
1797         if (siz != SIZN)
1798                 return error("bad size suffix");
1799
1800         if (*tok >= KW_D0 && *tok <= KW_D7)
1801         {
1802                 // Dx,Dy,#<adjustment>
1803                 inst |= (0 << 3);   // R/M
1804                 inst |= (*tok++ & 7);
1805
1806                 if (*tok != ',' && tok[2] != ',')
1807                         return error("missing comma");
1808
1809                 if (tok[1] < KW_D0 && tok[1] > KW_D7)
1810                         return error(syntax_error);
1811
1812                 inst |= ((tok[1] & 7)<<9);
1813                 tok = tok + 3;
1814                 D_word(inst);
1815                 // Fall through for adjustment (common in both valid cases)
1816         }
1817         else if (*tok == '-')
1818         {
1819                 // -(Ax),-(Ay),#<adjustment>
1820                 inst |= (1 << 3);   // R/M
1821                 tok++;  // eat the minus
1822
1823                 if ((*tok != '(') && (tok[2]!=')') && (tok[3]!=',') && (tok[4] != '-') && (tok[5] != '(') && (tok[7] != ')') && (tok[8] != ','))
1824                         return error(syntax_error);
1825
1826                 if (tok[1] < KW_A0 && tok[1] > KW_A7)
1827                         return error(syntax_error);
1828
1829                 if (tok[5] < KW_A0 && tok[6] > KW_A7)
1830                         return error(syntax_error);
1831
1832                 inst |= ((tok[1] & 7) << 0);
1833                 inst |= ((tok[6] & 7) << 9);
1834                 tok = tok + 9;
1835                 D_word(inst);
1836                 // Fall through for adjustment (common in both valid cases)
1837         }
1838         else
1839                 return error("invalid syntax");
1840
1841         if ((*tok != CONST) && (*tok != SYMBOL) && (*tok != '-'))
1842                 return error(syntax_error);
1843
1844         if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
1845                 return ERROR;
1846
1847         if ((a0exattr & DEFINED) == 0)
1848                 return error(undef_error);
1849
1850         if (a0exval + 0x8000 > 0x10000)
1851                 return error("");
1852
1853         if (*tok != EOL)
1854                 return error(extra_stuff);
1855
1856         D_word((a0exval & 0xFFFF));
1857
1858         return OK;
1859 }
1860
1861
1862 //
1863 // rtm Rn
1864 //
1865 int m_rtm(WORD inst, WORD siz)
1866 {
1867         CHECKNO20;
1868
1869         if (am0 == DREG)
1870         {
1871                 inst |= a0reg;
1872         }
1873         else if (am0 == AREG)
1874         {
1875                 inst |= (1 << 3) + a0reg;
1876         }
1877         else
1878                 return error("rtm only allows data or address registers.");
1879
1880         D_word(inst);
1881
1882         return OK;
1883 }
1884
1885
1886 //
1887 // rtd #n
1888 //
1889 int m_rtd(WORD inst, WORD siz)
1890 {
1891         CHECK00;
1892
1893         if (a0exattr & DEFINED)
1894         {
1895                 if (a0exattr & TDB)
1896                         return error(abs_error);
1897
1898                 if ((a0exval + 0x8000) <= 0x7FFF)
1899                         return error(range_error);
1900
1901                 D_word(inst);
1902                 D_word(a0exval);
1903         }
1904         else
1905                 return error(undef_error);
1906
1907         return OK;
1908 }
1909
1910
1911 //
1912 // trapcc
1913 //
1914 int m_trapcc(WORD inst, WORD siz)
1915 {
1916         CHECK00;
1917
1918         if (am0 == AM_NONE)
1919         {
1920                 D_word(inst);
1921         }
1922         else if (am0 == IMMED)
1923         {
1924                 if (siz == SIZW)
1925                 {
1926                         if (a0exval < 0x10000)
1927                         {
1928                                 inst |= 2;
1929                                 D_word(inst);
1930                                 D_word(a0exval);
1931                         }
1932                         else
1933                                 return error("Immediate value too big");
1934                 }
1935                 else //DOTL
1936                 {
1937                         inst |= 3;
1938                         D_word(inst);
1939                         D_long(a0exval);
1940                 }
1941         }
1942         else
1943                 return error("Invalid parameter for trapcc");
1944
1945         return OK;
1946 }
1947
1948
1949 //
1950 // cinvl/p/a (68040/68060)
1951 //
1952 int m_cinv(WORD inst, WORD siz)
1953 {
1954         CHECKNO40;
1955
1956         if (am1 == AM_NONE)
1957                 inst |= (0 << 6) | (a1reg);
1958         switch (a0reg)
1959         {
1960         case 0:     // KW_IC40
1961                 inst |= (2 << 6) | (a1reg);
1962                 break;
1963         case 1:     // KW_DC40
1964                 inst |= (1 << 6) | (a1reg);
1965                 break;
1966         case 2:     // KW_BC40
1967                 inst |= (3 << 6) | (a1reg);
1968                 break;
1969         }
1970
1971         D_word(inst);
1972         return OK;
1973 }
1974
1975
1976 int m_fpusavrest(WORD inst, WORD siz)
1977 {
1978         inst |= am0 | a0reg;
1979         D_word(inst);
1980         ea0gen(siz);
1981
1982         return OK;
1983 }
1984
1985
1986 //
1987 // cpSAVE/cpRESTORE (68020, 68030)
1988 //
1989 int m_cprest(WORD inst, WORD siz)
1990 {
1991         if (activecpu & !(CPU_68020 | CPU_68030))
1992                 return error(unsupport);
1993
1994         return m_fpusavrest(inst, siz);
1995
1996 }
1997
1998
1999 //
2000 // FSAVE/FRESTORE (68040, 68060)
2001 //
2002 int m_frestore(WORD inst, WORD siz)
2003 {
2004         if ((!(activecpu & (CPU_68040 | CPU_68060))) ||
2005                 (activefpu&(FPU_68881 | FPU_68882)))
2006                 return error(unsupport);
2007
2008         return m_fpusavrest(inst, siz);
2009 }
2010
2011
2012 //
2013 // movec (68010, 68020, 68030, 68040, 68060, CPU32)
2014 //
2015 int m_movec(WORD inst, WORD siz)
2016 {
2017         CHECK00;
2018
2019         if (am0 == DREG || am0 == AREG)
2020         {
2021                 // movec Rn,Rc
2022                 inst |= 1;
2023                 D_word(inst);
2024
2025                 if (am0 == DREG)
2026                 {
2027                         inst = (0 << 15) + (a0reg << 12) + CREGlut[a1reg];
2028                         D_word(inst);
2029                 }
2030                 else
2031                 {
2032                         inst = (1 << 15) + (a0reg << 12) + CREGlut[a1reg];
2033                         D_word(inst);
2034                 }
2035         }
2036         else
2037         {
2038                 // movec Rc,Rn
2039                 D_word(inst);
2040
2041                 if (am1 == DREG)
2042                 {
2043                         inst = (0 << 15) + (a1reg << 12) + CREGlut[a0reg];
2044                         D_word(inst);
2045                 }
2046                 else
2047                 {
2048                         inst = (1 << 15) + (a1reg << 12) + CREGlut[a0reg];
2049                         D_word(inst);
2050                 }
2051         }
2052
2053         return OK;
2054 }
2055
2056
2057 //
2058 // moves (68010, 68020, 68030, 68040, CPU32)
2059 //
2060 int m_moves(WORD inst, WORD siz)
2061 {
2062         if (activecpu & !(CPU_68020 | CPU_68030 | CPU_68040))
2063                 return error(unsupport);
2064
2065         if (siz == SIZB)
2066                 inst |= 0 << 6;
2067         else if (siz == SIZL)
2068                 inst |= 2 << 6;
2069         else // SIZW/SIZN
2070                 inst |= 1 << 6;
2071
2072         if (am0 == DREG)
2073         {
2074                 inst |= am1 | a1reg;
2075                 D_word(inst);
2076                 inst = (a0reg << 12) | (1 << 11) | (0 << 15);
2077                 D_word(inst);
2078         }
2079         else if (am0 == AREG)
2080         {
2081                 inst |= am1 | a1reg;
2082                 D_word(inst);
2083                 inst = (a0reg << 12) | (1 << 11) | (1 << 15);
2084                 D_word(inst);
2085         }
2086         else
2087         {
2088                 if (am1 == DREG)
2089                 {
2090                         inst |= am0 | a0reg;
2091                         D_word(inst);
2092                         inst = (a1reg << 12) | (0 << 11) | (0 << 15);
2093                         D_word(inst);
2094                 }
2095                 else
2096                 {
2097                         inst |= am0 | a0reg;
2098                         D_word(inst);
2099                         inst = (a1reg << 12) | (0 << 11) | (1 << 15);
2100                         D_word(inst);
2101                 }
2102         }
2103
2104         return OK;
2105 }
2106
2107
2108 //
2109 // PBcc (MC68851)
2110 //
2111 int m_pbcc(WORD inst, WORD siz)
2112 {
2113         CHECKNO20;
2114         return error("Not implemented yet.");
2115 }
2116
2117
2118 //
2119 // pflusha (68030, 68040)
2120 //
2121 int m_pflusha(WORD inst, WORD siz)
2122 {
2123         if (activecpu == CPU_68030)
2124         {
2125                 D_word(inst);
2126                 inst = (1 << 13) | (1 << 10) | (0 << 5) | 0;
2127                 D_word(inst);
2128                 return OK;
2129         }
2130         else if (activecpu == CPU_68040)
2131         {
2132                 inst = B16(11110101, 00011000);
2133                 D_word(inst);
2134                 return OK;
2135         }
2136         else
2137                 return error(unsupport);
2138
2139         return OK;
2140 }
2141
2142
2143 //
2144 // pflush (68030, 68040, 68060)
2145 //
2146 int m_pflush(WORD inst, WORD siz)
2147 {
2148         if (activecpu == CPU_68030)
2149         {
2150                 // PFLUSH FC, MASK
2151                 // PFLUSH FC, MASK, < ea >
2152                 WORD mask, fc;
2153
2154                 switch ((int)*tok)
2155                 {
2156                 case '#':
2157                         tok++;
2158
2159                         if (*tok != CONST && *tok != SYMBOL)
2160                                 return error("function code should be an expression");
2161
2162                         if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2163                                 return ERROR;
2164
2165                         if ((a0exattr & DEFINED) == 0)
2166                                 return error("function code immediate should be defined");
2167
2168                         if (a0exval > 7)
2169                                 return error("function code out of range (0-7)");
2170
2171                         fc = (uint16_t)a0exval;
2172                         break;
2173                 case KW_D0:
2174                 case KW_D1:
2175                 case KW_D2:
2176                 case KW_D3:
2177                 case KW_D4:
2178                 case KW_D5:
2179                 case KW_D6:
2180                 case KW_D7:
2181                         fc = (1 << 4) | (*tok++ & 7);
2182                         break;
2183                 case KW_SFC:
2184                         fc = 0;
2185                         tok++;
2186                         break;
2187                 case KW_DFC:
2188                         fc = 1;
2189                         tok++;
2190                         break;
2191                 default:
2192                         return error(syntax_error);
2193                 }
2194
2195                 if (*tok++ != ',')
2196                         return error("comma exptected");
2197
2198                 if (*tok++ != '#')
2199                         return error("mask should be an immediate value");
2200
2201                 if (*tok != CONST && *tok != SYMBOL)
2202                         return error("mask is supposed to be immediate");
2203
2204                 if (expr(a0expr, &a0exval, &a0exattr, &a0esym) == ERROR)
2205                         return ERROR;
2206
2207                 if ((a0exattr & DEFINED) == 0)
2208                         return error("mask immediate value should be defined");
2209
2210                 if (a0exval > 7)
2211                         return error("function code out of range (0-7)");
2212
2213                 mask = (uint16_t)a0exval << 5;
2214
2215                 if (*tok == EOL)
2216                 {
2217                         // PFLUSH FC, MASK
2218                         D_word(inst);
2219                         inst = (1 << 13) | fc | mask | (4 << 10);
2220                         D_word(inst);
2221                         return OK;
2222                 }
2223                 else if (*tok == ',')
2224                 {
2225                         // PFLUSH FC, MASK, < ea >
2226                         tok++;
2227
2228                         if (amode(0) == ERROR)
2229                                 return ERROR;
2230
2231                         if (*tok != EOL)
2232                                 return error(extra_stuff);
2233
2234                         if (am0 == AIND || am0 == ABSW || am0 == ABSL || am0 == ADISP || am0 == ADISP || am0 == AINDEXED || am0 == ABASE || am0 == MEMPOST || am0 == MEMPRE)
2235                         {
2236                                 inst |= am0 | a0reg;
2237                                 D_word(inst);
2238                                 inst = (1 << 13) | fc | mask | (6 << 10);
2239                                 D_word(inst);
2240                                 ea0gen(siz);
2241                                 return OK;
2242                         }
2243                         else
2244                                 return error("unsupported addressing mode");
2245
2246                 }
2247                 else
2248                         return error(syntax_error);
2249
2250                 return OK;
2251         }
2252         else if (activecpu == CPU_68040 || activecpu == CPU_68060)
2253         {
2254                 // PFLUSH(An)
2255                 // PFLUSHN(An)
2256                 if (*tok != '(' && tok[2] != ')')
2257                         return error(syntax_error);
2258
2259                 if (tok[1] < KW_A0 && tok[1] > KW_A7)
2260                         return error("expected (An)");
2261
2262                 if ((inst & 7) == 7)
2263                         // With pflushn/pflush there's no easy way to distinguish between
2264                         // the two in 68040 mode. Ideally the opcode bitfields would have
2265                         // been hardcoded in 68ktab but there is aliasing between 68030
2266                         // and 68040 opcode. So we just set the 3 lower bits to 1 in
2267                         // pflushn inside 68ktab and detect it here.
2268                         inst = (inst & 0xff8) | 8;
2269
2270                 inst |= (tok[1] & 7) | (5 << 8);
2271
2272                 if (tok[3] != EOL)
2273                         return error(extra_stuff);
2274
2275                 D_word(inst);
2276         }
2277         else
2278                 return error(unsupport);
2279
2280         return OK;
2281 }
2282
2283
2284 //
2285 // pflushan (68040, 68060)
2286 //
2287 int m_pflushan(WORD inst, WORD siz)
2288 {
2289         if (activecpu == CPU_68040 || activecpu == CPU_68060)
2290                 D_word(inst);
2291
2292         return OK;
2293 }
2294
2295
2296 //
2297 // pflushr (68851)
2298 //
2299 int m_pflushr(WORD inst, WORD siz)
2300 {
2301         CHECKNO20;
2302
2303         WORD flg = inst;                                        // Save flag bits
2304         inst &= ~0x3F;                                          // Clobber flag bits in instr
2305
2306         // Install "standard" instr size bits
2307         if (flg & 4)
2308                 inst |= siz_6[siz];
2309
2310         if (flg & 16)
2311         {
2312                 // OR-in register number
2313                 if (flg & 8)
2314                         inst |= reg_9[a1reg];           // ea1reg in bits 9..11
2315                 else
2316                         inst |= reg_9[a0reg];           // ea0reg in bits 9..11
2317         }
2318
2319         if (flg & 1)
2320         {
2321                 // Use am1
2322                 inst |= am1 | a1reg;                    // Get ea1 into instr
2323                 D_word(inst);                                   // Deposit instr
2324
2325                 // Generate ea0 if requested
2326                 if (flg & 2)
2327                         ea0gen(siz);
2328
2329                 ea1gen(siz);                                    // Generate ea1
2330         }
2331         else
2332         {
2333                 // Use am0
2334                 inst |= am0 | a0reg;                    // Get ea0 into instr
2335                 D_word(inst);                                   // Deposit instr
2336                 ea0gen(siz);                                    // Generate ea0
2337
2338                 // Generate ea1 if requested
2339                 if (flg & 2)
2340                         ea1gen(siz);
2341         }
2342
2343         D_word(B16(10100000, 00000000));
2344         return OK;
2345 }
2346
2347
2348 //
2349 // ploadr, ploadw (68030)
2350 //
2351 int m_pload(WORD inst, WORD siz, WORD extension)
2352 {
2353         // TODO: 68851 support is not added yet.
2354         // None of the ST series of computers had a 68020 + 68851 socket and since
2355         // this is an Atari targetted assembler...
2356         CHECKNO30;
2357
2358         inst |= am1;
2359         D_word(inst);
2360
2361         switch (am0)
2362         {
2363         case CREG:
2364                 if (a0reg == KW_SFC - KW_SFC)
2365                         inst = 0;
2366                 else if (a0reg == KW_DFC - KW_SFC)
2367                         inst = 1;
2368                 else
2369                         return error("illegal control register specified");
2370
2371                 break;
2372         case DREG:
2373                 inst = (1 << 3) | a0reg;
2374                 break;
2375         case IMMED:
2376                 if ((a0exattr & DEFINED) == 0)
2377                         return error("constant value must be defined");
2378
2379                 inst = (2 << 3) | (uint16_t)a0exval;
2380                 break;
2381         }
2382
2383         inst |= extension | (1 << 13);
2384         D_word(inst);
2385
2386         ea1gen(siz);
2387
2388         return OK;
2389 }
2390
2391
2392 int m_ploadr(WORD inst, WORD siz)
2393 {
2394         return m_pload(inst, siz, 1 << 9);
2395 }
2396
2397
2398 int m_ploadw(WORD inst, WORD siz)
2399 {
2400         return m_pload(inst, siz, 0 << 9);
2401 }
2402
2403
2404 //
2405 // pmove (68030/68851)
2406 //
2407 int m_pmove(WORD inst, WORD siz)
2408 {
2409         int inst2,reg;
2410
2411         // TODO: 68851 support is not added yet. None of the ST series of
2412         // computers had a 68020 + 68851 socket and since this is an Atari
2413         // targetted assembler.... (same for 68EC030)
2414         CHECKNO30;
2415
2416         inst2 = inst & (1 << 8);        // Copy the flush bit over to inst2 in case we're called from m_pmovefd
2417         inst &= ~(1 << 8);                      // And mask it out
2418
2419         if (am0 == CREG)
2420         {
2421                 reg = a0reg;
2422                 inst2 |= (1 << 9);
2423         }
2424         else if (am1 == CREG)
2425         {
2426                 reg = a1reg;
2427                 inst2 |= 0;
2428         }
2429         else
2430                 return error("pmove sez: Wut?");
2431
2432         // The instruction is a quad-word (8 byte) operation
2433         // for the CPU root pointer and the supervisor root pointer.
2434         // It is a long-word operation for the translation control register
2435         // and the transparent translation registers(TT0 and TT1).
2436         // It is a word operation for the MMU status register.
2437
2438         if (((reg == (KW_URP - KW_SFC)) || (reg == (KW_SRP - KW_SFC)))
2439                 && ((siz != SIZD) && (siz != SIZN)))
2440                 return error(siz_error);
2441
2442         if (((reg == (KW_TC - KW_SFC)) || (reg == (KW_TT0 - KW_SFC)) || (reg == (KW_TT1 - KW_SFC)))
2443                 && ((siz != SIZL) && (siz != SIZN)))
2444                 return error(siz_error);
2445
2446         if ((reg == (KW_MMUSR - KW_SFC)) && ((siz != SIZW) && (siz != SIZN)))
2447                 return error(siz_error);
2448
2449         if (am0 == CREG)
2450         {
2451                 inst |= am1 | a1reg;
2452                 D_word(inst);
2453         }
2454         else if (am1 == CREG)
2455         {
2456                 inst |= am0 | a0reg;
2457                 D_word(inst);
2458         }
2459
2460         switch (reg + KW_SFC)
2461         {
2462         case KW_TC:
2463                 inst2 |= (0 << 10) + (1 << 14); break;
2464         case KW_SRP:
2465                 inst2 |= (2 << 10) + (1 << 14); break;
2466         case KW_CRP:
2467                 inst2 |= (3 << 10) + (1 << 14); break;
2468         case KW_TT0:
2469                 inst2 |= (2 << 10) + (0 << 13); break;
2470         case KW_TT1:
2471                 inst2 |= (3 << 10) + (0 << 13); break;
2472         case KW_MMUSR:
2473                 if (am0 == CREG)
2474                         inst2 |= (1 << 9) + (3 << 13);
2475                 else
2476                         inst2 |= (0 << 9) + (3 << 13);
2477                 break;
2478         default:
2479                 return error("unsupported register");
2480                 break;
2481         }
2482
2483         D_word(inst2);
2484
2485         if (am0 == CREG)
2486                 ea1gen(siz);
2487         else if (am1 == CREG)
2488                 ea0gen(siz);
2489
2490         return OK;
2491 }
2492
2493
2494 //
2495 // pmovefd (68030)
2496 //
2497 int m_pmovefd(WORD inst, WORD siz)
2498 {
2499         CHECKNO30;
2500
2501         return m_pmove(inst | (1 << 8), siz);
2502 }
2503
2504
2505 //
2506 // ptrapcc (68851)
2507 //
2508 int m_ptrapcc(WORD inst, WORD siz)
2509 {
2510         CHECKNO20;
2511         // We stash the 5 condition bits inside the opcode in 68ktab (bits 0-4),
2512         // so we need to extract them first and fill in the clobbered bits.
2513         WORD opcode = inst & 0x1F;
2514         inst = (inst & 0xFFE0) | (0x18);
2515
2516         if (siz == SIZW)
2517         {
2518                 inst |= 2;
2519                 D_word(inst);
2520                 D_word(opcode);
2521                 D_word(a0exval);
2522         }
2523         else if (siz == SIZL)
2524         {
2525                 inst |= 3;
2526                 D_word(inst);
2527                 D_word(opcode);
2528                 D_long(a0exval);
2529         }
2530         else if (siz == SIZN)
2531         {
2532                 inst |= 4;
2533                 D_word(inst);
2534                 D_word(opcode);
2535         }
2536
2537         return OK;
2538 }
2539
2540
2541 //
2542 // ptestr, ptestw (68030)
2543 //
2544 int m_ptest(WORD inst, WORD siz)
2545 {
2546         CHECKNO30;
2547
2548         if (activecpu == CPU_68030)
2549                 return error("Not implemented yet.");
2550         else if (activecpu == CPU_68040)
2551                 return error("Not implemented yet.");
2552
2553         return ERROR;
2554 }
2555
2556 //////////////////////////////////////////////////////////////////////////////
2557 //
2558 // 68020/30/40/60 instructions
2559 // Note: the map of which instructions are allowed on which CPUs came from the
2560 // 68060 manual, section D-1 (page 392 of the PDF). The current implementation
2561 // is missing checks for the EC models which have a simplified FPU.
2562 //
2563 //////////////////////////////////////////////////////////////////////////////
2564
2565
2566 #define FPU_NOWARN 0
2567 #define FPU_FPSP   1
2568
2569
2570 //
2571 // Generate a FPU opcode
2572 //
2573 static inline int gen_fpu(WORD inst, WORD siz, WORD opmode, WORD emul)
2574 {
2575         if (am0 < AM_NONE)      // Check first operand for ea or fp - is this right?
2576         {
2577                 inst |= (1 << 9);       // Bolt on FPU id
2578                 inst |= am0;
2579
2580                 //if (am0 == DREG || am0 == AREG)
2581                         inst |= a0reg;
2582
2583                 D_word(inst);
2584                 inst = 1 << 14; // R/M field (we have ea so have to set this to 1)
2585
2586                 switch (siz)
2587                 {
2588                 case SIZB:      inst |= (6 << 10); break;
2589                 case SIZW:      inst |= (4 << 10); break;
2590                 case SIZL:      inst |= (0 << 10); break;
2591                 case SIZN:
2592                 case SIZS:      inst |= (1 << 10); break;
2593                 case SIZD:      inst |= (5 << 10); break;
2594                 case SIZX:      inst |= (2 << 10); break;
2595                 case SIZP:
2596                         inst |= (3 << 10);
2597
2598                         if (emul)
2599                                 warn("This encoding will cause an unimplemented data type exception in the MC68040 to allow emulation in software.");
2600
2601                         break;
2602                 default:
2603                         return error("Something bad happened, possibly, in gen_fpu.");
2604                         break;
2605                 }
2606
2607                 inst |= (a1reg << 7);
2608                 inst |= opmode;
2609                 D_word(inst);
2610                 ea0gen(siz);
2611         }
2612         else
2613         {
2614                 inst |= (1 << 9);       // Bolt on FPU id
2615                 D_word(inst);
2616                 inst = 0;
2617                 inst = a0reg << 10;
2618                 inst |= (a1reg << 7);
2619                 inst |= opmode;
2620                 D_word(inst);
2621         }
2622
2623         if ((emul & FPU_FPSP) && (activefpu == (FPU_68040 | FPU_68060)))
2624                 warn("Instruction is emulated in 68040/060");
2625
2626         return OK;
2627 }
2628
2629
2630 //
2631 // fabs (6888X, 68040FPSP, 68060FPSP)
2632 //
2633 int m_fabs(WORD inst, WORD siz)
2634 {
2635         CHECKNOFPU;
2636         return gen_fpu(inst, siz, B8(00011000), FPU_NOWARN);
2637 }
2638
2639
2640 //
2641 // fsabs (68040, 68060)
2642 //
2643 int m_fsabs(WORD inst, WORD siz)
2644 {
2645         CHECKNO40;
2646         if (activefpu == FPU_68040)
2647                 return gen_fpu(inst, siz, B8(01011000), FPU_NOWARN);
2648
2649         return error("Unsupported in current FPU");
2650 }
2651
2652
2653 //
2654 // fdabs (68040, 68060)
2655 //
2656 int m_fdabs(WORD inst, WORD siz)
2657 {
2658         if (activefpu == FPU_68040)
2659                 return gen_fpu(inst, siz, B8(01011100), FPU_NOWARN);
2660
2661         return error("Unsupported in current FPU");
2662 }
2663
2664
2665 //
2666 // facos (6888X, 68040FPSP, 68060FPSP)
2667 //
2668 int m_facos(WORD inst, WORD siz)
2669 {
2670         CHECKNOFPU;
2671         return gen_fpu(inst, siz, B8(00011100), FPU_FPSP);
2672 }
2673
2674
2675 //
2676 // fadd (6888X, 68040, 68060)
2677 //
2678 int m_fadd(WORD inst, WORD siz)
2679 {
2680         CHECKNOFPU;
2681         return gen_fpu(inst, siz, B8(00100010), FPU_NOWARN);
2682 }
2683
2684
2685 //
2686 // fsadd (68040, 68060)
2687 //
2688 int m_fsadd(WORD inst, WORD siz)
2689 {
2690         if (activefpu & (FPU_68040 | FPU_68060))
2691                 return gen_fpu(inst, siz, B8(01100010), FPU_NOWARN);
2692
2693         return error("Unsupported in current FPU");
2694 }
2695
2696
2697 //
2698 // fxadd (68040)
2699 //
2700 int m_fdadd(WORD inst, WORD siz)
2701 {
2702         if (activefpu & (FPU_68040 | FPU_68060))
2703                 return gen_fpu(inst, siz, B8(01100110), FPU_NOWARN);
2704
2705         return error("Unsupported in current FPU");
2706 }
2707
2708
2709 //
2710 // fasin (6888X, 68040FPSP, 68060FPSP)
2711 //
2712 int m_fasin(WORD inst, WORD siz)
2713 {
2714         CHECKNOFPU;
2715         return gen_fpu(inst, siz, B8(00001100), FPU_FPSP);
2716 }
2717
2718
2719 //
2720 // fatan (6888X, 68040FPSP, 68060FPSP)
2721 //
2722 int m_fatan(WORD inst, WORD siz)
2723 {
2724         CHECKNOFPU;
2725         return gen_fpu(inst, siz, B8(00001010), FPU_FPSP);
2726 }
2727
2728
2729 //
2730 // fatanh (6888X, 68040FPSP, 68060FPSP)
2731 //
2732 int m_fatanh(WORD inst, WORD siz)
2733 {
2734         CHECKNOFPU;
2735         return gen_fpu(inst, siz, B8(00001101), FPU_FPSP);
2736 }
2737
2738
2739 //
2740 // fcmp (6888X, 68040, 68060)
2741 //
2742 int m_fcmp(WORD inst, WORD siz)
2743 {
2744         CHECKNOFPU;
2745         return gen_fpu(inst, siz, B8(00111000), FPU_FPSP);
2746 }
2747
2748
2749 //
2750 // fcos (6888X, 68040FPSP, 68060FPSP)
2751 //
2752 int m_fcos(WORD inst, WORD siz)
2753 {
2754         CHECKNOFPU;
2755         return gen_fpu(inst, siz, B8(00011101), FPU_FPSP);
2756 }
2757
2758
2759 //
2760 // fcosh (6888X, 68040FPSP, 68060FPSP)
2761 //
2762 int m_fcosh(WORD inst, WORD siz)
2763 {
2764         CHECKNOFPU;
2765         return gen_fpu(inst, siz, B8(00011001), FPU_FPSP);
2766 }
2767
2768
2769 //
2770 // fdbcc (6888X, 68040, 68060FPSP)
2771 //
2772 int m_fdbcc(WORD inst, WORD siz)
2773 {
2774         CHECKNOFPU;
2775         WORD opcode = inst & 0x3F;      // Grab conditional bitfield
2776
2777         inst &= ~0x3F;
2778         inst |= 1 << 3;
2779
2780         siz = siz;
2781         inst |= a0reg;
2782         D_word(inst);
2783         D_word(opcode);
2784
2785         if (a1exattr & DEFINED)
2786         {
2787                 if ((a1exattr & TDB) != cursect)
2788                         return error(rel_error);
2789
2790                 uint32_t v = (uint32_t)a1exval - sloc;
2791
2792                 if ((v + 0x8000) > 0x10000)
2793                         return error(range_error);
2794
2795                 D_word(v);
2796         }
2797         else
2798         {
2799                 AddFixup(FU_WORD | FU_PCREL | FU_ISBRA, sloc, a1expr);
2800                 D_word(0);
2801         }
2802
2803         if (activefpu == FPU_68060)
2804                 warn("Instruction is emulated in 68060");
2805
2806         return OK;
2807 }
2808
2809
2810 //
2811 // fdiv (6888X, 68040, 68060)
2812 //
2813 int m_fdiv(WORD inst, WORD siz)
2814 {
2815         CHECKNOFPU;
2816         return gen_fpu(inst, siz, B8(00100000), FPU_NOWARN);
2817 }
2818
2819
2820 //
2821 // fsdiv (68040, 68060)
2822 //
2823 int m_fsdiv(WORD inst, WORD siz)
2824 {
2825         if (activefpu & (FPU_68040 | FPU_68060))
2826                 return gen_fpu(inst, siz, B8(01100000), FPU_NOWARN);
2827
2828         return error("Unsupported in current FPU");
2829 }
2830
2831
2832 //
2833 // fddiv (68040, 68060)
2834 //
2835 int m_fddiv(WORD inst, WORD siz)
2836 {
2837         if (activefpu & (FPU_68040 | FPU_68060))
2838                 return gen_fpu(inst, siz, B8(01100100), FPU_NOWARN);
2839
2840         return error("Unsupported in current FPU");
2841 }
2842
2843
2844 //
2845 // fetox (6888X, 68040FPSP, 68060FPSP)
2846 //
2847 int m_fetox(WORD inst, WORD siz)
2848 {
2849         CHECKNOFPU;
2850         return gen_fpu(inst, siz, B8(00010000), FPU_FPSP);
2851 }
2852
2853
2854 //
2855 // fetoxm1 (6888X, 68040FPSP, 68060FPSP)
2856 //
2857 int m_fetoxm1(WORD inst, WORD siz)
2858 {
2859         CHECKNOFPU;
2860         return gen_fpu(inst, siz, B8(00001000), FPU_FPSP);
2861 }
2862
2863
2864 //
2865 // fgetexp (6888X, 68040FPSP, 68060FPSP)
2866 //
2867 int m_fgetexp(WORD inst, WORD siz)
2868 {
2869         CHECKNOFPU;
2870         return gen_fpu(inst, siz, B8(00011110), FPU_FPSP);
2871 }
2872
2873
2874 //
2875 // fgetman (6888X, 68040FPSP, 68060FPSP)
2876 //
2877 int m_fgetman(WORD inst, WORD siz)
2878 {
2879         CHECKNOFPU;
2880         return gen_fpu(inst, siz, B8(00011111), FPU_FPSP);
2881 }
2882
2883
2884 //
2885 // fint (6888X, 68040FPSP, 68060)
2886 //
2887 int m_fint(WORD inst, WORD siz)
2888 {
2889         if (am1 == AM_NONE)
2890                 // special case - fint fpx = fint fpx,fpx
2891                 a1reg = a0reg;
2892
2893         if (activefpu == FPU_68040)
2894                 warn("Instruction is emulated in 68040");
2895
2896         return gen_fpu(inst, siz, B8(00000001), FPU_NOWARN);
2897 }
2898
2899
2900 //
2901 // fintrz (6888X, 68040FPSP, 68060)
2902 //
2903 int m_fintrz(WORD inst, WORD siz)
2904 {
2905         if (am1 == AM_NONE)
2906                 // special case - fintrz fpx = fintrz fpx,fpx
2907                 a1reg = a0reg;
2908
2909         if (activefpu == FPU_68040)
2910                 warn("Instruction is emulated in 68040");
2911         
2912         return gen_fpu(inst, siz, B8(00000011), FPU_NOWARN);
2913 }
2914
2915
2916 //
2917 // flog10 (6888X, 68040FPSP, 68060FPSP)
2918 //
2919 int m_flog10(WORD inst, WORD siz)
2920 {
2921         CHECKNOFPU;
2922         return gen_fpu(inst, siz, B8(00010101), FPU_FPSP);
2923 }
2924
2925
2926 //
2927 // flog2 (6888X, 68040FPSP, 68060FPSP)
2928 //
2929 int m_flog2(WORD inst, WORD siz)
2930 {
2931         CHECKNOFPU;
2932         return gen_fpu(inst, siz, B8(00010110), FPU_FPSP);
2933 }
2934
2935
2936 //
2937 // flogn (6888X, 68040FPSP, 68060FPSP)
2938 //
2939 int m_flogn(WORD inst, WORD siz)
2940 {
2941         CHECKNOFPU;
2942         return gen_fpu(inst, siz, B8(00010100), FPU_FPSP);
2943 }
2944
2945
2946 //
2947 // flognp1 (68040FPSP, 68060FPSP)
2948 //
2949 int m_flognp1(WORD inst, WORD siz)
2950 {
2951         if (activefpu & (FPU_68040 | FPU_68060))
2952                 return gen_fpu(inst, siz, B8(00000110), FPU_FPSP);
2953
2954         return error("Unsupported in current FPU");
2955 }
2956
2957
2958 //
2959 // fmod (6888X, 68040FPSP, 68060FPSP)
2960 //
2961 int m_fmod(WORD inst, WORD siz)
2962 {
2963         CHECKNOFPU;
2964         return gen_fpu(inst, siz, B8(00100001), FPU_FPSP);
2965 }
2966
2967
2968 //
2969 // fmove (6888X, 68040, 68060)
2970 //
2971 int m_fmove(WORD inst, WORD siz)
2972 {
2973         CHECKNOFPU;
2974
2975         // EA to register
2976         if ((am0 == FREG) && (am1 < AM_USP))
2977         {
2978                 // fpx->ea
2979                 // EA
2980                 inst |= am1 | a1reg;
2981                 D_word(inst);
2982
2983                 // R/M
2984                 inst = 3 << 13;
2985
2986                 // Source specifier
2987                 switch (siz)
2988                 {
2989                 case SIZB:      inst |= (6 << 10); break;
2990                 case SIZW:      inst |= (4 << 10); break;
2991                 case SIZL:      inst |= (0 << 10); break;
2992                 case SIZN:
2993                 case SIZS:      inst |= (1 << 10); break;
2994                 case SIZD:      inst |= (5 << 10); break;
2995                 case SIZX:      inst |= (2 << 10); break;
2996                 case SIZP:      inst |= (3 << 10);
2997                         // In P size we have 2 cases: {#k} where k is immediate
2998                         // and {Dn} where Dn=Data register
2999                         if (bfparam1)
3000                         {
3001                                 // Dn
3002                                 inst |= 1 << 12;
3003                                 inst |= bfval1 << 4;
3004                         }
3005                         else
3006                         {
3007                                 // #k
3008                                 if (bfval1 > 63 && bfval1 < -64)
3009                                         return error("K-factor must be between -64 and 63");
3010
3011                                 inst |= bfval1 & 127;
3012                         }
3013
3014                         break;
3015                 default:
3016                         return error("Something bad happened, possibly.");
3017                         break;
3018                 }
3019
3020                 // Destination specifier
3021                 inst |= (a0reg << 7);
3022
3023                 // Opmode
3024                 inst |= 0;
3025
3026                 D_word(inst);
3027                 ea1gen(siz);
3028         }
3029         else if ((am0 < AM_USP) && (am1 == FREG))
3030         {
3031                 // ea->fpx
3032
3033                 // EA
3034                 inst |= am0 | a0reg;
3035                 D_word(inst);
3036
3037                 // R/M
3038                 inst = 1 << 14;
3039
3040                 // Source specifier
3041                 switch (siz)
3042                 {
3043                 case SIZB:      inst |= (6 << 10); break;
3044                 case SIZW:      inst |= (4 << 10); break;
3045                 case SIZL:      inst |= (0 << 10); break;
3046                 case SIZN:
3047                 case SIZS:      inst |= (1 << 10); break;
3048                 case SIZD:      inst |= (5 << 10); break;
3049                 case SIZX:      inst |= (2 << 10); break;
3050                 case SIZP:      inst |= (3 << 10); break;
3051                 default:
3052                         return error("Something bad happened, possibly.");
3053                         break;
3054                 }
3055
3056                 // Destination specifier
3057                 inst |= (a1reg << 7);
3058
3059                 // Opmode
3060                 inst |= 0;
3061
3062                 D_word(inst);
3063                 ea0gen(siz);
3064         }
3065         else if ((am0 == FREG) && (am1 == FREG))
3066         {
3067                 // register-to-register
3068                 // Essentially ea to register with R/0=0
3069
3070                 // EA
3071                 D_word(inst);
3072
3073                 // R/M
3074                 inst = 0 << 14;
3075
3076                 // Source specifier
3077                 if (siz != SIZX && siz != SIZN)
3078                         return error("Invalid size");
3079
3080                 // Source register
3081                 inst |= (a0reg << 10);
3082
3083                 // Destination register
3084                 inst |= (a1reg << 7);
3085
3086                 D_word(inst);
3087         }
3088
3089         return OK;
3090 }
3091
3092
3093 //
3094 // fmove (6888X, 68040, 68060)
3095 //
3096 int m_fmovescr(WORD inst, WORD siz)
3097 {
3098         CHECKNOFPU;
3099
3100         // Move Floating-Point System Control Register (FPCR)
3101         // ea
3102         // dr
3103         // Register select
3104         if ((am0 == FPSCR) && (am1 < AM_USP))
3105         {
3106                 inst |= am1 | a1reg;
3107                 D_word(inst);
3108                 inst = (1 << 13) + (1 << 15);
3109                 inst |= a0reg;
3110                 D_word(inst);
3111                 ea1gen(siz);
3112                 return OK;
3113         }
3114         else if ((am1 == FPSCR) && (am0 < AM_USP))
3115         {
3116                 inst |= am0 | a0reg;
3117                 D_word(inst);
3118                 inst = (0 << 13) + (1 << 15);
3119                 inst |= a1reg;
3120                 D_word(inst);
3121                 ea0gen(siz);
3122                 return OK;
3123         }
3124
3125         return error("m_fmovescr says: wut?");
3126 }
3127
3128 //
3129 // fsmove/fdmove (68040, 68060)
3130 //
3131 int m_fsmove(WORD inst, WORD siz)
3132 {
3133         if (!(activefpu & (FPU_68040 | FPU_68060)))
3134                 return error("Unsupported in current FPU");
3135
3136         return error("Not implemented yet.");
3137
3138 #if 0
3139         if (activefpu == FPU_68040)
3140                 return gen_fpu(inst, siz, B8(01100100), FPU_P_EMUL);
3141         else
3142                 return error("Unsupported in current FPU");
3143 #endif
3144 }
3145
3146
3147 int m_fdmove(WORD inst, WORD siz)
3148 {
3149         if (!(activefpu & (FPU_68040 | FPU_68060)))
3150                 return error("Unsupported in current FPU");
3151
3152         return error("Not implemented yet.");
3153
3154 #if 0
3155         if (activefpu == FPU_68040)
3156                 return gen_fpu(inst, siz, B8(01100100), FPU_P_EMUL);
3157         else
3158                 return error("Unsupported in current FPU");
3159 #endif
3160 }
3161
3162
3163 //
3164 // fmovecr (6888X, 68040FPSP, 68060FPSP)
3165 //
3166 int m_fmovecr(WORD inst, WORD siz)
3167 {
3168         CHECKNOFPU;
3169
3170         D_word(inst);
3171         inst = 0x5c00;
3172         inst |= a1reg << 7;
3173         inst |= a0exval;
3174         D_word(inst);
3175
3176         if (activefpu == FPU_68040)
3177                 warn("Instruction is emulated in 68040/060");
3178
3179         return OK;
3180 }
3181
3182
3183 //
3184 // fmovem (6888X, 68040, 68060FPSP)
3185 //
3186 int m_fmovem(WORD inst, WORD siz)
3187 {
3188         CHECKNOFPU;
3189
3190         WORD regmask;
3191         WORD datareg;
3192
3193         if (siz == SIZX || siz == SIZN)
3194         {
3195                 if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
3196                 {
3197                         // fmovem.x <rlist>,ea
3198                         if (fpu_reglist_left(&regmask) < 0)
3199                                 return OK;
3200
3201                         if (*tok++ != ',')
3202                                 return error("missing comma");
3203
3204                         if (amode(0) < 0)
3205                                 return OK;
3206
3207                         inst |= am0 | a0reg;
3208
3209                         if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3210                                 return error("invalid addressing mode");
3211
3212                         D_word(inst);
3213                         inst = (1 << 15) | (1 << 14) | (1 << 13) | (0 << 11) | regmask;
3214                         D_word(inst);
3215                         ea0gen(siz);
3216                         return OK;
3217                 }
3218                 else if ((*tok >= KW_D0) && (*tok <= KW_D7))
3219                 {
3220                         // fmovem.x Dn,ea
3221                         datareg = (*tok++ & 7) << 10;
3222
3223                         if (*tok++ != ',')
3224                                 return error("missing comma");
3225
3226                         if (amode(0) < 0)
3227                                 return OK;
3228
3229                         inst |= am0 | a0reg;
3230
3231                         if (!(amsktab[am0] & (C_ALTCTRL | M_APREDEC)))
3232                                 return error("invalid addressing mode");
3233
3234                         // Quote from the 060 manual:
3235                         // "[..] when the processor attempts an FMOVEM.X instruction using a dynamic register list."
3236                         if (activefpu == FPU_68060)
3237                                 warn("Instruction is emulated in 68060");
3238
3239                         D_word(inst);
3240                         inst = (1 << 15) | (1 << 14) | (1 << 13) | (1 << 11) | (datareg << 4);
3241                         D_word(inst);
3242                         ea0gen(siz);
3243                         return OK;
3244                 }
3245                 else
3246                 {
3247                         // fmovem.x ea,...
3248                         if (amode(0) < 0)
3249                                 return OK;
3250
3251                         inst |= am0 | a0reg;
3252
3253                         if (*tok++ != ',')
3254                                 return error("missing comma");
3255
3256                         if ((*tok >= KW_FP0) && (*tok <= KW_FP7))
3257                         {
3258                                 // fmovem.x ea,<rlist>
3259                                 if (fpu_reglist_right(&regmask) < 0)
3260                                         return OK;
3261
3262                                 D_word(inst);
3263                                 inst = (1 << 15) | (1 << 14) | (0 << 13) | (2 << 11) | regmask;
3264                                 D_word(inst);
3265                                 ea0gen(siz);
3266                                 return OK;
3267                         }
3268                         else
3269                         {
3270                                 // fmovem.x ea,Dn
3271                                 datareg = (*tok++ & 7) << 10;
3272
3273                                 // Quote from the 060 manual:
3274                                 // "[..] when the processor attempts an FMOVEM.X instruction using a dynamic register list."
3275                                 if (activefpu == FPU_68060)
3276                                         warn("Instruction is emulated in 68060");
3277
3278                                 D_word(inst);
3279                                 inst = (1 << 15) | (1 << 14) | (0 << 13) | (3 << 11) | (datareg << 4);
3280                                 D_word(inst);
3281                                 ea0gen(siz);
3282                                 return OK;
3283                         }
3284                 }
3285         }
3286         else if (siz == SIZL)
3287         {
3288                 if ((*tok == KW_FPCR) || (*tok == KW_FPSR) || (*tok == KW_FPIAR))
3289                 {
3290                         // fmovem.l <rlist>,ea
3291                         regmask = (1 << 15) | (1 << 13);
3292                         int no_control_regs = 0;
3293
3294 fmovem_loop_1:
3295                         if (*tok == KW_FPCR)
3296                         {
3297                                 regmask |= (1 << 12);
3298                                 tok++;
3299                                 no_control_regs++;
3300                                 goto fmovem_loop_1;
3301                         }
3302
3303                         if (*tok == KW_FPSR)
3304                         {
3305                                 regmask |= (1 << 11);
3306                                 tok++;
3307                                 no_control_regs++;
3308                                 goto fmovem_loop_1;
3309                         }
3310
3311                         if (*tok == KW_FPIAR)
3312                         {
3313                                 regmask |= (1 << 10);
3314                                 tok++;
3315                                 no_control_regs++;
3316                                 goto fmovem_loop_1;
3317                         }
3318
3319                         if ((*tok == '/') || (*tok == '-'))
3320                         {
3321                                 tok++;
3322                                 goto fmovem_loop_1;
3323                         }
3324
3325                         if (*tok++ != ',')
3326                                 return error("missing comma");
3327
3328                         if (amode(0) < 0)
3329                                 return OK;
3330
3331                         // Quote from the 060 manual:
3332                         // "[..] when the processor attempts to execute an FMOVEM.L instruction with
3333                         // an immediate addressing mode to more than one floating - point
3334                         // control register (FPCR, FPSR, FPIAR)[..]"
3335                         if (activefpu == FPU_68060)
3336                                 if (no_control_regs > 1 && am0 == IMMED)
3337                                         warn("Instruction is emulated in 68060");
3338
3339                         inst |= am0 | a0reg;
3340                         D_word(inst);
3341                         D_word(regmask);
3342                         ea0gen(siz);
3343                 }
3344                 else
3345                 {
3346                         // fmovem.l ea,<rlist>
3347                         if (amode(0) < 0)
3348                                 return OK;
3349
3350                         inst |= am0 | a0reg;
3351
3352                         if (*tok++ != ',')
3353                                 return error("missing comma");
3354
3355                         regmask = (1 << 15) | (0 << 13);
3356
3357 fmovem_loop_2:
3358                         if (*tok == KW_FPCR)
3359                         {
3360                                 regmask |= (1 << 12);
3361                                 tok++;
3362                                 goto fmovem_loop_2;
3363                         }
3364
3365                         if (*tok == KW_FPSR)
3366                         {
3367                                 regmask |= (1 << 11);
3368                                 tok++;
3369                                 goto fmovem_loop_2;
3370                         }
3371
3372                         if (*tok == KW_FPIAR)
3373                         {
3374                                 regmask |= (1 << 10);
3375                                 tok++;
3376                                 goto fmovem_loop_2;
3377                         }
3378
3379                         if ((*tok == '/') || (*tok == '-'))
3380                         {
3381                                 tok++;
3382                                 goto fmovem_loop_2;
3383                         }
3384
3385                         if (*tok != EOL)
3386                                 return error("extra (unexpected) text found");
3387
3388                         inst |= am0 | a0reg;
3389                         D_word(inst);
3390                         D_word(regmask);
3391                         ea0gen(siz);
3392                 }
3393         }
3394         else
3395                 return error("bad size suffix");
3396
3397         return OK;
3398 }
3399
3400
3401 //
3402 // fmul (6888X, 68040, 68060)
3403 //
3404 int m_fmul(WORD inst, WORD siz)
3405 {
3406         CHECKNOFPU;
3407         return gen_fpu(inst, siz, B8(00100011), FPU_NOWARN);
3408 }
3409
3410
3411 //
3412 // fsmul (68040, 68060)
3413 //
3414 int m_fsmul(WORD inst, WORD siz)
3415 {
3416         if (activefpu & (FPU_68040 | FPU_68060))
3417                 return gen_fpu(inst, siz, B8(01100011), FPU_NOWARN);
3418         
3419         return error("Unsupported in current FPU");
3420 }
3421
3422
3423 //
3424 // fdmul (68040)
3425 //
3426 int m_fdmul(WORD inst, WORD siz)
3427 {
3428         if (activefpu & (FPU_68040 | FPU_68060))
3429                 return gen_fpu(inst, siz, B8(01100111), FPU_NOWARN);
3430
3431         return error("Unsupported in current FPU");
3432 }
3433
3434
3435 //
3436 // fneg (6888X, 68040, 68060)
3437 //
3438 int m_fneg(WORD inst, WORD siz)
3439 {
3440         CHECKNOFPU;
3441
3442         if (am1 == AM_NONE)
3443         {
3444                 a1reg = a0reg;
3445                 return gen_fpu(inst, siz, B8(00011010), FPU_NOWARN);
3446         }
3447         
3448         return gen_fpu(inst, siz, B8(00011010), FPU_NOWARN);
3449 }
3450
3451
3452 //
3453 // fsneg (68040, 68060)
3454 //
3455 int m_fsneg(WORD inst, WORD siz)
3456 {
3457         if (activefpu & (FPU_68040 | FPU_68060))
3458         {
3459                 if (am1 == AM_NONE)
3460                 {
3461                         a1reg = a0reg;
3462                         return gen_fpu(inst, siz, B8(01011010), FPU_NOWARN);
3463                 }
3464                 
3465                 return gen_fpu(inst, siz, B8(01011010), FPU_NOWARN);
3466         }
3467
3468         return error("Unsupported in current FPU");
3469 }
3470
3471
3472 //
3473 // fdneg (68040, 68060)
3474 //
3475 int m_fdneg(WORD inst, WORD siz)
3476 {
3477         if (activefpu & (FPU_68040 | FPU_68060))
3478         {
3479                 if (am1 == AM_NONE)
3480                 {
3481                                 a1reg = a0reg;
3482                                 return gen_fpu(inst, siz, B8(01011110), FPU_NOWARN);
3483                 }
3484
3485                 return gen_fpu(inst, siz, B8(01011110), FPU_NOWARN);
3486         }
3487
3488         return error("Unsupported in current FPU");
3489 }
3490
3491
3492 //
3493 // fnop (6888X, 68040, 68060)
3494 //
3495 int m_fnop(WORD inst, WORD siz)
3496 {
3497         CHECKNOFPU;
3498         return gen_fpu(inst, siz, B8(00000000), FPU_NOWARN);
3499 }
3500
3501
3502 //
3503 // frem (6888X, 68040FPSP, 68060FPSP)
3504 //
3505 int m_frem(WORD inst, WORD siz)
3506 {
3507         CHECKNOFPU;
3508         return gen_fpu(inst, siz, B8(00100101), FPU_FPSP);
3509 }
3510
3511
3512 //
3513 // fscale (6888X, 68040FPSP, 68060FPSP)
3514 //
3515 int m_fscale(WORD inst, WORD siz)
3516 {
3517         CHECKNOFPU;
3518         return gen_fpu(inst, siz, B8(00100110), FPU_FPSP);
3519 }
3520
3521
3522 //
3523 // FScc (6888X, 68040, 68060), cpScc (68851, 68030), PScc (68851)
3524 // TODO: Add check for PScc to ensure 68020+68851 active
3525 // TODO: Add check for cpScc to ensure 68020+68851, 68030
3526 //
3527 int m_fscc(WORD inst, WORD siz)
3528 {
3529         CHECKNOFPU;
3530
3531         // We stash the 5 condition bits inside the opcode in 68ktab (bits 4-0),
3532         // so we need to extract them first and fill in the clobbered bits.
3533         WORD opcode = inst & 0x1F;
3534         inst &= 0xFFE0;
3535         inst |= am0 | a0reg;
3536         D_word(inst);
3537         ea0gen(siz);
3538         D_word(opcode);
3539         if (activefpu == FPU_68060)
3540                 warn("Instruction is emulated in 68060");
3541         return OK;
3542 }
3543
3544
3545 //
3546 // fsgldiv (6888X, 68040FPSP, 68060FPSP)
3547 //
3548 int m_fsgldiv(WORD inst, WORD siz)
3549 {
3550         CHECKNOFPU;
3551         return gen_fpu(inst, siz, B8(00100100), FPU_FPSP);
3552 }
3553
3554
3555 //
3556 // fsglmul (6888X, 68040, 68060FPSP)
3557 //
3558 int m_fsglmul(WORD inst, WORD siz)
3559 {
3560         CHECKNOFPU;
3561         return gen_fpu(inst, siz, B8(00100111), FPU_FPSP);
3562 }
3563
3564
3565 //
3566 // fsin (6888X, 68040FPSP, 68060FPSP)
3567 //
3568 int m_fsin(WORD inst, WORD siz)
3569 {
3570         CHECKNOFPU;
3571         return gen_fpu(inst, siz, B8(00001110), FPU_FPSP);
3572 }
3573
3574
3575 //
3576 // fsincos (6888X, 68040FPSP, 68060FPSP)
3577 //
3578 int m_fsincos(WORD inst, WORD siz)
3579 {
3580         CHECKNOFPU;
3581
3582         // Swap a1reg, a2reg as a2reg should be stored in the bitfield gen_fpu
3583         // generates
3584         int temp;
3585         temp = a2reg;
3586         a2reg = a1reg;
3587         a1reg = temp;
3588
3589         if (gen_fpu(inst, siz, B8(00110000), FPU_FPSP) == OK)
3590         {
3591                 chptr[-1] |= a2reg;
3592                 return OK;
3593         }
3594
3595         return ERROR;
3596 }
3597
3598
3599 //
3600 // fsinh (6888X, 68040FPSP, 68060FPSP)
3601 //
3602 int m_fsinh(WORD inst, WORD siz)
3603 {
3604         CHECKNOFPU;
3605         return gen_fpu(inst, siz, B8(00000010), FPU_FPSP);
3606 }
3607
3608
3609 //
3610 // fsqrt (6888X, 68040, 68060)
3611 //
3612 int m_fsqrt(WORD inst, WORD siz)
3613 {
3614         CHECKNOFPU;
3615         return gen_fpu(inst, siz, B8(00000100), FPU_NOWARN);
3616 }
3617
3618
3619 //
3620 // fsfsqrt (68040, 68060)
3621 //
3622 int m_fsfsqrt(WORD inst, WORD siz)
3623 {
3624         if (activefpu & (FPU_68040 | FPU_68060))
3625                 return gen_fpu(inst, siz, B8(01000001), FPU_NOWARN);
3626         
3627         return error("Unsupported in current FPU");
3628 }
3629
3630
3631 //
3632 // fdfsqrt (68040, 68060)
3633 //
3634 int m_fdfsqrt(WORD inst, WORD siz)
3635 {
3636         if (activefpu & (FPU_68040 | FPU_68060))
3637                 return gen_fpu(inst, siz, B8(01000101), FPU_NOWARN);
3638
3639         return error("Unsupported in current FPU");
3640 }
3641
3642
3643 //
3644 // fsub (6888X, 68040, 68060)
3645 //
3646 int m_fsub(WORD inst, WORD siz)
3647 {
3648         CHECKNOFPU;
3649         return gen_fpu(inst, siz, B8(00101000), FPU_NOWARN);
3650 }
3651
3652
3653 //
3654 // fsfsub (68040, 68060)
3655 //
3656 int m_fsfsub(WORD inst, WORD siz)
3657 {
3658         if (activefpu & (FPU_68040 | FPU_68060))
3659                 return gen_fpu(inst, siz, B8(01101000), FPU_NOWARN);
3660
3661         return error("Unsupported in current FPU");
3662 }
3663
3664
3665 //
3666 // fdfsub (68040, 68060)
3667 //
3668 int m_fdsub(WORD inst, WORD siz)
3669 {
3670         if (activefpu & (FPU_68040 | FPU_68060))
3671                 return gen_fpu(inst, siz, B8(01101100), FPU_NOWARN);
3672
3673         return error("Unsupported in current FPU");
3674 }
3675
3676
3677 //
3678 // ftan (6888X, 68040FPSP, 68060FPSP)
3679 //
3680 int m_ftan(WORD inst, WORD siz)
3681 {
3682         CHECKNOFPU;
3683         return gen_fpu(inst, siz, B8(00001111), FPU_FPSP);
3684 }
3685
3686
3687 //
3688 // ftanh (6888X, 68040FPSP, 68060FPSP)
3689 //
3690 int m_ftanh(WORD inst, WORD siz)
3691 {
3692         CHECKNOFPU;
3693         return gen_fpu(inst, siz, B8(00001001), FPU_FPSP);
3694 }
3695
3696
3697 //
3698 // ftentox (6888X, 68040FPSP, 68060FPSP)
3699 //
3700 int m_ftentox(WORD inst, WORD siz)
3701 {
3702         CHECKNOFPU;
3703         return gen_fpu(inst, siz, B8(00010010), FPU_FPSP);
3704 }
3705
3706
3707 //
3708 // FTRAPcc (6888X, 68040, 68060FPSP)
3709 //
3710 int m_ftrapcc(WORD inst, WORD siz)
3711 {
3712         CHECKNOFPU;
3713
3714         // We stash the 5 condition bits inside the opcode in 68ktab (bits 3-7),
3715         // so we need to extract them first and fill in the clobbered bits.
3716         WORD opcode = (inst >> 3) & 0x1F;
3717         inst = (inst & 0xFF07) | (0xF << 3);
3718
3719         if (siz == SIZW)
3720         {
3721                 inst |= 2;
3722                 D_word(inst);
3723                 D_word(opcode);
3724                 D_word(a0exval);
3725         }
3726         else if (siz == SIZL)
3727         {
3728                 inst |= 3;
3729                 D_word(inst);
3730                 D_word(opcode);
3731                 D_long(a0exval);
3732         }
3733         else if (siz == SIZN)
3734         {
3735                 inst |= 4;
3736                 D_word(inst);
3737                 D_word(opcode);
3738                 return OK;
3739         }
3740
3741         if (activefpu == FPU_68060)
3742                 warn("Instruction is emulated in 68060");
3743
3744         return OK;
3745 }
3746
3747
3748 //
3749 // ftst (6888X, 68040, 68060)
3750 //
3751 int m_ftst(WORD inst, WORD siz)
3752 {
3753         CHECKNOFPU;
3754         return gen_fpu(inst, siz, B8(00111010), FPU_NOWARN);
3755 }
3756
3757
3758 //
3759 // ftwotox (6888X, 68040FPSP, 68060FPSP)
3760 //
3761 int m_ftwotox(WORD inst, WORD siz)
3762 {
3763         CHECKNOFPU;
3764         return gen_fpu(inst, siz, B8(00010001), FPU_FPSP);
3765 }
3766
3767
3768 /////////////////////////////////
3769 //                             //
3770 // 68060 specific instructions //
3771 //                             //
3772 /////////////////////////////////
3773
3774
3775 //
3776 // lpstop (68060)
3777 //
3778 int m_lpstop(WORD inst, WORD siz)
3779 {
3780         CHECKNO60;
3781         D_word(B16(00000001, 11000000));
3782
3783         if (a0exattr&DEFINED)
3784                 D_word(a0exval);
3785         else
3786         {
3787                 AddFixup(FU_WORD, sloc, a0expr);
3788                 D_word(0);
3789         }
3790
3791         return OK;
3792 }
3793
3794
3795 //
3796 // plpa (68060)
3797 //
3798 int m_plpa(WORD inst, WORD siz)
3799 {
3800         CHECKNO60;
3801         inst |= a0reg;          // Install register
3802         D_word(inst);
3803
3804         return OK;
3805 }
3806