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