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