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