summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/cpu/m68000/m68kfpu.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/cpu/m68000/m68kfpu.c')
-rw-r--r--src/emu/cpu/m68000/m68kfpu.c828
1 files changed, 828 insertions, 0 deletions
diff --git a/src/emu/cpu/m68000/m68kfpu.c b/src/emu/cpu/m68000/m68kfpu.c
new file mode 100644
index 00000000000..c5ca30bb14a
--- /dev/null
+++ b/src/emu/cpu/m68000/m68kfpu.c
@@ -0,0 +1,828 @@
+#include "cpuintrf.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)
+
+INLINE void SET_CONDITION_CODES(fp_reg reg)
+{
+ REG_FPSR &= ~(FPCC_N|FPCC_Z|FPCC_I|FPCC_NAN);
+
+ // sign flag
+ if (reg.i & U64(0x8000000000000000))
+ {
+ REG_FPSR |= FPCC_N;
+ }
+
+ // zero flag
+ if ((reg.i & U64(0x7fffffffffffffff)) == 0)
+ {
+ REG_FPSR |= FPCC_Z;
+ }
+
+ // infinity flag
+ if ((reg.i & U64(0x7fffffffffffffff)) == DOUBLE_INFINITY)
+ {
+ REG_FPSR |= FPCC_I;
+ }
+
+ // NaN flag
+ if (((reg.i & DOUBLE_EXPONENT) == DOUBLE_EXPONENT) && ((reg.i & DOUBLE_MANTISSA) != 0))
+ {
+ REG_FPSR |= FPCC_NAN;
+ }
+}
+
+INLINE int TEST_CONDITION(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 0x00: return 0; // False
+ case 0x01: return (z); // Equal
+ case 0x0e: return (!z); // Not Equal
+ case 0x0f: return 1; // True
+ case 0x12: return (!(nan || z || n)); // Greater Than
+ case 0x13: return (z || !(nan || n)); // Greater or Equal
+ case 0x14: return (n && !(nan || z)); // Less Than
+ case 0x15: return (z || (n && !nan)); // Less Than or Equal
+ case 0x1a: return (nan || !(n || z)); // Not Less Than or Equal
+ case 0x1b: return (nan || z || !n); // Not Less Than
+ case 0x1c: return (nan || (n && !z)); // Not Greater or Equal Than
+ case 0x1d: return (nan || z || n); // Not Greater Than
+
+ default: fatalerror("M68040: test_condition: unhandled condition %02X\n", condition);
+ }
+
+ return r;
+}
+
+static UINT8 READ_EA_8(int ea)
+{
+ int mode = (ea >> 3) & 0x7;
+ int reg = (ea & 0x7);
+
+ switch (mode)
+ {
+ case 0: // Dn
+ {
+ return REG_D[reg];
+ }
+ case 5: // (d16, An)
+ {
+ UINT32 ea = EA_AY_DI_8();
+ return m68ki_read_8(ea);
+ }
+ case 6: // (An) + (Xn) + d8
+ {
+ UINT32 ea = EA_AY_IX_8();
+ return m68ki_read_8(ea);
+ }
+ case 7:
+ {
+ switch (reg)
+ {
+ case 1: // (xxx).L
+ {
+ UINT32 d1 = OPER_I_16();
+ UINT32 d2 = OPER_I_16();
+ UINT32 ea = (d1 << 16) | d2;
+ return m68ki_read_8(ea);
+ }
+ case 4: // #<data>
+ {
+ return OPER_I_8();
+ }
+ default: fatalerror("MC68040: READ_EA_8: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
+ }
+ break;
+ }
+ default: fatalerror("MC68040: READ_EA_8: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
+ }
+
+ return 0;
+}
+
+static UINT16 READ_EA_16(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(ea);
+ }
+ case 5: // (d16, An)
+ {
+ UINT32 ea = EA_AY_DI_16();
+ return m68ki_read_16(ea);
+ }
+ case 6: // (An) + (Xn) + d8
+ {
+ UINT32 ea = EA_AY_IX_16();
+ return m68ki_read_16(ea);
+ }
+ case 7:
+ {
+ switch (reg)
+ {
+ case 1: // (xxx).L
+ {
+ UINT32 d1 = OPER_I_16();
+ UINT32 d2 = OPER_I_16();
+ UINT32 ea = (d1 << 16) | d2;
+ return m68ki_read_16(ea);
+ }
+ case 4: // #<data>
+ {
+ return OPER_I_16();
+ }
+
+ default: fatalerror("MC68040: READ_EA_16: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
+ }
+ break;
+ }
+ default: fatalerror("MC68040: READ_EA_16: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
+ }
+
+ return 0;
+}
+
+static UINT32 READ_EA_32(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(ea);
+ }
+ case 3: // (An)+
+ {
+ UINT32 ea = EA_AY_PI_32();
+ return m68ki_read_32(ea);
+ }
+ case 5: // (d16, An)
+ {
+ UINT32 ea = EA_AY_DI_32();
+ return m68ki_read_32(ea);
+ }
+ case 6: // (An) + (Xn) + d8
+ {
+ UINT32 ea = EA_AY_IX_32();
+ return m68ki_read_32(ea);
+ }
+ case 7:
+ {
+ switch (reg)
+ {
+ case 1: // (xxx).L
+ {
+ UINT32 d1 = OPER_I_16();
+ UINT32 d2 = OPER_I_16();
+ UINT32 ea = (d1 << 16) | d2;
+ return m68ki_read_32(ea);
+ }
+ case 2: // (d16, PC)
+ {
+ UINT32 ea = EA_PCDI_32();
+ return m68ki_read_32(ea);
+ }
+ case 4: // #<data>
+ {
+ return OPER_I_32();
+ }
+ default: fatalerror("MC68040: READ_EA_32: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
+ }
+ break;
+ }
+ default: fatalerror("MC68040: READ_EA_32: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
+ }
+ return 0;
+}
+
+static void WRITE_EA_32(int ea, UINT32 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_32(ea, data);
+ break;
+ }
+ case 3: // (An)+
+ {
+ UINT32 ea = EA_AY_PI_32();
+ m68ki_write_32(ea, data);
+ break;
+ }
+ case 4: // -(An)
+ {
+ UINT32 ea = EA_AY_PD_32();
+ m68ki_write_32(ea, data);
+ break;
+ }
+ case 5: // (d16, An)
+ {
+ UINT32 ea = EA_AY_DI_32();
+ m68ki_write_32(ea, data);
+ break;
+ }
+ case 6: // (An) + (Xn) + d8
+ {
+ UINT32 ea = EA_AY_IX_32();
+ m68ki_write_32(ea, data);
+ break;
+ }
+ case 7:
+ {
+ switch (reg)
+ {
+ case 1: // (xxx).L
+ {
+ UINT32 d1 = OPER_I_16();
+ UINT32 d2 = OPER_I_16();
+ UINT32 ea = (d1 << 16) | d2;
+ m68ki_write_32(ea, data);
+ break;
+ }
+ case 2: // (d16, PC)
+ {
+ UINT32 ea = EA_PCDI_32();
+ m68ki_write_32(ea, data);
+ break;
+ }
+ default: fatalerror("MC68040: WRITE_EA_32: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
+ }
+ break;
+ }
+ default: fatalerror("MC68040: WRITE_EA_32: unhandled mode %d, reg %d, data %08X at %08X\n", mode, reg, data, REG_PC);
+ }
+}
+
+static UINT64 READ_EA_64(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(ea+0);
+ h2 = m68ki_read_32(ea+4);
+ return (UINT64)(h1) << 32 | (UINT64)(h2);
+ }
+ case 3: // (An)+
+ {
+ UINT32 ea = REG_A[reg];
+ REG_A[reg] += 8;
+ h1 = m68ki_read_32(ea+0);
+ h2 = m68ki_read_32(ea+4);
+ return (UINT64)(h1) << 32 | (UINT64)(h2);
+ }
+ case 5: // (d16, An)
+ {
+ UINT32 ea = EA_AY_DI_32();
+ h1 = m68ki_read_32(ea+0);
+ h2 = m68ki_read_32(ea+4);
+ return (UINT64)(h1) << 32 | (UINT64)(h2);
+ }
+ case 7:
+ {
+ switch (reg)
+ {
+ case 4: // #<data>
+ {
+ h1 = OPER_I_32();
+ h2 = OPER_I_32();
+ return (UINT64)(h1) << 32 | (UINT64)(h2);
+ }
+ case 2: // (d16, PC)
+ {
+ UINT32 ea = EA_PCDI_32();
+ h1 = m68ki_read_32(ea+0);
+ h2 = m68ki_read_32(ea+4);
+ return (UINT64)(h1) << 32 | (UINT64)(h2);
+ }
+ default: fatalerror("MC68040: READ_EA_64: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
+ }
+ break;
+ }
+ default: fatalerror("MC68040: READ_EA_64: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
+ }
+
+ return 0;
+}
+
+static void WRITE_EA_64(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(ea, (UINT32)(data >> 32));
+ m68ki_write_32(ea, (UINT32)(data));
+ break;
+ }
+ case 4: // -(An)
+ {
+ UINT32 ea;
+ REG_A[reg] -= 8;
+ ea = REG_A[reg];
+ m68ki_write_32(ea+0, (UINT32)(data >> 32));
+ m68ki_write_32(ea+4, (UINT32)(data));
+ break;
+ }
+ case 5: // (d16, An)
+ {
+ UINT32 ea = EA_AY_DI_32();
+ m68ki_write_32(ea+0, (UINT32)(data >> 32));
+ m68ki_write_32(ea+4, (UINT32)(data));
+ break;
+ }
+ default: fatalerror("MC68040: WRITE_EA_64: unhandled mode %d, reg %d, data %08X%08X at %08X\n", mode, reg, (UINT32)(data >> 32), (UINT32)(data), REG_PC);
+ }
+}
+
+static fp_reg READ_EA_FPE(int ea)
+{
+ fp_reg r;
+ int mode = (ea >> 3) & 0x7;
+ int reg = (ea & 0x7);
+
+ // TODO: convert to extended floating-point!
+
+ switch (mode)
+ {
+ case 3: // (An)+
+ {
+ UINT32 d1,d2,d3;
+ UINT32 ea = REG_A[reg];
+ REG_A[reg] += 12;
+ d1 = m68ki_read_32(ea+0);
+ d2 = m68ki_read_32(ea+4);
+ d3 = m68ki_read_32(ea+8);
+ r.i = (UINT64)(d1) << 32 | (UINT64)(d2);
+ break;
+ }
+ default: fatalerror("MC68040: READ_EA_FPE: unhandled mode %d, reg %d, at %08X\n", mode, reg, REG_PC);
+ }
+
+ return r;
+}
+
+static void WRITE_EA_FPE(int ea, fp_reg fpr)
+{
+ int mode = (ea >> 3) & 0x7;
+ int reg = (ea & 0x7);
+
+ // TODO: convert to extended floating-point!
+
+ switch (mode)
+ {
+ case 4: // -(An)
+ {
+ UINT32 ea;
+ REG_A[reg] -= 12;
+ ea = REG_A[reg];
+ m68ki_write_32(ea+0, (UINT32)(fpr.i >> 32));
+ m68ki_write_32(ea+4, (UINT32)(fpr.i));
+ m68ki_write_32(ea+8, 0);
+ break;
+ }
+ default: fatalerror("MC68040: WRITE_EA_FPE: unhandled mode %d, reg %d, data %f at %08X\n", mode, reg, fpr.f, REG_PC);
+ }
+}
+
+
+static void fpgen_rm_reg(UINT16 w2)
+{
+ int ea = REG_IR & 0x3f;
+ int rm = (w2 >> 14) & 0x1;
+ int src = (w2 >> 10) & 0x7;
+ int dst = (w2 >> 7) & 0x7;
+ int opmode = w2 & 0x7f;
+ double source;
+
+ if (rm)
+ {
+ switch (src)
+ {
+ case 0: // Long-Word Integer
+ {
+ INT32 d = READ_EA_32(ea);
+ source = (double)(d);
+ break;
+ }
+ case 1: // Single-precision Real
+ {
+ UINT32 d = READ_EA_32(ea);
+ source = (double)(*(float*)&d);
+ break;
+ }
+ case 2: // Extended-precision Real
+ {
+ fatalerror("fpgen_rm_reg: extended-precision real load unimplemented at %08X\n", REG_PC-4);
+ break;
+ }
+ case 3: // Packed-decimal Real
+ {
+ fatalerror("fpgen_rm_reg: packed-decimal real load unimplemented at %08X\n", REG_PC-4);
+ break;
+ }
+ case 4: // Word Integer
+ {
+ INT16 d = READ_EA_16(ea);
+ source = (double)(d);
+ break;
+ }
+ case 5: // Double-precision Real
+ {
+ UINT64 d = READ_EA_64(ea);
+ source = *(double*)&d;
+ break;
+ }
+ case 6: // Byte Integer
+ {
+ INT8 d = READ_EA_8(ea);
+ source = (double)(d);
+ break;
+ }
+ default: fatalerror("fmove_rm_reg: invalid source specifier at %08X\n", REG_PC-4);
+ }
+ }
+ else
+ {
+ source = REG_FP[src].f;
+ }
+
+ switch (opmode)
+ {
+ case 0x00: // FMOVE
+ {
+ REG_FP[dst].f = source;
+ USE_CYCLES(4);
+ break;
+ }
+ case 0x04: // FSQRT
+ {
+ REG_FP[dst].f = sqrt(source);
+ SET_CONDITION_CODES(REG_FP[dst]);
+ USE_CYCLES(109);
+ break;
+ }
+ case 0x18: // FABS
+ {
+ REG_FP[dst].f = fabs(source);
+ SET_CONDITION_CODES(REG_FP[dst]);
+ USE_CYCLES(3);
+ break;
+ }
+ case 0x1a: // FNEG
+ {
+ REG_FP[dst].f = -source;
+ SET_CONDITION_CODES(REG_FP[dst]);
+ USE_CYCLES(3);
+ break;
+ }
+ case 0x20: // FDIV
+ {
+ REG_FP[dst].f /= source;
+ USE_CYCLES(43);
+ break;
+ }
+ case 0x22: // FADD
+ {
+ REG_FP[dst].f += source;
+ SET_CONDITION_CODES(REG_FP[dst]);
+ USE_CYCLES(9);
+ break;
+ }
+ case 0x23: // FMUL
+ {
+ REG_FP[dst].f *= source;
+ SET_CONDITION_CODES(REG_FP[dst]);
+ USE_CYCLES(11);
+ break;
+ }
+ case 0x28: // FSUB
+ {
+ REG_FP[dst].f -= source;
+ SET_CONDITION_CODES(REG_FP[dst]);
+ USE_CYCLES(9);
+ break;
+ }
+ case 0x38: // FCMP
+ {
+ fp_reg res;
+ res.f = REG_FP[dst].f - source;
+ SET_CONDITION_CODES(res);
+ USE_CYCLES(7);
+ break;
+ }
+ case 0x3a: // FTST
+ {
+ fp_reg res;
+ res.f = source;
+ SET_CONDITION_CODES(res);
+ USE_CYCLES(7);
+ break;
+ }
+
+ default: fatalerror("fpgen_rm_reg: unimplemented opmode %02X at %08X\n", opmode, REG_PC-4);
+ }
+}
+
+static void fmove_reg_mem(UINT16 w2)
+{
+ int ea = REG_IR & 0x3f;
+ int src = (w2 >> 7) & 0x7;
+ int dst = (w2 >> 10) & 0x7;
+ //int kfactor = w2 & 0x7f;
+
+ switch (dst)
+ {
+ case 0: // Long-Word Integer
+ {
+ INT32 d = (INT32)(REG_FP[src].f);
+ WRITE_EA_32(ea, d);
+ break;
+ }
+ case 1: // Single-precision Real
+ {
+ float f = (float)(REG_FP[src].f);
+ UINT32 d = *(UINT32 *)&f;
+ WRITE_EA_32(ea, d);
+ break;
+ }
+ case 2: // Extended-precision Real
+ {
+ fatalerror("fmove_reg_mem: extended-precision real store unimplemented at %08X\n", REG_PC-4);
+ break;
+ }
+ case 3: // Packed-decimal Real with Static K-factor
+ {
+ fatalerror("fmove_reg_mem: packed-decimal real store unimplemented at %08X\n", REG_PC-4);
+ break;
+ }
+ case 4: // Word Integer
+ {
+ fatalerror("fmove_reg_mem: word integer store unimplemented at %08X\n", REG_PC-4);
+ break;
+ }
+ case 5: // Double-precision Real
+ {
+ UINT64 d = REG_FP[src].i;
+ WRITE_EA_64(ea, d);
+ break;
+ }
+ case 6: // Byte Integer
+ {
+ fatalerror("fmove_reg_mem: byte integer store unimplemented at %08X\n", REG_PC-4);
+ break;
+ }
+ case 7: // Packed-decimal Real with Dynamic K-factor
+ {
+ fatalerror("fmove_reg_mem: packed-decimal real store unimplemented at %08X\n", REG_PC-4);
+ break;
+ }
+ }
+
+ USE_CYCLES(12);
+}
+
+static void fmove_fpcr(UINT16 w2)
+{
+ int ea = REG_IR & 0x3f;
+ int dir = (w2 >> 13) & 0x1;
+ int reg = (w2 >> 10) & 0x7;
+
+ if (dir) // From system control reg to <ea>
+ {
+ switch (reg)
+ {
+ case 1: WRITE_EA_32(ea, REG_FPIAR); break;
+ case 2: WRITE_EA_32(ea, REG_FPSR); break;
+ case 4: WRITE_EA_32(ea, REG_FPCR); break;
+ default: fatalerror("fmove_fpcr: unknown reg %d, dir %d\n", reg, dir);
+ }
+ }
+ else // From <ea> to system control reg
+ {
+ switch (reg)
+ {
+ case 1: REG_FPIAR = READ_EA_32(ea); break;
+ case 2: REG_FPSR = READ_EA_32(ea); break;
+ case 4: REG_FPCR = READ_EA_32(ea); break;
+ default: fatalerror("fmove_fpcr: unknown reg %d, dir %d\n", reg, dir);
+ }
+ }
+
+ USE_CYCLES(10);
+}
+
+static void fmovem(UINT16 w2)
+{
+ int i;
+ int ea = REG_IR & 0x3f;
+ int dir = (w2 >> 13) & 0x1;
+ int mode = (w2 >> 11) & 0x3;
+ int reglist = w2 & 0xff;
+
+ if (dir) // From FP regs to mem
+ {
+ switch (mode)
+ {
+ case 0: // Static register list, predecrement addressing mode
+ {
+ for (i=0; i < 8; i++)
+ {
+ if (reglist & (1 << i))
+ {
+ WRITE_EA_FPE(ea, REG_FP[i]);
+ USE_CYCLES(2);
+ }
+ }
+ break;
+ }
+
+ default: fatalerror("040fpu0: FMOVEM: mode %d unimplemented at %08X\n", mode, REG_PC-4);
+ }
+ }
+ else // From mem to FP regs
+ {
+ switch (mode)
+ {
+ case 2: // Static register list, postincrement addressing mode
+ {
+ for (i=0; i < 8; i++)
+ {
+ if (reglist & (1 << i))
+ {
+ REG_FP[7-i] = READ_EA_FPE(ea);
+ USE_CYCLES(2);
+ }
+ }
+ break;
+ }
+
+ default: fatalerror("040fpu0: FMOVEM: mode %d unimplemented at %08X\n", mode, REG_PC-4);
+ }
+ }
+}
+
+static void fbcc16(void)
+{
+ INT32 offset;
+ int condition = REG_IR & 0x3f;
+
+ offset = (INT16)(OPER_I_16());
+
+ // TODO: condition and jump!!!
+ if (TEST_CONDITION(condition))
+ {
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ m68ki_branch_16(offset-2);
+ }
+
+ USE_CYCLES(7);
+}
+
+static void fbcc32(void)
+{
+ INT32 offset;
+ int condition = REG_IR & 0x3f;
+
+ offset = OPER_I_32();
+
+ // TODO: condition and jump!!!
+ if (TEST_CONDITION(condition))
+ {
+ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
+ m68ki_branch_32(offset-4);
+ }
+
+ USE_CYCLES(7);
+}
+
+
+void m68040_fpu_op0(void)
+{
+ switch ((REG_IR >> 6) & 0x3)
+ {
+ case 0:
+ {
+ UINT16 w2 = OPER_I_16();
+ switch ((w2 >> 13) & 0x7)
+ {
+ case 0x0: // FPU ALU FP, FP
+ case 0x2: // FPU ALU ea, FP
+ {
+ fpgen_rm_reg(w2);
+ break;
+ }
+
+ case 0x3: // FMOVE FP, ea
+ {
+ fmove_reg_mem(w2);
+ break;
+ }
+
+ case 0x4: // FMOVE ea, FPCR
+ case 0x5: // FMOVE FPCR, ea
+ {
+ fmove_fpcr(w2);
+ break;
+ }
+
+ case 0x6: // FMOVEM ea, list
+ case 0x7: // FMOVEM list, ea
+ {
+ fmovem(w2);
+ break;
+ }
+
+ default: fatalerror("m68040_fpu_op0: unimplemented subop %d at %08X\n", (w2 >> 13) & 0x7, REG_PC-4);
+ }
+ break;
+ }
+
+ case 2: // FBcc disp16
+ {
+ fbcc16();
+ break;
+ }
+ case 3: // FBcc disp32
+ {
+ fbcc32();
+ break;
+ }
+
+ default: fatalerror("m68040_fpu_op0: unimplemented main op %d\n", (REG_IR >> 6) & 0x3);
+ }
+}
+
+void m68040_fpu_op1(void)
+{
+ int ea = REG_IR & 0x3f;
+
+ switch ((REG_IR >> 6) & 0x3)
+ {
+ case 0: // FSAVE <ea>
+ {
+ WRITE_EA_32(ea, 0x00000000);
+ // TODO: correct state frame
+ break;
+ }
+
+ case 1: // FRESTORE <ea>
+ {
+ READ_EA_32(ea);
+ // TODO: correct state frame
+ break;
+ }
+
+ default: fatalerror("m68040_fpu_op1: unimplemented op %d at %08X\n", (REG_IR >> 6) & 0x3, REG_PC-2);
+ }
+}
+
+
+