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