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