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