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