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