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