summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/cpu/m68000/m68kfpu.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/cpu/m68000/m68kfpu.c')
-rw-r--r--trunk/src/emu/cpu/m68000/m68kfpu.c1993
1 files changed, 1993 insertions, 0 deletions
diff --git a/trunk/src/emu/cpu/m68000/m68kfpu.c b/trunk/src/emu/cpu/m68000/m68kfpu.c
new file mode 100644
index 00000000000..9556df0a6c2
--- /dev/null
+++ b/trunk/src/emu/cpu/m68000/m68kfpu.c
@@ -0,0 +1,1993 @@
+#include <math.h>
+
+#define FPCC_N 0x08000000
+#define FPCC_Z 0x04000000
+#define FPCC_I 0x02000000
+#define FPCC_NAN 0x01000000
+
+#define DOUBLE_INFINITY U64(0x7ff0000000000000)
+#define DOUBLE_EXPONENT U64(0x7ff0000000000000)
+#define DOUBLE_MANTISSA U64(0x000fffffffffffff)
+
+extern flag floatx80_is_nan( floatx80 a );
+
+// masks for packed dwords, positive k-factor
+static const UINT32 pkmask2[18] =
+{
+ 0xffffffff, 0, 0xf0000000, 0xff000000, 0xfff00000, 0xffff0000,
+ 0xfffff000, 0xffffff00, 0xfffffff0, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff
+};
+
+static const UINT32 pkmask3[18] =
+{
+ 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xf0000000, 0xff000000, 0xfff00000, 0xffff0000,
+ 0xfffff000, 0xffffff00, 0xfffffff0, 0xffffffff,
+};
+
+INLINE double fx80_to_double(floatx80 fx)
+{
+ UINT64 d;
+ double *foo;
+
+ foo = (double *)&d;
+
+ d = floatx80_to_float64(fx);
+
+ return *foo;
+}
+
+INLINE floatx80 double_to_fx80(double in)
+{
+ UINT64 *d;
+
+ d = (UINT64 *)&in;
+
+ return float64_to_floatx80(*d);
+}
+
+INLINE floatx80 load_extended_float80(m68ki_cpu_core *m68k, UINT32 ea)
+{
+ UINT32 d1,d2;
+ UINT16 d3;
+ floatx80 fp;
+
+ d3 = m68ki_read_16(m68k, ea);
+ d1 = m68ki_read_32(m68k, ea+4);
+ d2 = m68ki_read_32(m68k, ea+8);
+
+ fp.high = d3;
+ fp.low = ((UINT64)d1<<32) | (d2 & 0xffffffff);
+
+ return fp;
+}
+
+INLINE void store_extended_float80(m68ki_cpu_core *m68k, UINT32 ea, floatx80 fpr)
+{
+ m68ki_write_16(m68k, ea+0, fpr.high);
+ m68ki_write_16(m68k, ea+2, 0);
+ m68ki_write_32(m68k, ea+4, (fpr.low>>32)&0xffffffff);
+ m68ki_write_32(m68k, ea+8, fpr.low&0xffffffff);
+}
+
+INLINE floatx80 load_pack_float80(m68ki_cpu_core *m68k, UINT32 ea)
+{
+ UINT32 dw1, dw2, dw3;
+ floatx80 result;
+ double tmp;
+ char str[128], *ch;
+
+ dw1 = m68ki_read_32(m68k, ea);
+ dw2 = m68ki_read_32(m68k, ea+4);
+ dw3 = m68ki_read_32(m68k, ea+8);
+
+ ch = &str[0];
+ if (dw1 & 0x80000000) // mantissa sign
+ {
+ *ch++ = '-';
+ }
+ *ch++ = (char)((dw1 & 0xf) + '0');
+ *ch++ = '.';
+ *ch++ = (char)(((dw2 >> 28) & 0xf) + '0');
+ *ch++ = (char)(((dw2 >> 24) & 0xf) + '0');
+ *ch++ = (char)(((dw2 >> 20) & 0xf) + '0');
+ *ch++ = (char)(((dw2 >> 16) & 0xf) + '0');
+ *ch++ = (char)(((dw2 >> 12) & 0xf) + '0');
+ *ch++ = (char)(((dw2 >> 8) & 0xf) + '0');
+ *ch++ = (char)(((dw2 >> 4) & 0xf) + '0');
+ *ch++ = (char)(((dw2 >> 0) & 0xf) + '0');
+ *ch++ = (char)(((dw3 >> 28) & 0xf) + '0');
+ *ch++ = (char)(((dw3 >> 24) & 0xf) + '0');
+ *ch++ = (char)(((dw3 >> 20) & 0xf) + '0');
+ *ch++ = (char)(((dw3 >> 16) & 0xf) + '0');
+ *ch++ = (char)(((dw3 >> 12) & 0xf) + '0');
+ *ch++ = (char)(((dw3 >> 8) & 0xf) + '0');
+ *ch++ = (char)(((dw3 >> 4) & 0xf) + '0');
+ *ch++ = (char)(((dw3 >> 0) & 0xf) + '0');
+ *ch++ = 'E';
+ if (dw1 & 0x40000000) // exponent sign
+ {
+ *ch++ = '-';
+ }
+ *ch++ = (char)(((dw1 >> 24) & 0xf) + '0');
+ *ch++ = (char)(((dw1 >> 20) & 0xf) + '0');
+ *ch++ = (char)(((dw1 >> 16) & 0xf) + '0');
+ *ch = '\0';
+
+ sscanf(str, "%le", &tmp);
+
+ result = double_to_fx80(tmp);
+
+ return result;
+}
+
+INLINE void store_pack_float80(m68ki_cpu_core *m68k, UINT32 ea, int k, floatx80 fpr)
+{
+ UINT32 dw1, dw2, dw3;
+ char str[128], *ch;
+ int i, j, exp;
+
+ dw1 = dw2 = dw3 = 0;
+ ch = &str[0];
+
+ sprintf(str, "%.16e", fx80_to_double(fpr));
+
+ if (*ch == '-')
+ {
+ ch++;
+ dw1 = 0x80000000;
+ }
+
+ if (*ch == '+')
+ {
+ ch++;
+ }
+
+ dw1 |= (*ch++ - '0');
+
+ if (*ch == '.')
+ {
+ ch++;
+ }
+
+ // handle negative k-factor here
+ if ((k <= 0) && (k >= -13))
+ {
+ exp = 0;
+ for (i = 0; i < 3; i++)
+ {
+ if (ch[18+i] >= '0' && ch[18+i] <= '9')
+ {
+ exp = (exp << 4) | (ch[18+i] - '0');
+ }
+ }
+
+ if (ch[17] == '-')
+ {
+ exp = -exp;
+ }
+
+ k = -k;
+ // last digit is (k + exponent - 1)
+ k += (exp - 1);
+
+ // round up the last significant mantissa digit
+ if (ch[k+1] >= '5')
+ {
+ ch[k]++;
+ }
+
+ // zero out the rest of the mantissa digits
+ for (j = (k+1); j < 16; j++)
+ {
+ ch[j] = '0';
+ }
+
+ // now zero out K to avoid tripping the positive K detection below
+ k = 0;
+ }
+
+ // crack 8 digits of the mantissa
+ for (i = 0; i < 8; i++)
+ {
+ dw2 <<= 4;
+ if (*ch >= '0' && *ch <= '9')
+ {
+ dw2 |= *ch++ - '0';
+ }
+ }
+
+ // next 8 digits of the mantissa
+ for (i = 0; i < 8; i++)
+ {
+ dw3 <<= 4;
+ if (*ch >= '0' && *ch <= '9')
+ dw3 |= *ch++ - '0';
+ }
+
+ // handle masking if k is positive
+ if (k >= 1)
+ {
+ if (k <= 17)
+ {
+ dw2 &= pkmask2[k];
+ dw3 &= pkmask3[k];
+ }
+ else
+ {
+ dw2 &= pkmask2[17];
+ dw3 &= pkmask3[17];
+// m68k->fpcr |= (need to set OPERR bit)
+ }
+ }
+
+ // finally, crack the exponent
+ if (*ch == 'e' || *ch == 'E')
+ {
+ ch++;
+ if (*ch == '-')
+ {
+ ch++;
+ dw1 |= 0x40000000;
+ }
+
+ if (*ch == '+')
+ {
+ ch++;
+ }
+
+ j = 0;
+ for (i = 0; i < 3; i++)
+ {
+ if (*ch >= '0' && *ch <= '9')
+ {
+ j = (j << 4) | (*ch++ - '0');
+ }
+ }
+
+ dw1 |= (j << 16);
+ }
+
+ m68ki_write_32(m68k, ea, dw1);
+ m68ki_write_32(m68k, ea+4, dw2);
+ m68ki_write_32(m68k, ea+8, dw3);
+}
+
+INLINE void SET_CONDITION_CODES(m68ki_cpu_core *m68k, floatx80 reg)
+{
+// UINT64 *regi;
+
+// regi = (UINT64 *)&reg;
+
+ REG_FPSR &= ~(FPCC_N|FPCC_Z|FPCC_I|FPCC_NAN);
+
+ // sign flag
+ if (reg.high & 0x8000)
+ {
+ REG_FPSR |= FPCC_N;
+ }
+
+ // zero flag
+ if (((reg.high & 0x7fff) == 0) && ((reg.low<<1) == 0))
+ {
+ REG_FPSR |= FPCC_Z;
+ }
+
+ // infinity flag
+ if (((reg.high & 0x7fff) == 0x7fff) && ((reg.low<<1) == 0))
+ {
+ REG_FPSR |= FPCC_I;
+ }
+
+ // NaN flag
+ if (floatx80_is_nan(reg))
+ {
+ REG_FPSR |= FPCC_NAN;
+ }
+}
+
+INLINE int TEST_CONDITION(m68ki_cpu_core *m68k, int condition)
+{
+ int n = (REG_FPSR & FPCC_N) != 0;
+ int z = (REG_FPSR & FPCC_Z) != 0;
+ int nan = (REG_FPSR & FPCC_NAN) != 0;
+ int r = 0;
+ switch (condition)
+ {
+ case 0x10:
+ case 0x00: return 0; // False
+
+ case 0x11:
+ case 0x01: return (z); // Equal
+
+ case 0x12:
+ case 0x02: return (!(nan || z || n)); // Greater Than
+
+ case 0x13:
+ case 0x03: return (z || !(nan || n)); // Greater or Equal
+
+ case 0x14:
+ case 0x04: return (n && !(nan || z)); // Less Than
+
+ case 0x15:
+ case 0x05: return (z || (n && !nan)); // Less Than or Equal
+
+ case 0x16:
+ case 0x06: return !nan && !z;
+
+ case 0x17:
+ case 0x07: return !nan;
+
+ case 0x18:
+ case 0x08: return nan;
+
+ case 0x19:
+ case 0x09: return nan || z;
+
+ case 0x1a:
+ case 0x0a: return (nan || !(n || z)); // Not Less Than or Equal
+
+ case 0x1b:
+ case 0x0b: return (nan || z || !n); // Not Less Than
+
+ case 0x1c:
+ case 0x0c: return (nan || (n && !z)); // Not Greater or Equal Than
+
+ case 0x1d:
+ case 0x0d: return (nan || z || n); // Not Greater Than
+
+ case 0x1e:
+ case 0x0e: return (!z); // Not Equal
+
+ case 0x1f:
+ case 0x0f: return 1; // True
+
+ default: fatalerror("M68kFPU: test_condition: unhandled condition %02X\n", condition);
+ }
+
+ return r;
+}
+
+static UINT8 READ_EA_8(m68ki_cpu_core *m68k, int ea)
+{
+ int mode = (ea >> 3) & 0x7;
+ int reg = (ea & 0x7);
+
+ switch (mode)
+ {
+ case 0: // Dn
+ {
+ return REG_D[reg];
+ }
+ case 2: // (An)
+ {
+ UINT32 ea = REG_A[reg];
+ return m68ki_read_8(m68k, ea);
+ }
+ case 3: // (An)+
+ {
+ UINT32 ea = EA_AY_PI_8(m68k);
+ return m68ki_read_8(m68k, ea);
+ }
+ case 4: // -(An)
+ {
+ UINT32 ea = EA_AY_PD_8(m68k);
+ return m68ki_read_8(m68k, ea);
+ }
+ case 5: // (d16, An)
+ {
+ UINT32 ea = EA_AY_DI_8(m68k);
+ return m68ki_read_8(m68k, ea);
+ }
+ case 6: // (An) + (Xn) + d8
+ {
+ UINT32 ea = EA_AY_IX_8(m68k);
+ return m68ki_read_8(m68k, ea);
+ }
+ case 7:
+ {
+ switch (reg)
+ {
+ case 0: // (xxx).W
+ {
+ UINT32 ea = (UINT32)OPER_I_16(m68k);
+ return m68ki_read_8(m68k, ea);
+ }
+ case 1: // (xxx).L
+ {
+ UINT32 d1 = OPER_I_16(m68k);
+ UINT32 d2 = OPER_I_16(m68k);
+ UINT32 ea = (d1 << 16) | d2;
+ return m68ki_read_8(m68k, ea);
+ }
+ case 2: // (d16, PC)
+ {
+ UINT32 ea = EA_PCDI_8(m68k);
+ return m68ki_read_8(m68k, ea);
+ }
+ case 3: // (PC) + (Xn) + d8
+ {
+ UINT32 ea = EA_PCIX_8(m68k);
+ return m68ki_read_8(m68k, ea);
+ }
+ case 4: // #<data>
+ {
+ return OPER_I_8(m68k);
+ }
+ default: fatalerror("M68kFPU: READ_EA_8: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
+ }
+ break;
+ }
+ default: fatalerror("M68kFPU: READ_EA_8: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
+ }
+
+ return 0;
+}
+
+static UINT16 READ_EA_16(m68ki_cpu_core *m68k, int ea)
+{
+ int mode = (ea >> 3) & 0x7;
+ int reg = (ea & 0x7);
+
+ switch (mode)
+ {
+ case 0: // Dn
+ {
+ return (UINT16)(REG_D[reg]);
+ }
+ case 2: // (An)
+ {
+ UINT32 ea = REG_A[reg];
+ return m68ki_read_16(m68k, ea);
+ }
+ case 3: // (An)+
+ {
+ UINT32 ea = EA_AY_PI_16(m68k);
+ return m68ki_read_16(m68k, ea);
+ }
+ case 4: // -(An)
+ {
+ UINT32 ea = EA_AY_PD_16(m68k);
+ return m68ki_read_16(m68k, ea);
+ }
+ case 5: // (d16, An)
+ {
+ UINT32 ea = EA_AY_DI_16(m68k);
+ return m68ki_read_16(m68k, ea);
+ }
+ case 6: // (An) + (Xn) + d8
+ {
+ UINT32 ea = EA_AY_IX_16(m68k);
+ return m68ki_read_16(m68k, ea);
+ }
+ case 7:
+ {
+ switch (reg)
+ {
+ case 0: // (xxx).W
+ {
+ UINT32 ea = (UINT32)OPER_I_16(m68k);
+ return m68ki_read_16(m68k, ea);
+ }
+ case 1: // (xxx).L
+ {
+ UINT32 d1 = OPER_I_16(m68k);
+ UINT32 d2 = OPER_I_16(m68k);
+ UINT32 ea = (d1 << 16) | d2;
+ return m68ki_read_16(m68k, ea);
+ }
+ case 2: // (d16, PC)
+ {
+ UINT32 ea = EA_PCDI_16(m68k);
+ return m68ki_read_16(m68k, ea);
+ }
+ case 3: // (PC) + (Xn) + d8
+ {
+ UINT32 ea = EA_PCIX_16(m68k);
+ return m68ki_read_16(m68k, ea);
+ }
+ case 4: // #<data>
+ {
+ return OPER_I_16(m68k);
+ }
+
+ default: fatalerror("M68kFPU: READ_EA_16: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
+ }
+ break;
+ }
+ default: fatalerror("M68kFPU: READ_EA_16: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
+ }
+
+ return 0;
+}
+
+static UINT32 READ_EA_32(m68ki_cpu_core *m68k, int ea)
+{
+ int mode = (ea >> 3) & 0x7;
+ int reg = (ea & 0x7);
+
+ switch (mode)
+ {
+ case 0: // Dn
+ {
+ return REG_D[reg];
+ }
+ case 2: // (An)
+ {
+ UINT32 ea = REG_A[reg];
+ return m68ki_read_32(m68k, ea);
+ }
+ case 3: // (An)+
+ {
+ UINT32 ea = EA_AY_PI_32(m68k);
+ return m68ki_read_32(m68k, ea);
+ }
+ case 4: // -(An)
+ {
+ UINT32 ea = EA_AY_PD_32(m68k);
+ return m68ki_read_32(m68k, ea);
+ }
+ case 5: // (d16, An)
+ {
+ UINT32 ea = EA_AY_DI_32(m68k);
+ return m68ki_read_32(m68k, ea);
+ }
+ case 6: // (An) + (Xn) + d8
+ {
+ UINT32 ea = EA_AY_IX_32(m68k);
+ return m68ki_read_32(m68k, ea);
+ }
+ case 7:
+ {
+ switch (reg)
+ {
+ case 0: // (xxx).W
+ {
+ UINT32 ea = (UINT32)OPER_I_16(m68k);
+ return m68ki_read_32(m68k, ea);
+ }
+ case 1: // (xxx).L
+ {
+ UINT32 d1 = OPER_I_16(m68k);
+ UINT32 d2 = OPER_I_16(m68k);
+ UINT32 ea = (d1 << 16) | d2;
+ return m68ki_read_32(m68k, ea);
+ }
+ case 2: // (d16, PC)
+ {
+ UINT32 ea = EA_PCDI_32(m68k);
+ return m68ki_read_32(m68k, ea);
+ }
+ case 3: // (PC) + (Xn) + d8
+ {
+ UINT32 ea = EA_PCIX_32(m68k);
+ return m68ki_read_32(m68k, ea);
+ }
+ case 4: // #<data>
+ {
+ return OPER_I_32(m68k);
+ }
+ default: fatalerror("M68kFPU: READ_EA_32: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
+ }
+ break;
+ }
+ default: fatalerror("M68kFPU: READ_EA_32: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
+ }
+ return 0;
+}
+
+static UINT64 READ_EA_64(m68ki_cpu_core *m68k, int ea)
+{
+ int mode = (ea >> 3) & 0x7;
+ int reg = (ea & 0x7);
+ UINT32 h1, h2;
+
+ switch (mode)
+ {
+ case 2: // (An)
+ {
+ UINT32 ea = REG_A[reg];
+ h1 = m68ki_read_32(m68k, ea+0);
+ h2 = m68ki_read_32(m68k, ea+4);
+ return (UINT64)(h1) << 32 | (UINT64)(h2);
+ }
+ case 3: // (An)+
+ {
+ UINT32 ea = REG_A[reg];
+ REG_A[reg] += 8;
+ h1 = m68ki_read_32(m68k, ea+0);
+ h2 = m68ki_read_32(m68k, ea+4);
+ return (UINT64)(h1) << 32 | (UINT64)(h2);
+ }
+ case 4: // -(An)
+ {
+ UINT32 ea = REG_A[reg]-8;
+ REG_A[reg] -= 8;
+ h1 = m68ki_read_32(m68k, ea+0);
+ h2 = m68ki_read_32(m68k, ea+4);
+ return (UINT64)(h1) << 32 | (UINT64)(h2);
+ }
+ case 5: // (d16, An)
+ {
+ UINT32 ea = EA_AY_DI_32(m68k);
+ h1 = m68ki_read_32(m68k, ea+0);
+ h2 = m68ki_read_32(m68k, ea+4);
+ return (UINT64)(h1) << 32 | (UINT64)(h2);
+ }
+ case 6: // (An) + (Xn) + d8
+ {
+ UINT32 ea = EA_AY_IX_32(m68k);
+ h1 = m68ki_read_32(m68k, ea+0);
+ h2 = m68ki_read_32(m68k, ea+4);
+ return (UINT64)(h1) << 32 | (UINT64)(h2);
+ }
+ case 7:
+ {
+ switch (reg)
+ {
+ case 1: // (xxx).L
+ {
+ UINT32 d1 = OPER_I_16(m68k);
+ UINT32 d2 = OPER_I_16(m68k);
+ UINT32 ea = (d1 << 16) | d2;
+ return (UINT64)(m68ki_read_32(m68k, ea)) << 32 | (UINT64)(m68ki_read_32(m68k, ea+4));
+ }
+ case 3: // (PC) + (Xn) + d8
+ {
+ UINT32 ea = EA_PCIX_32(m68k);
+ h1 = m68ki_read_32(m68k, ea+0);
+ h2 = m68ki_read_32(m68k, ea+4);
+ return (UINT64)(h1) << 32 | (UINT64)(h2);
+ }
+ case 4: // #<data>
+ {
+ h1 = OPER_I_32(m68k);
+ h2 = OPER_I_32(m68k);
+ return (UINT64)(h1) << 32 | (UINT64)(h2);
+ }
+ case 2: // (d16, PC)
+ {
+ UINT32 ea = EA_PCDI_32(m68k);
+ h1 = m68ki_read_32(m68k, ea+0);
+ h2 = m68ki_read_32(m68k, ea+4);
+ return (UINT64)(h1) << 32 | (UINT64)(h2);
+ }
+ default: fatalerror("M68kFPU: READ_EA_64: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
+ }
+ break;
+ }
+ default: fatalerror("M68kFPU: READ_EA_64: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
+ }
+
+ return 0;
+}
+
+
+static floatx80 READ_EA_FPE(m68ki_cpu_core *m68k, int ea)
+{
+ floatx80 fpr;
+ int mode = (ea >> 3) & 0x7;
+ int reg = (ea & 0x7);
+
+ switch (mode)
+ {
+ case 2: // (An)
+ {
+ UINT32 ea = REG_A[reg];
+ fpr = load_extended_float80(m68k, ea);
+ break;
+ }
+
+ case 3: // (An)+
+ {
+ UINT32 ea = REG_A[reg];
+ REG_A[reg] += 12;
+ fpr = load_extended_float80(m68k, ea);
+ break;
+ }
+ case 4: // -(An)
+ {
+ UINT32 ea = REG_A[reg]-12;
+ REG_A[reg] -= 12;
+ fpr = load_extended_float80(m68k, ea);
+ break;
+ }
+ case 5: // (d16, An)
+ {
+ // FIXME: will fail for fmovem
+ UINT32 ea = EA_AY_DI_32(m68k);
+ fpr = load_extended_float80(m68k, ea);
+ break;
+ }
+ case 6: // (An) + (Xn) + d8
+ {
+ // FIXME: will fail for fmovem
+ UINT32 ea = EA_AY_IX_32(m68k);
+ fpr = load_extended_float80(m68k, ea);
+ break;
+ }
+
+ case 7: // extended modes
+ {
+ switch (reg)
+ {
+ case 2: // (d16, PC)
+ {
+ UINT32 ea = EA_PCDI_32(m68k);
+ fpr = load_extended_float80(m68k, ea);
+ }
+ break;
+
+ case 3: // (d16,PC,Dx.w)
+ {
+ UINT32 ea = EA_PCIX_32(m68k);
+ fpr = load_extended_float80(m68k, ea);
+ }
+ break;
+
+ default:
+ fatalerror("M68kFPU: READ_EA_FPE: unhandled mode %d, reg %d, at %08X\n", mode, reg, REG_PC);
+ break;
+ }
+ }
+ break;
+
+ default: fatalerror("M68kFPU: READ_EA_FPE: unhandled mode %d, reg %d, at %08X\n", mode, reg, REG_PC); break;
+ }
+
+ return fpr;
+}
+
+static floatx80 READ_EA_PACK(m68ki_cpu_core *m68k, int ea)
+{
+ floatx80 fpr;
+ int mode = (ea >> 3) & 0x7;
+ int reg = (ea & 0x7);
+
+ switch (mode)
+ {
+ case 2: // (An)
+ {
+ UINT32 ea = REG_A[reg];
+ fpr = load_pack_float80(m68k, ea);
+ break;
+ }
+
+ case 3: // (An)+
+ {
+ UINT32 ea = REG_A[reg];
+ REG_A[reg] += 12;
+ fpr = load_pack_float80(m68k, ea);
+ break;
+ }
+
+ case 7: // extended modes
+ {
+ switch (reg)
+ {
+ case 3: // (d16,PC,Dx.w)
+ {
+ UINT32 ea = EA_PCIX_32(m68k);
+ fpr = load_pack_float80(m68k, ea);
+ }
+ break;
+
+ default:
+ fatalerror("M68kFPU: READ_EA_PACK: unhandled mode %d, reg %d, at %08X\n", mode, reg, REG_PC);
+ break;
+ }
+ }
+ break;
+
+ default: fatalerror("M68kFPU: READ_EA_PACK: unhandled mode %d, reg %d, at %08X\n", mode, reg, REG_PC); break;
+ }
+
+ return fpr;
+}
+
+static void WRITE_EA_8(m68ki_cpu_core *m68k, int ea, UINT8 data)
+{
+ int mode = (ea >> 3) & 0x7;
+ int reg = (ea & 0x7);
+
+ switch (mode)
+ {
+ case 0: // Dn
+ {
+ REG_D[reg] = data;
+ break;
+ }
+ case 2: // (An)
+ {
+ UINT32 ea = REG_A[reg];
+ m68ki_write_8(m68k, ea, data);
+ break;
+ }
+ case 3: // (An)+
+ {
+ UINT32 ea = EA_AY_PI_8(m68k);
+ m68ki_write_8(m68k, ea, data);
+ break;
+ }
+ case 4: // -(An)
+ {
+ UINT32 ea = EA_AY_PD_8(m68k);
+ m68ki_write_8(m68k, ea, data);
+ break;
+ }
+ case 5: // (d16, An)
+ {
+ UINT32 ea = EA_AY_DI_8(m68k);
+ m68ki_write_8(m68k, ea, data);
+ break;
+ }
+ case 6: // (An) + (Xn) + d8
+ {
+ UINT32 ea = EA_AY_IX_8(m68k);
+ m68ki_write_8(m68k, ea, data);
+ break;
+ }
+ case 7:
+ {
+ switch (reg)
+ {
+ case 1: // (xxx).B
+ {
+ UINT32 d1 = OPER_I_16(m68k);
+ UINT32 d2 = OPER_I_16(m68k);
+ UINT32 ea = (d1 << 16) | d2;
+ m68ki_write_8(m68k, ea, data);
+ break;
+ }
+ case 2: // (d16, PC)
+ {
+ UINT32 ea = EA_PCDI_16(m68k);
+ m68ki_write_8(m68k, ea, data);
+ break;
+ }
+ default: fatalerror("M68kFPU: WRITE_EA_8: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
+ }
+ break;
+ }
+ default: fatalerror("M68kFPU: WRITE_EA_8: unhandled mode %d, reg %d, data %08X at %08X\n", mode, reg, data, REG_PC);
+ }
+}
+
+static void WRITE_EA_16(m68ki_cpu_core *m68k, int ea, UINT16 data)
+{
+ int mode = (ea >> 3) & 0x7;
+ int reg = (ea & 0x7);
+
+ switch (mode)
+ {
+ case 0: // Dn
+ {
+ REG_D[reg] = data;
+ break;
+ }
+ case 2: // (An)
+ {
+ UINT32 ea = REG_A[reg];
+ m68ki_write_16(m68k, ea, data);
+ break;
+ }
+ case 3: // (An)+
+ {
+ UINT32 ea = EA_AY_PI_16(m68k);
+ m68ki_write_16(m68k, ea, data);
+ break;
+ }
+ case 4: // -(An)
+ {
+ UINT32 ea = EA_AY_PD_16(m68k);
+ m68ki_write_16(m68k, ea, data);
+ break;
+ }
+ case 5: // (d16, An)
+ {
+ UINT32 ea = EA_AY_DI_16(m68k);
+ m68ki_write_16(m68k, ea, data);
+ break;
+ }
+ case 6: // (An) + (Xn) + d8
+ {
+ UINT32 ea = EA_AY_IX_16(m68k);
+ m68ki_write_16(m68k, ea, data);
+ break;
+ }
+ case 7:
+ {
+ switch (reg)
+ {
+ case 1: // (xxx).W
+ {
+ UINT32 d1 = OPER_I_16(m68k);
+ UINT32 d2 = OPER_I_16(m68k);
+ UINT32 ea = (d1 << 16) | d2;
+ m68ki_write_16(m68k, ea, data);
+ break;
+ }
+ case 2: // (d16, PC)
+ {
+ UINT32 ea = EA_PCDI_16(m68k);
+ m68ki_write_16(m68k, ea, data);
+ break;
+ }
+ default: fatalerror("M68kFPU: WRITE_EA_16: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
+ }
+ break;
+ }
+ default: fatalerror("M68kFPU: WRITE_EA_16: unhandled mode %d, reg %d, data %08X at %08X\n", mode, reg, data, REG_PC);
+ }
+}
+
+static void WRITE_EA_32(m68ki_cpu_core *m68k, int ea, UINT32 data)
+{
+ int mode = (ea >> 3) & 0x7;
+ int reg = (ea & 0x7);
+
+ switch (mode)
+ {
+ case 0: // Dn
+ {
+ REG_D[reg] = data;
+ break;
+ }
+ case 1: // An
+ {
+ REG_A[reg] = data;
+ break;
+ }
+ case 2: // (An)
+ {
+ UINT32 ea = REG_A[reg];
+ m68ki_write_32(m68k, ea, data);
+ break;
+ }
+ case 3: // (An)+
+ {
+ UINT32 ea = EA_AY_PI_32(m68k);
+ m68ki_write_32(m68k, ea, data);
+ break;
+ }
+ case 4: // -(An)
+ {
+ UINT32 ea = EA_AY_PD_32(m68k);
+ m68ki_write_32(m68k, ea, data);
+ break;
+ }
+ case 5: // (d16, An)
+ {
+ UINT32 ea = EA_AY_DI_32(m68k);
+ m68ki_write_32(m68k, ea, data);
+ break;
+ }
+ case 6: // (An) + (Xn) + d8
+ {
+ UINT32 ea = EA_AY_IX_32(m68k);
+ m68ki_write_32(m68k, ea, data);
+ break;
+ }
+ case 7:
+ {
+ switch (reg)
+ {
+ case 1: // (xxx).L
+ {
+ UINT32 d1 = OPER_I_16(m68k);
+ UINT32 d2 = OPER_I_16(m68k);
+ UINT32 ea = (d1 << 16) | d2;
+ m68ki_write_32(m68k, ea, data);
+ break;
+ }
+ case 2: // (d16, PC)
+ {
+ UINT32 ea = EA_PCDI_32(m68k);
+ m68ki_write_32(m68k, ea, data);
+ break;
+ }
+ default: fatalerror("M68kFPU: WRITE_EA_32: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
+ }
+ break;
+ }
+ default: fatalerror("M68kFPU: WRITE_EA_32: unhandled mode %d, reg %d, data %08X at %08X\n", mode, reg, data, REG_PC);
+ }
+}
+
+static void WRITE_EA_64(m68ki_cpu_core *m68k, int ea, UINT64 data)
+{
+ int mode = (ea >> 3) & 0x7;
+ int reg = (ea & 0x7);
+
+ switch (mode)
+ {
+ case 2: // (An)
+ {
+ UINT32 ea = REG_A[reg];
+ m68ki_write_32(m68k, ea, (UINT32)(data >> 32));
+ m68ki_write_32(m68k, ea+4, (UINT32)(data));
+ break;
+ }
+ case 3: // (An)+
+ {
+ UINT32 ea = REG_A[reg];
+ REG_A[reg] += 8;
+ m68ki_write_32(m68k, ea+0, (UINT32)(data >> 32));
+ m68ki_write_32(m68k, ea+4, (UINT32)(data));
+ break;
+ }
+ case 4: // -(An)
+ {
+ UINT32 ea;
+ REG_A[reg] -= 8;
+ ea = REG_A[reg];
+ m68ki_write_32(m68k, ea+0, (UINT32)(data >> 32));
+ m68ki_write_32(m68k, ea+4, (UINT32)(data));
+ break;
+ }
+ case 5: // (d16, An)
+ {
+ UINT32 ea = EA_AY_DI_32(m68k);
+ m68ki_write_32(m68k, ea+0, (UINT32)(data >> 32));
+ m68ki_write_32(m68k, ea+4, (UINT32)(data));
+ break;
+ }
+ case 6: // (An) + (Xn) + d8
+ {
+ UINT32 ea = EA_AY_IX_32(m68k);
+ m68ki_write_32(m68k, ea+0, (UINT32)(data >> 32));
+ m68ki_write_32(m68k, ea+4, (UINT32)(data));
+ break;
+ }
+ case 7:
+ {
+ switch (reg)
+ {
+ case 1: // (xxx).L
+ {
+ UINT32 d1 = OPER_I_16(m68k);
+ UINT32 d2 = OPER_I_16(m68k);
+ UINT32 ea = (d1 << 16) | d2;
+ m68ki_write_32(m68k, ea+0, (UINT32)(data >> 32));
+ m68ki_write_32(m68k, ea+4, (UINT32)(data));
+ break;
+ }
+ case 2: // (d16, PC)
+ {
+ UINT32 ea = EA_PCDI_32(m68k);
+ m68ki_write_32(m68k, ea+0, (UINT32)(data >> 32));
+ m68ki_write_32(m68k, ea+4, (UINT32)(data));
+ break;
+ }
+ default: fatalerror("M68kFPU: WRITE_EA_64: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
+ }
+ break;
+ }
+ default: fatalerror("M68kFPU: WRITE_EA_64: unhandled mode %d, reg %d, data %08X%08X at %08X\n", mode, reg, (UINT32)(data >> 32), (UINT32)(data), REG_PC);
+ }
+}
+
+static void WRITE_EA_FPE(m68ki_cpu_core *m68k, int ea, floatx80 fpr)
+{
+ int mode = (ea >> 3) & 0x7;
+ int reg = (ea & 0x7);
+
+ switch (mode)
+ {
+ case 2: // (An)
+ {
+ UINT32 ea;
+ ea = REG_A[reg];
+ store_extended_float80(m68k, ea, fpr);
+ break;
+ }
+
+ case 3: // (An)+
+ {
+ UINT32 ea;
+ ea = REG_A[reg];
+ store_extended_float80(m68k, ea, fpr);
+ REG_A[reg] += 12;
+ break;
+ }
+
+ case 4: // -(An)
+ {
+ UINT32 ea;
+ REG_A[reg] -= 12;
+ ea = REG_A[reg];
+ store_extended_float80(m68k, ea, fpr);
+ break;
+ }
+
+ case 7:
+ {
+ switch (reg)
+ {
+ default: fatalerror("M68kFPU: WRITE_EA_FPE: unhandled mode %d, reg %d, at %08X\n", mode, reg, REG_PC);
+ }
+ }
+ default: fatalerror("M68kFPU: WRITE_EA_FPE: unhandled mode %d, reg %d, at %08X\n", mode, reg, REG_PC);
+ }
+}
+
+static void WRITE_EA_PACK(m68ki_cpu_core *m68k, int ea, int k, floatx80 fpr)
+{
+ int mode = (ea >> 3) & 0x7;
+ int reg = (ea & 0x7);
+
+ switch (mode)
+ {
+ case 2: // (An)
+ {
+ UINT32 ea;
+ ea = REG_A[reg];
+ store_pack_float80(m68k, ea, k, fpr);
+ break;
+ }
+
+ case 3: // (An)+
+ {
+ UINT32 ea;
+ ea = REG_A[reg];
+ store_pack_float80(m68k, ea, k, fpr);
+ REG_A[reg] += 12;
+ break;
+ }
+
+ case 4: // -(An)
+ {
+ UINT32 ea;
+ REG_A[reg] -= 12;
+ ea = REG_A[reg];
+ store_pack_float80(m68k, ea, k, fpr);
+ break;
+ }
+
+ case 7:
+ {
+ switch (reg)
+ {
+ default: fatalerror("M68kFPU: WRITE_EA_PACK: unhandled mode %d, reg %d, at %08X\n", mode, reg, REG_PC);
+ }
+ }
+ default: fatalerror("M68kFPU: WRITE_EA_PACK: unhandled mode %d, reg %d, at %08X\n", mode, reg, REG_PC);
+ }
+}
+
+static void fpgen_rm_reg(m68ki_cpu_core *m68k, UINT16 w2)
+{
+ int ea = m68k->ir & 0x3f;
+ int rm = (w2 >> 14) & 0x1;
+ int src = (w2 >> 10) & 0x7;
+ int dst = (w2 >> 7) & 0x7;
+ int opmode = w2 & 0x7f;
+ floatx80 source;
+
+ // fmovecr #$f, fp0 f200 5c0f
+
+ if (rm)
+ {
+ switch (src)
+ {
+ case 0: // Long-Word Integer
+ {
+ INT32 d = READ_EA_32(m68k, ea);
+ source = int32_to_floatx80(d);
+ break;
+ }
+ case 1: // Single-precision Real
+ {
+ UINT32 d = READ_EA_32(m68k, ea);
+ source = float32_to_floatx80(d);
+ break;
+ }
+ case 2: // Extended-precision Real
+ {
+ source = READ_EA_FPE(m68k, ea);
+ break;
+ }
+ case 3: // Packed-decimal Real
+ {
+ source = READ_EA_PACK(m68k, ea);
+ break;
+ }
+ case 4: // Word Integer
+ {
+ INT16 d = READ_EA_16(m68k, ea);
+ source = int32_to_floatx80((INT32)d);
+ break;
+ }
+ case 5: // Double-precision Real
+ {
+ UINT64 d = READ_EA_64(m68k, ea);
+
+ source = float64_to_floatx80(d);
+ break;
+ }
+ case 6: // Byte Integer
+ {
+ INT8 d = READ_EA_8(m68k, ea);
+ source = int32_to_floatx80((INT32)d);
+ break;
+ }
+ case 7: // FMOVECR load from constant ROM
+ {
+ switch (w2 & 0x7f)
+ {
+ case 0x0: // Pi
+ source.high = 0x4000;
+ source.low = U64(0xc90fdaa22168c235);
+ break;
+
+ case 0xb: // log10(2)
+ source.high = 0x3ffd;
+ source.low = U64(0x9a209a84fbcff798);
+ break;
+
+ case 0xc: // e
+ source.high = 0x4000;
+ source.low = U64(0xadf85458a2bb4a9b);
+ break;
+
+ case 0xd: // log2(e)
+ source.high = 0x3fff;
+ source.low = U64(0xb8aa3b295c17f0bc);
+ break;
+
+ case 0xe: // log10(e)
+ source.high = 0x3ffd;
+ source.low = U64(0xde5bd8a937287195);
+ break;
+
+ case 0xf: // 0.0
+ source = int32_to_floatx80((INT32)0);
+ break;
+
+ case 0x30: // ln(2)
+ source.high = 0x3ffe;
+ source.low = U64(0xb17217f7d1cf79ac);
+ break;
+
+ case 0x31: // ln(10)
+ source.high = 0x4000;
+ source.low = U64(0x935d8dddaaa8ac17);
+ break;
+
+ case 0x32: // 1 (or 100? manuals are unclear, but 1 would make more sense)
+ source = int32_to_floatx80((INT32)1);
+ break;
+
+ case 0x33: // 10^1
+ source = int32_to_floatx80((INT32)10);
+ break;
+
+ case 0x34: // 10^2
+ source = int32_to_floatx80((INT32)10*10);
+ break;
+
+ default:
+ fatalerror("fmove_rm_reg: unknown constant ROM offset %x at %08x\n", w2&0x7f, REG_PC-4);
+ break;
+ }
+
+ // handle it right here, the usual opmode bits aren't valid in the FMOVECR case
+ REG_FP[dst] = source;
+ m68k->remaining_cycles -= 4;
+ return;
+ }
+ default: fatalerror("fmove_rm_reg: invalid source specifier %x at %08X\n", src, REG_PC-4);
+ }
+ }
+ else
+ {
+ source = REG_FP[src];
+ }
+
+
+
+ switch (opmode)
+ {
+ case 0x00: // FMOVE
+ {
+ REG_FP[dst] = source;
+ SET_CONDITION_CODES(m68k, REG_FP[dst]);
+ m68k->remaining_cycles -= 4;
+ break;
+ }
+ case 0x01: // FINT
+ {
+ INT32 temp;
+ temp = floatx80_to_int32(source);
+ REG_FP[dst] = int32_to_floatx80(temp);
+ break;
+ }
+ case 0x03: // FINTRZ
+ {
+ INT32 temp;
+ temp = floatx80_to_int32_round_to_zero(source);
+ REG_FP[dst] = int32_to_floatx80(temp);
+ break;
+ }
+ case 0x04: // FSQRT
+ {
+ REG_FP[dst] = floatx80_sqrt(source);
+ SET_CONDITION_CODES(m68k, REG_FP[dst]);
+ m68k->remaining_cycles -= 109;
+ break;
+ }
+ case 0x0e: // FSIN
+ {
+ REG_FP[dst] = source;
+ floatx80_fsin(REG_FP[dst]);
+ SET_CONDITION_CODES(m68k, REG_FP[dst]);
+ m68k->remaining_cycles -= 75;
+ break;
+ }
+ case 0x0f: // FTAN
+ {
+ REG_FP[dst] = source;
+ floatx80_ftan(REG_FP[dst]);
+ SET_CONDITION_CODES(m68k, REG_FP[dst]);
+ m68k->remaining_cycles -= 75;
+ break;
+ }
+ case 0x18: // FABS
+ {
+ REG_FP[dst] = source;
+ REG_FP[dst].high &= 0x7fff;
+ SET_CONDITION_CODES(m68k, REG_FP[dst]);
+ m68k->remaining_cycles -= 3;
+ break;
+ }
+ case 0x1a: // FNEG
+ {
+ REG_FP[dst] = source;
+ REG_FP[dst].high ^= 0x8000;
+ SET_CONDITION_CODES(m68k, REG_FP[dst]);
+ m68k->remaining_cycles -= 3;
+ break;
+ }
+ case 0x1d: // FCOS
+ {
+ REG_FP[dst] = source;
+ floatx80_fcos(REG_FP[dst]);
+ SET_CONDITION_CODES(m68k, REG_FP[dst]);
+ m68k->remaining_cycles -= 75;
+ break;
+ }
+ case 0x1e: // FGETEXP
+ {
+ INT16 temp2;
+
+ temp2 = source.high; // get the exponent
+ temp2 -= 0x3fff; // take off the bias
+ REG_FP[dst] = double_to_fx80((double)temp2);
+ SET_CONDITION_CODES(m68k, REG_FP[dst]);
+ m68k->remaining_cycles -= 6;
+ }
+ case 0x20: // FDIV
+ {
+ REG_FP[dst] = floatx80_div(REG_FP[dst], source);
+ m68k->remaining_cycles -= 43;
+ break;
+ }
+ case 0x22: // FADD
+ {
+ REG_FP[dst] = floatx80_add(REG_FP[dst], source);
+ SET_CONDITION_CODES(m68k, REG_FP[dst]);
+ m68k->remaining_cycles -= 9;
+ break;
+ }
+ case 0x23: // FMUL
+ {
+ REG_FP[dst] = floatx80_mul(REG_FP[dst], source);
+ SET_CONDITION_CODES(m68k, REG_FP[dst]);
+ m68k->remaining_cycles -= 11;
+ break;
+ }
+ case 0x24: // FSGLDIV
+ {
+ REG_FP[dst] = floatx80_div(REG_FP[dst], source);
+ m68k->remaining_cycles -= 43; // // ? (value is from FDIV)
+ break;
+ }
+ case 0x25: // FREM
+ {
+ REG_FP[dst] = floatx80_rem(REG_FP[dst], source);
+ SET_CONDITION_CODES(m68k, REG_FP[dst]);
+ m68k->remaining_cycles -= 43; // guess
+ break;
+ }
+ case 0x27: // FSGLMUL
+ {
+ REG_FP[dst] = floatx80_mul(REG_FP[dst], source);
+ SET_CONDITION_CODES(m68k, REG_FP[dst]);
+ m68k->remaining_cycles -= 11; // ? (value is from FMUL)
+ break;
+ }
+ case 0x28: // FSUB
+ {
+ REG_FP[dst] = floatx80_sub(REG_FP[dst], source);
+ SET_CONDITION_CODES(m68k, REG_FP[dst]);
+ m68k->remaining_cycles -= 9;
+ break;
+ }
+ case 0x38: // FCMP
+ {
+ floatx80 res;
+ res = floatx80_sub(REG_FP[dst], source);
+ SET_CONDITION_CODES(m68k, res);
+ m68k->remaining_cycles -= 7;
+ break;
+ }
+ case 0x3a: // FTST
+ {
+ floatx80 res;
+ res = source;
+ SET_CONDITION_CODES(m68k, res);
+ m68k->remaining_cycles -= 7;
+ break;
+ }
+
+ default: fatalerror("fpgen_rm_reg: unimplemented opmode %02X at %08X\n", opmode, REG_PPC);
+ }
+}
+
+static void fmove_reg_mem(m68ki_cpu_core *m68k, UINT16 w2)
+{
+ int ea = m68k->ir & 0x3f;
+ int src = (w2 >> 7) & 0x7;
+ int dst = (w2 >> 10) & 0x7;
+ int k = (w2 & 0x7f);
+
+ switch (dst)
+ {
+ case 0: // Long-Word Integer
+ {
+ INT32 d = (INT32)floatx80_to_int32(REG_FP[src]);
+ WRITE_EA_32(m68k, ea, d);
+ break;
+ }
+ case 1: // Single-precision Real
+ {
+ UINT32 d = floatx80_to_float32(REG_FP[src]);
+ WRITE_EA_32(m68k, ea, d);
+ break;
+ }
+ case 2: // Extended-precision Real
+ {
+ WRITE_EA_FPE(m68k, ea, REG_FP[src]);
+ break;
+ }
+ case 3: // Packed-decimal Real with Static K-factor
+ {
+ // sign-extend k
+ k = (k & 0x40) ? (k | 0xffffff80) : (k & 0x7f);
+ WRITE_EA_PACK(m68k, ea, k, REG_FP[src]);
+ break;
+ }
+ case 4: // Word Integer
+ {
+ WRITE_EA_16(m68k, ea, (INT16)floatx80_to_int32(REG_FP[src]));
+ break;
+ }
+ case 5: // Double-precision Real
+ {
+ UINT64 d;
+
+ d = floatx80_to_float64(REG_FP[src]);
+
+ WRITE_EA_64(m68k, ea, d);
+ break;
+ }
+ case 6: // Byte Integer
+ {
+ WRITE_EA_8(m68k, ea, (INT8)floatx80_to_int32(REG_FP[src]));
+ break;
+ }
+ case 7: // Packed-decimal Real with Dynamic K-factor
+ {
+ WRITE_EA_PACK(m68k, ea, REG_D[k>>4], REG_FP[src]);
+ break;
+ }
+ }
+
+ m68k->remaining_cycles -= 12;
+}
+
+static void fmove_fpcr(m68ki_cpu_core *m68k, UINT16 w2)
+{
+ int ea = m68k->ir & 0x3f;
+ int dir = (w2 >> 13) & 0x1;
+ int regsel = (w2 >> 10) & 0x7;
+ int mode = (ea >> 3) & 0x7;
+
+ if ((mode == 5) || (mode == 6))
+ {
+ UINT32 address = 0xffffffff; // force a bus error if this doesn't get assigned
+
+ if (mode == 5)
+ {
+ address = EA_AY_DI_32(m68k);
+ }
+ else if (mode == 6)
+ {
+ address = EA_AY_IX_32(m68k);
+ }
+
+ if (dir) // From system control reg to <ea>
+ {
+ if (regsel & 4) { m68ki_write_32(m68k, address, REG_FPCR); address += 4; }
+ if (regsel & 2) { m68ki_write_32(m68k, address, REG_FPSR); address += 4; }
+ if (regsel & 1) { m68ki_write_32(m68k, address, REG_FPIAR); address += 4; }
+ }
+ else // From <ea> to system control reg
+ {
+ if (regsel & 4) { REG_FPCR = m68ki_read_32(m68k, address); address += 4; }
+ if (regsel & 2) { REG_FPSR = m68ki_read_32(m68k, address); address += 4; }
+ if (regsel & 1) { REG_FPIAR = m68ki_read_32(m68k, address); address += 4; }
+ }
+ }
+ else
+ {
+ if (dir) // From system control reg to <ea>
+ {
+ if (regsel & 4) WRITE_EA_32(m68k, ea, REG_FPCR);
+ if (regsel & 2) WRITE_EA_32(m68k, ea, REG_FPSR);
+ if (regsel & 1) WRITE_EA_32(m68k, ea, REG_FPIAR);
+ }
+ else // From <ea> to system control reg
+ {
+ if (regsel & 4) REG_FPCR = READ_EA_32(m68k, ea);
+ if (regsel & 2) REG_FPSR = READ_EA_32(m68k, ea);
+ if (regsel & 1) REG_FPIAR = READ_EA_32(m68k, ea);
+ }
+ }
+
+ m68k->remaining_cycles -= 10;
+}
+
+static void fmovem(m68ki_cpu_core *m68k, UINT16 w2)
+{
+ int i;
+ int ea = m68k->ir & 0x3f;
+ int dir = (w2 >> 13) & 0x1;
+ int mode = (w2 >> 11) & 0x3;
+ int reglist = w2 & 0xff;
+
+ UINT32 mem_addr = 0;
+ switch (ea >> 3)
+ {
+ case 5: // (d16, An)
+ mem_addr= EA_AY_DI_32(m68k);
+ break;
+ case 6: // (An) + (Xn) + d8
+ mem_addr= EA_AY_IX_32(m68k);
+ break;
+ }
+
+ if (dir) // From FP regs to mem
+ {
+ switch (mode)
+ {
+ case 1: // Dynamic register list, postincrement or control addressing mode.
+ // FIXME: not really tested, but seems to work
+ reglist = REG_D[(reglist >> 4) & 7];
+
+ case 0: // Static register list, predecrement or control addressing mode
+ {
+ for (i=0; i < 8; i++)
+ {
+ if (reglist & (1 << i))
+ {
+ switch (ea >> 3)
+ {
+ case 5: // (d16, An)
+ case 6: // (An) + (Xn) + d8
+ store_extended_float80(m68k, mem_addr, REG_FP[i]);
+ mem_addr += 12;
+ break;
+ default:
+ WRITE_EA_FPE(m68k, ea, REG_FP[i]);
+ break;
+ }
+
+ m68k->remaining_cycles -= 2;
+ }
+ }
+ break;
+ }
+
+ case 2: // Static register list, postdecrement or control addressing mode
+ {
+ for (i=0; i < 8; i++)
+ {
+ if (reglist & (1 << i))
+ {
+ switch (ea >> 3)
+ {
+ case 5: // (d16, An)
+ case 6: // (An) + (Xn) + d8
+ store_extended_float80(m68k, mem_addr, REG_FP[7-i]);
+ mem_addr += 12;
+ break;
+ default:
+ WRITE_EA_FPE(m68k, ea, REG_FP[7-i]);
+ break;
+ }
+
+ m68k->remaining_cycles -= 2;
+ }
+ }
+ break;
+ }
+
+ default: fatalerror("M680x0: FMOVEM: mode %d unimplemented at %08X\n", mode, REG_PC-4);
+ }
+ }
+ else // From mem to FP regs
+ {
+ switch (mode)
+ {
+ case 3: // Dynamic register list, predecrement addressing mode.
+ // FIXME: not really tested, but seems to work
+ reglist = REG_D[(reglist >> 4) & 7];
+
+ case 2: // Static register list, postincrement or control addressing mode
+ {
+ for (i=0; i < 8; i++)
+ {
+ if (reglist & (1 << i))
+ {
+ switch (ea >> 3)
+ {
+ case 5: // (d16, An)
+ case 6: // (An) + (Xn) + d8
+ REG_FP[7-i] = load_extended_float80(m68k, mem_addr);
+ mem_addr += 12;
+ break;
+ default:
+ REG_FP[7-i] = READ_EA_FPE(m68k, ea);
+ break;
+ }
+ m68k->remaining_cycles -= 2;
+ }
+ }
+ break;
+ }
+
+ default: fatalerror("M680x0: FMOVEM: mode %d unimplemented at %08X\n", mode, REG_PC-4);
+ }
+ }
+}
+
+static void fscc(m68ki_cpu_core *m68k)
+{
+ int ea = m68k->ir & 0x3f;
+ int condition = (INT16)(OPER_I_16(m68k));
+
+ WRITE_EA_8(m68k, ea, TEST_CONDITION(m68k, condition) ? 0xff : 0);
+ m68k->remaining_cycles -= 7; // ???
+}
+
+static void fbcc16(m68ki_cpu_core *m68k)
+{
+ INT32 offset;
+ int condition = m68k->ir & 0x3f;
+
+ offset = (INT16)(OPER_I_16(m68k));
+
+ // TODO: condition and jump!!!
+ if (TEST_CONDITION(m68k, condition))
+ {
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ m68ki_branch_16(m68k, offset-2);
+ }
+
+ m68k->remaining_cycles -= 7;
+}
+
+static void fbcc32(m68ki_cpu_core *m68k)
+{
+ INT32 offset;
+ int condition = m68k->ir & 0x3f;
+
+ offset = OPER_I_32(m68k);
+
+ // TODO: condition and jump!!!
+ if (TEST_CONDITION(m68k, condition))
+ {
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ m68ki_branch_32(m68k, offset-4);
+ }
+
+ m68k->remaining_cycles -= 7;
+}
+
+
+void m68040_fpu_op0(m68ki_cpu_core *m68k)
+{
+ m68k->fpu_just_reset = 0;
+
+ switch ((m68k->ir >> 6) & 0x3)
+ {
+ case 0:
+ {
+ UINT16 w2 = OPER_I_16(m68k);
+ switch ((w2 >> 13) & 0x7)
+ {
+ case 0x0: // FPU ALU FP, FP
+ case 0x2: // FPU ALU ea, FP
+ {
+ fpgen_rm_reg(m68k, w2);
+ break;
+ }
+
+ case 0x3: // FMOVE FP, ea
+ {
+ fmove_reg_mem(m68k, w2);
+ break;
+ }
+
+ case 0x4: // FMOVEM ea, FPCR
+ case 0x5: // FMOVEM FPCR, ea
+ {
+ fmove_fpcr(m68k, w2);
+ break;
+ }
+
+ case 0x6: // FMOVEM ea, list
+ case 0x7: // FMOVEM list, ea
+ {
+ fmovem(m68k, w2);
+ break;
+ }
+
+ default: fatalerror("M68kFPU: unimplemented subop %d at %08X\n", (w2 >> 13) & 0x7, REG_PC-4);
+ }
+ break;
+ }
+
+ case 1: // FBcc disp16
+ {
+ switch ((m68k->ir >> 3) & 0x7) {
+ case 1: // FDBcc
+ // TODO:
+ break;
+ default: // FScc (?)
+ fscc(m68k);
+ return;
+ }
+ fatalerror("M68kFPU: unimplemented main op %d with mode %d at %08X\n", (m68k->ir >> 6) & 0x3, (m68k->ir >> 3) & 0x7, REG_PPC);
+ }
+
+ case 2: // FBcc disp16
+ {
+ fbcc16(m68k);
+ break;
+ }
+ case 3: // FBcc disp32
+ {
+ fbcc32(m68k);
+ break;
+ }
+
+ default: fatalerror("M68kFPU: unimplemented main op %d\n", (m68k->ir >> 6) & 0x3);
+ }
+}
+
+static void perform_fsave(m68ki_cpu_core *m68k, UINT32 addr, int inc)
+{
+ if (inc)
+ {
+ // 68881 IDLE, version 0x1f
+ m68ki_write_32(m68k, addr, 0x1f180000);
+ m68ki_write_32(m68k, addr+4, 0);
+ m68ki_write_32(m68k, addr+8, 0);
+ m68ki_write_32(m68k, addr+12, 0);
+ m68ki_write_32(m68k, addr+16, 0);
+ m68ki_write_32(m68k, addr+20, 0);
+ m68ki_write_32(m68k, addr+24, 0x70000000);
+ }
+ else
+ {
+ m68ki_write_32(m68k, addr, 0x70000000);
+ m68ki_write_32(m68k, addr-4, 0);
+ m68ki_write_32(m68k, addr-8, 0);
+ m68ki_write_32(m68k, addr-12, 0);
+ m68ki_write_32(m68k, addr-16, 0);
+ m68ki_write_32(m68k, addr-20, 0);
+ m68ki_write_32(m68k, addr-24, 0x1f180000);
+ }
+}
+
+// FRESTORE on a NULL frame reboots the FPU - all registers to NaN, the 3 status regs to 0
+static void do_frestore_null(m68ki_cpu_core *m68k)
+{
+ int i;
+
+ REG_FPCR = 0;
+ REG_FPSR = 0;
+ REG_FPIAR = 0;
+ for (i = 0; i < 8; i++)
+ {
+ REG_FP[i].high = 0x7fff;
+ REG_FP[i].low = U64(0xffffffffffffffff);
+ }
+
+ // Mac IIci at 408458e6 wants an FSAVE of a just-restored NULL frame to also be NULL
+ // The PRM says it's possible to generate a NULL frame, but not how/when/why. (need the 68881/68882 manual!)
+ m68k->fpu_just_reset = 1;
+}
+
+void m68040_fpu_op1(m68ki_cpu_core *m68k)
+{
+ int ea = m68k->ir & 0x3f;
+ int mode = (ea >> 3) & 0x7;
+ int reg = (ea & 0x7);
+ UINT32 addr, temp;
+
+ switch ((m68k->ir >> 6) & 0x3)
+ {
+ case 0: // FSAVE <ea>
+ {
+ switch (mode)
+ {
+ case 2: // (An)
+ addr = REG_A[reg];
+
+ if (m68k->fpu_just_reset)
+ {
+ m68ki_write_32(m68k, addr, 0);
+ }
+ else
+ {
+ // we normally generate an IDLE frame
+ perform_fsave(m68k, addr, 1);
+ }
+ break;
+
+ case 3: // (An)+
+ addr = EA_AY_PI_32(m68k);
+
+ if (m68k->fpu_just_reset)
+ {
+ m68ki_write_32(m68k, addr, 0);
+ }
+ else
+ {
+ // we normally generate an IDLE frame
+ REG_A[reg] += 6*4;
+ perform_fsave(m68k, addr, 1);
+ }
+ break;
+
+ case 4: // -(An)
+ addr = EA_AY_PD_32(m68k);
+
+ if (m68k->fpu_just_reset)
+ {
+ m68ki_write_32(m68k, addr, 0);
+ }
+ else
+ {
+ // we normally generate an IDLE frame
+ REG_A[reg] -= 6*4;
+ perform_fsave(m68k, addr, 0);
+ }
+ break;
+
+ default:
+ fatalerror("M68kFPU: FSAVE unhandled mode %d reg %d at %x\n", mode, reg, REG_PC);
+ }
+ break;
+ }
+ break;
+
+ case 1: // FRESTORE <ea>
+ {
+ switch (mode)
+ {
+ case 2: // (An)
+ addr = REG_A[reg];
+ temp = m68ki_read_32(m68k, addr);
+
+ // check for NULL frame
+ if (temp & 0xff000000)
+ {
+ // we don't handle non-NULL frames and there's no pre/post inc/dec to do here
+ m68k->fpu_just_reset = 0;
+ }
+ else
+ {
+ do_frestore_null(m68k);
+ }
+ break;
+
+ case 3: // (An)+
+ addr = EA_AY_PI_32(m68k);
+ temp = m68ki_read_32(m68k, addr);
+
+ // check for NULL frame
+ if (temp & 0xff000000)
+ {
+ m68k->fpu_just_reset = 0;
+
+ // how about an IDLE frame?
+ if ((temp & 0x00ff0000) == 0x00180000)
+ {
+ REG_A[reg] += 6*4;
+ } // check UNIMP
+ else if ((temp & 0x00ff0000) == 0x00380000)
+ {
+ REG_A[reg] += 14*4;
+ } // check BUSY
+ else if ((temp & 0x00ff0000) == 0x00b40000)
+ {
+ REG_A[reg] += 45*4;
+ }
+ }
+ else
+ {
+ do_frestore_null(m68k);
+ }
+ break;
+
+ case 5: // (D16, An)
+ addr = EA_AY_DI_16(m68k);
+ temp = m68ki_read_32(m68k, addr);
+
+ // check for NULL frame
+ if (temp & 0xff000000)
+ {
+ // we don't handle non-NULL frames and there's no pre/post inc/dec to do here
+ m68k->fpu_just_reset = 0;
+ }
+ else
+ {
+ do_frestore_null(m68k);
+ }
+ break;
+
+ case 7: //
+ switch (reg)
+ {
+ case 2: // (d16, PC)
+ {
+ addr = EA_PCDI_16(m68k);;
+ temp = m68ki_read_32(m68k, addr);
+
+ // check for NULL frame
+ if (temp & 0xff000000)
+ {
+ // we don't handle non-NULL frames and there's no pre/post inc/dec to do here
+ m68k->fpu_just_reset = 0;
+ }
+ else
+ {
+ do_frestore_null(m68k);
+ }
+ break;
+ }
+ default:
+ fatalerror("M68kFPU: FRESTORE unhandled mode %d reg %d at %x\n", mode, reg, REG_PC);
+ }
+
+ break;
+
+ default:
+ fatalerror("M68kFPU: FRESTORE unhandled mode %d reg %d at %x\n", mode, reg, REG_PC);
+ }
+ break;
+ }
+ break;
+
+ default: fatalerror("m68040_fpu_op1: unimplemented op %d at %08X\n", (m68k->ir >> 6) & 0x3, REG_PC-2);
+ }
+}
+
+
+