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