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