]> git.sesse.net Git - pistorm/blobdiff - m68kfpu.c
Add Meson build files.
[pistorm] / m68kfpu.c
index 473e07859bd29184b822fb6a029ec72fbc725fd2..e836933f8401f459f1f968574a708fd945868f4d 100644 (file)
--- a/m68kfpu.c
+++ b/m68kfpu.c
@@ -1,7 +1,13 @@
+// SPDX-License-Identifier: MIT
 #include <math.h>
 #include <stdio.h>
 #include <stdarg.h>
 
+#include "softfloat/softfloat.h"
+#include "m68kcpu.h"
+
+float_status status;
+
 extern void exit(int);
 
 static void fatalerror(char *format, ...) {
@@ -17,11 +23,25 @@ static void fatalerror(char *format, ...) {
 #define FPCC_I                 0x02000000
 #define FPCC_NAN               0x01000000
 
+#define FPES_OE      0x00002000
+#define FPAE_IOP     0x00000080
+
 #define DOUBLE_INFINITY                                        (unsigned long long)(0x7ff0000000000000)
 #define DOUBLE_EXPONENT                                        (unsigned long long)(0x7ff0000000000000)
 #define DOUBLE_MANTISSA                                        (unsigned long long)(0x000fffffffffffff)
 
-extern flag floatx80_is_nan( floatx80 a );
+/*----------------------------------------------------------------------------
+| Returns 1 if the extended double-precision floating-point value `a' is a
+| NaN; otherwise returns 0.
+*----------------------------------------------------------------------------*/
+
+flag floatx80_is_nan( floatx80 a )
+{
+
+    return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (uint64_t) ( a.low<<1 );
+
+}
+
 
 // masks for packed dwords, positive k-factor
 static uint32 pkmask2[18] =
@@ -46,7 +66,7 @@ static inline double fx80_to_double(floatx80 fx)
 
        foo = (double *)&d;
 
-       d = floatx80_to_float64(fx);
+       d = floatx80_to_float64(fx, &status);
 
        return *foo;
 }
@@ -57,18 +77,18 @@ static inline floatx80 double_to_fx80(double in)
 
        d = (uint64 *)&in;
 
-       return float64_to_floatx80(*d);
+       return float64_to_floatx80(*d, &status);
 }
 
-static inline floatx80 load_extended_float80(uint32 ea)
+static inline floatx80 load_extended_float80(m68ki_cpu_core *state, uint32 ea)
 {
        uint32 d1,d2;
        uint16 d3;
        floatx80 fp;
 
-       d3 = m68ki_read_16(ea);
-       d1 = m68ki_read_32(ea+4);
-       d2 = m68ki_read_32(ea+8);
+       d3 = m68ki_read_16(state, ea);
+       d1 = m68ki_read_32(state, ea + 4);
+       d2 = m68ki_read_32(state, ea + 8);
 
        fp.high = d3;
        fp.low = ((uint64)d1<<32) | (d2 & 0xffffffff);
@@ -76,24 +96,24 @@ static inline floatx80 load_extended_float80(uint32 ea)
        return fp;
 }
 
-static inline void store_extended_float80(uint32 ea, floatx80 fpr)
+static inline void store_extended_float80(m68ki_cpu_core *state, uint32 ea, floatx80 fpr)
 {
-       m68ki_write_16(ea+0, fpr.high);
-       m68ki_write_16(ea+2, 0);
-       m68ki_write_32(ea+4, (fpr.low>>32)&0xffffffff);
-       m68ki_write_32(ea+8, fpr.low&0xffffffff);
+       m68ki_write_16(state, ea + 0, fpr.high);
+       m68ki_write_16(state, ea + 2, 0);
+       m68ki_write_32(state, ea + 4, (fpr.low >> 32) & 0xffffffff);
+       m68ki_write_32(state, ea + 8, fpr.low & 0xffffffff);
 }
 
-static inline floatx80 load_pack_float80(uint32 ea)
+static inline floatx80 load_pack_float80(m68ki_cpu_core *state, uint32 ea)
 {
        uint32 dw1, dw2, dw3;
        floatx80 result;
        double tmp;
        char str[128], *ch;
 
-       dw1 = m68ki_read_32(ea);
-       dw2 = m68ki_read_32(ea+4);
-       dw3 = m68ki_read_32(ea+8);
+       dw1 = m68ki_read_32(state, ea);
+       dw2 = m68ki_read_32(state, ea + 4);
+       dw3 = m68ki_read_32(state, ea + 8);
 
        ch = &str[0];
        if (dw1 & 0x80000000)   // mantissa sign
@@ -135,7 +155,7 @@ static inline floatx80 load_pack_float80(uint32 ea)
        return result;
 }
 
-static inline void store_pack_float80(uint32 ea, int k, floatx80 fpr)
+static inline void store_pack_float80(m68ki_cpu_core *state, uint32 ea, int k, floatx80 fpr)
 {
        uint32 dw1, dw2, dw3;
        char str[128], *ch;
@@ -231,7 +251,7 @@ static inline void store_pack_float80(uint32 ea, int k, floatx80 fpr)
                {
                        dw2 &= pkmask2[17];
                        dw3 &= pkmask3[17];
-//                     m68ki_cpu.fpcr |=  (need to set OPERR bit)
+//                     state->fpcr |=  (need to set OPERR bit)
                }
        }
 
@@ -262,13 +282,17 @@ static inline void store_pack_float80(uint32 ea, int k, floatx80 fpr)
                dw1 |= (j << 16);
        }
 
-       m68ki_write_32(ea, dw1);
-       m68ki_write_32(ea+4, dw2);
-       m68ki_write_32(ea+8, dw3);
+       m68ki_write_32(state, ea, dw1);
+       m68ki_write_32(state, ea + 4, dw2);
+       m68ki_write_32(state, ea + 8, dw3);
 }
 
-static inline void SET_CONDITION_CODES(floatx80 reg)
+static inline void SET_CONDITION_CODES(m68ki_cpu_core *state, floatx80 reg)
 {
+//  u64 *regi;
+
+//  regi = (u64 *)&reg;
+
        REG_FPSR &= ~(FPCC_N|FPCC_Z|FPCC_I|FPCC_NAN);
 
        // sign flag
@@ -296,7 +320,7 @@ static inline void SET_CONDITION_CODES(floatx80 reg)
        }
 }
 
-static inline int TEST_CONDITION(int condition)
+static inline int TEST_CONDITION(m68ki_cpu_core *state, int condition)
 {
        int n = (REG_FPSR & FPCC_N) != 0;
        int z = (REG_FPSR & FPCC_Z) != 0;
@@ -358,7 +382,7 @@ static inline int TEST_CONDITION(int condition)
        return r;
 }
 
-static uint8 READ_EA_8(int ea)
+static uint8 READ_EA_8(m68ki_cpu_core *state, int ea)
 {
        int mode = (ea >> 3) & 0x7;
        int reg = (ea & 0x7);
@@ -372,17 +396,27 @@ static uint8 READ_EA_8(int ea)
                case 2:         // (An)
                {
                        uint32 ea = REG_A[reg];
-                       return m68ki_read_8(ea);
+                       return m68ki_read_8(state, ea);
+               }
+               case 3:     // (An)+
+               {
+                       uint32 ea = EA_AY_PI_8();
+                       return m68ki_read_8(state, ea);
+               }
+               case 4:     // -(An)
+               {
+                       uint32 ea = EA_AY_PD_8();
+                       return m68ki_read_8(state, ea);
                }
                case 5:         // (d16, An)
                {
                        uint32 ea = EA_AY_DI_8();
-                       return m68ki_read_8(ea);
+                       return m68ki_read_8(state, ea);
                }
                case 6:         // (An) + (Xn) + d8
                {
                        uint32 ea = EA_AY_IX_8();
-                       return m68ki_read_8(ea);
+                       return m68ki_read_8(state, ea);
                }
                case 7:
                {
@@ -390,19 +424,29 @@ static uint8 READ_EA_8(int ea)
                        {
                                case 0:         // (xxx).W
                                {
-                                       uint32 ea = (uint32)OPER_I_16();
-                                       return m68ki_read_8(ea);
+                                       uint32 ea = (uint32) OPER_I_16(state);
+                                       return m68ki_read_8(state, ea);
                                }
                                case 1:         // (xxx).L
                                {
-                                       uint32 d1 = OPER_I_16();
-                                       uint32 d2 = OPER_I_16();
+                                       uint32 d1 = OPER_I_16(state);
+                                       uint32 d2 = OPER_I_16(state);
                                        uint32 ea = (d1 << 16) | d2;
-                                       return m68ki_read_8(ea);
+                                       return m68ki_read_8(state, ea);
+                               }
+                               case 2:     // (d16, PC)
+                               {
+                                       uint32 ea = EA_PCDI_8();
+                                       return m68ki_read_8(state, ea);
+                               }
+                               case 3:     // (PC) + (Xn) + d8
+                               {
+                                       uint32 ea = EA_PCIX_8();
+                                       return m68ki_read_8(state, ea);
                                }
                                case 4:         // #<data>
                                {
-                                       return  OPER_I_8();
+                                       return OPER_I_8(state);
                                }
                                default:        fatalerror("M68kFPU: READ_EA_8: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
                        }
@@ -414,7 +458,7 @@ static uint8 READ_EA_8(int ea)
        return 0;
 }
 
-static uint16 READ_EA_16(int ea)
+static uint16 READ_EA_16(m68ki_cpu_core *state, int ea)
 {
        int mode = (ea >> 3) & 0x7;
        int reg = (ea & 0x7);
@@ -428,17 +472,27 @@ static uint16 READ_EA_16(int ea)
                case 2:         // (An)
                {
                        uint32 ea = REG_A[reg];
-                       return m68ki_read_16(ea);
+                       return m68ki_read_16(state, ea);
+               }
+               case 3:     // (An)+
+               {
+                       uint32 ea = EA_AY_PI_16();
+                       return m68ki_read_16(state, ea);
+               }
+               case 4:     // -(An)
+               {
+                       uint32 ea = EA_AY_PD_16();
+                       return m68ki_read_16(state, ea);
                }
                case 5:         // (d16, An)
                {
                        uint32 ea = EA_AY_DI_16();
-                       return m68ki_read_16(ea);
+                       return m68ki_read_16(state, ea);
                }
                case 6:         // (An) + (Xn) + d8
                {
                        uint32 ea = EA_AY_IX_16();
-                       return m68ki_read_16(ea);
+                       return m68ki_read_16(state, ea);
                }
                case 7:
                {
@@ -446,19 +500,29 @@ static uint16 READ_EA_16(int ea)
                        {
                                case 0:         // (xxx).W
                                {
-                                       uint32 ea = (uint32)OPER_I_16();
-                                       return m68ki_read_16(ea);
+                                       uint32 ea = (uint32) OPER_I_16(state);
+                                       return m68ki_read_16(state, ea);
                                }
                                case 1:         // (xxx).L
                                {
-                                       uint32 d1 = OPER_I_16();
-                                       uint32 d2 = OPER_I_16();
+                                       uint32 d1 = OPER_I_16(state);
+                                       uint32 d2 = OPER_I_16(state);
                                        uint32 ea = (d1 << 16) | d2;
-                                       return m68ki_read_16(ea);
+                                       return m68ki_read_16(state, ea);
+                               }
+                               case 2:     // (d16, PC)
+                               {
+                                       uint32 ea = EA_PCDI_16();
+                                       return m68ki_read_16(state, ea);
+                               }
+                               case 3:     // (PC) + (Xn) + d8
+                               {
+                                       uint32 ea =  EA_PCIX_16();
+                                       return m68ki_read_16(state, ea);
                                }
                                case 4:         // #<data>
                                {
-                                       return OPER_I_16();
+                                       return OPER_I_16(state);
                                }
 
                                default:        fatalerror("M68kFPU: READ_EA_16: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
@@ -471,7 +535,7 @@ static uint16 READ_EA_16(int ea)
        return 0;
 }
 
-static uint32 READ_EA_32(int ea)
+static uint32 READ_EA_32(m68ki_cpu_core *state, int ea)
 {
        int mode = (ea >> 3) & 0x7;
        int reg = (ea & 0x7);
@@ -485,22 +549,27 @@ static uint32 READ_EA_32(int ea)
                case 2:         // (An)
                {
                        uint32 ea = REG_A[reg];
-                       return m68ki_read_32(ea);
+                       return m68ki_read_32(state, ea);
                }
                case 3:         // (An)+
                {
                        uint32 ea = EA_AY_PI_32();
-                       return m68ki_read_32(ea);
+                       return m68ki_read_32(state, ea);
+               }
+               case 4:         // -(An)
+               {
+                       uint32 ea = EA_AY_PD_32();
+                       return m68ki_read_32(state, ea);
                }
                case 5:         // (d16, An)
                {
                        uint32 ea = EA_AY_DI_32();
-                       return m68ki_read_32(ea);
+                       return m68ki_read_32(state, ea);
                }
                case 6:         // (An) + (Xn) + d8
                {
                        uint32 ea = EA_AY_IX_32();
-                       return m68ki_read_32(ea);
+                       return m68ki_read_32(state, ea);
                }
                case 7:
                {
@@ -508,24 +577,29 @@ static uint32 READ_EA_32(int ea)
                        {
                                case 0:         // (xxx).W
                                {
-                                       uint32 ea = (uint32)OPER_I_16();
-                                       return m68ki_read_32(ea);
+                                       uint32 ea = (uint32) OPER_I_16(state);
+                                       return m68ki_read_32(state, ea);
                                }
                                case 1:         // (xxx).L
                                {
-                                       uint32 d1 = OPER_I_16();
-                                       uint32 d2 = OPER_I_16();
+                                       uint32 d1 = OPER_I_16(state);
+                                       uint32 d2 = OPER_I_16(state);
                                        uint32 ea = (d1 << 16) | d2;
-                                       return m68ki_read_32(ea);
+                                       return m68ki_read_32(state, ea);
                                }
                                case 2:         // (d16, PC)
                                {
                                        uint32 ea = EA_PCDI_32();
-                                       return m68ki_read_32(ea);
+                                       return m68ki_read_32(state, ea);
+                               }
+                               case 3:     // (PC) + (Xn) + d8
+                               {
+                                       uint32 ea =  EA_PCIX_32();
+                                       return m68ki_read_32(state, ea);
                                }
                                case 4:         // #<data>
                                {
-                                       return  OPER_I_32();
+                                       return OPER_I_32(state);
                                }
                                default:        fatalerror("M68kFPU: READ_EA_32: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
                        }
@@ -536,7 +610,7 @@ static uint32 READ_EA_32(int ea)
        return 0;
 }
 
-static uint64 READ_EA_64(int ea)
+static uint64 READ_EA_64(m68ki_cpu_core *state, int ea)
 {
        int mode = (ea >> 3) & 0x7;
        int reg = (ea & 0x7);
@@ -547,40 +621,69 @@ static uint64 READ_EA_64(int ea)
                case 2:         // (An)
                {
                        uint32 ea = REG_A[reg];
-                       h1 = m68ki_read_32(ea+0);
-                       h2 = m68ki_read_32(ea+4);
+                       h1 = m68ki_read_32(state, ea + 0);
+                       h2 = m68ki_read_32(state, 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);
+                       h1 = m68ki_read_32(state, ea + 0);
+                       h2 = m68ki_read_32(state, 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(state, ea + 0);
+                       h2 = m68ki_read_32(state, 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);
+                       h1 = m68ki_read_32(state, ea + 0);
+                       h2 = m68ki_read_32(state, ea + 4);
+                       return  (uint64)(h1) << 32 | (uint64)(h2);
+               }
+               case 6:     // (An) + (Xn) + d8
+               {
+                       uint32 ea = EA_AY_IX_32();
+                       h1 = m68ki_read_32(state, ea + 0);
+                       h2 = m68ki_read_32(state, ea + 4);
                        return  (uint64)(h1) << 32 | (uint64)(h2);
                }
                case 7:
                {
                        switch (reg)
                        {
+                               case 1:     // (xxx).L
+                               {
+                                       uint32 d1 = OPER_I_16(state);
+                                       uint32 d2 = OPER_I_16(state);
+                                       uint32 ea = (d1 << 16) | d2;
+                                       return (uint64)(m68ki_read_32(state, ea)) << 32 | (uint64)(m68ki_read_32(state, ea + 4));
+                               }
+                               case 3:     // (PC) + (Xn) + d8
+                               {
+                                       uint32 ea =  EA_PCIX_32();
+                                       h1 = m68ki_read_32(state, ea + 0);
+                                       h2 = m68ki_read_32(state, ea + 4);
+                                       return  (uint64)(h1) << 32 | (uint64)(h2);
+                               }
                                case 4:         // #<data>
                                {
-                                       h1 = OPER_I_32();
-                                       h2 = OPER_I_32();
+                                       h1 = OPER_I_32(state);
+                                       h2 = OPER_I_32(state);
                                        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);
+                                       h1 = m68ki_read_32(state, ea + 0);
+                                       h2 = m68ki_read_32(state, 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);
@@ -594,16 +697,18 @@ static uint64 READ_EA_64(int ea)
 }
 
 
-static floatx80 READ_EA_FPE(int mode, int reg, uint32 di_mode_ea)
+static floatx80 READ_EA_FPE(m68ki_cpu_core *state, uint32 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(ea);
+                       fpr = load_extended_float80(state, ea);
                        break;
                }
 
@@ -611,39 +716,66 @@ static floatx80 READ_EA_FPE(int mode, int reg, uint32 di_mode_ea)
                {
                        uint32 ea = REG_A[reg];
                        REG_A[reg] += 12;
-                       fpr = load_extended_float80(ea);
+                       fpr = load_extended_float80(state, ea);
+                       break;
+               }
+               case 4:     // -(An)
+               {
+                       uint32 ea = REG_A[reg]-12;
+                       REG_A[reg] -= 12;
+                       fpr = load_extended_float80(state, ea);
                        break;
                }
-      case 5:          // (d16, An)  (added by JFF)
+      case 5:          // (d16, An)
                {
-                 fpr = load_extended_float80(di_mode_ea);
+                       // FIXME: will fail for fmovem
+                       uint32 ea = EA_AY_DI_32();
+                       fpr = load_extended_float80(state, ea);
                break;
-
                }
+               case 6:     // (An) + (Xn) + d8
+               {
+                       // FIXME: will fail for fmovem
+                       uint32 ea = EA_AY_IX_32();
+                       fpr = load_extended_float80(state, ea);
+                       break;
+               }
+
                case 7: // extended modes
                {
                        switch (reg)
                        {
+                               case 1:     // (xxx)
+                                       {
+                                               uint32 d1 = OPER_I_16(state);
+                                               uint32 d2 = OPER_I_16(state);
+                                               uint32 ea = (d1 << 16) | d2;
+                                               fpr = load_extended_float80(state, ea);
+                                       }
+                                       break;
+
                                case 2: // (d16, PC)
                                        {
                                                uint32 ea = EA_PCDI_32();
-                                               fpr = load_extended_float80(ea);
+                                               fpr = load_extended_float80(state, ea);
                                        }
                                        break;
 
                                case 3: // (d16,PC,Dx.w)
                                        {
                                                uint32 ea = EA_PCIX_32();
-                                               fpr = load_extended_float80(ea);
+                                               fpr = load_extended_float80(state, ea);
                                        }
                                        break;
-                       case 4: // immediate (JFF)
-                               {
-                                 uint32 ea = REG_PC;
-                                 fpr = load_extended_float80(ea);
-                                 REG_PC += 12;
-                               }
-                               break;
+
+                               case 4: // immediate (JFF)
+                                       {
+                                               uint32 ea = REG_PC;
+                                               fpr = load_extended_float80(state, ea);
+                                               REG_PC += 12;
+                                       }
+                                       break;
+
                                default:
                                        fatalerror("M68kFPU: READ_EA_FPE: unhandled mode %d, reg %d, at %08X\n", mode, reg, REG_PC);
                                        break;
@@ -657,7 +789,7 @@ static floatx80 READ_EA_FPE(int mode, int reg, uint32 di_mode_ea)
        return fpr;
 }
 
-static floatx80 READ_EA_PACK(int ea)
+static floatx80 READ_EA_PACK(m68ki_cpu_core *state, int ea)
 {
        floatx80 fpr;
        int mode = (ea >> 3) & 0x7;
@@ -668,7 +800,7 @@ static floatx80 READ_EA_PACK(int ea)
                case 2:         // (An)
                {
                        uint32 ea = REG_A[reg];
-                       fpr = load_pack_float80(ea);
+                       fpr = load_pack_float80(state, ea);
                        break;
                }
 
@@ -676,7 +808,7 @@ static floatx80 READ_EA_PACK(int ea)
                {
                        uint32 ea = REG_A[reg];
                        REG_A[reg] += 12;
-                       fpr = load_pack_float80(ea);
+                       fpr = load_pack_float80(state, ea);
                        break;
                }
 
@@ -687,7 +819,7 @@ static floatx80 READ_EA_PACK(int ea)
                                case 3: // (d16,PC,Dx.w)
                                        {
                                                uint32 ea = EA_PCIX_32();
-                                               fpr = load_pack_float80(ea);
+                                               fpr = load_pack_float80(state, ea);
                                        }
                                        break;
 
@@ -704,7 +836,7 @@ static floatx80 READ_EA_PACK(int ea)
        return fpr;
 }
 
-static void WRITE_EA_8(int ea, uint8 data)
+static void WRITE_EA_8(m68ki_cpu_core *state, int ea, uint8 data)
 {
        int mode = (ea >> 3) & 0x7;
        int reg = (ea & 0x7);
@@ -719,31 +851,31 @@ static void WRITE_EA_8(int ea, uint8 data)
                case 2:         // (An)
                {
                        uint32 ea = REG_A[reg];
-                       m68ki_write_8(ea, data);
+                       m68ki_write_8(state, ea, data);
                        break;
                }
                case 3:         // (An)+
                {
                        uint32 ea = EA_AY_PI_8();
-                       m68ki_write_8(ea, data);
+                       m68ki_write_8(state, ea, data);
                        break;
                }
                case 4:         // -(An)
                {
                        uint32 ea = EA_AY_PD_8();
-                       m68ki_write_8(ea, data);
+                       m68ki_write_8(state, ea, data);
                        break;
                }
                case 5:         // (d16, An)
                {
                        uint32 ea = EA_AY_DI_8();
-                       m68ki_write_8(ea, data);
+                       m68ki_write_8(state, ea, data);
                        break;
                }
                case 6:         // (An) + (Xn) + d8
                {
                        uint32 ea = EA_AY_IX_8();
-                       m68ki_write_8(ea, data);
+                       m68ki_write_8(state, ea, data);
                        break;
                }
                case 7:
@@ -752,16 +884,16 @@ static void WRITE_EA_8(int ea, uint8 data)
                        {
                                case 1:         // (xxx).B
                                {
-                                       uint32 d1 = OPER_I_16();
-                                       uint32 d2 = OPER_I_16();
+                                       uint32 d1 = OPER_I_16(state);
+                                       uint32 d2 = OPER_I_16(state);
                                        uint32 ea = (d1 << 16) | d2;
-                                       m68ki_write_8(ea, data);
+                                       m68ki_write_8(state, ea, data);
                                        break;
                                }
                                case 2:         // (d16, PC)
                                {
                                        uint32 ea = EA_PCDI_16();
-                                       m68ki_write_8(ea, data);
+                                       m68ki_write_8(state, ea, data);
                                        break;
                                }
                                default:        fatalerror("M68kFPU: WRITE_EA_8: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
@@ -772,7 +904,7 @@ static void WRITE_EA_8(int ea, uint8 data)
        }
 }
 
-static void WRITE_EA_16(int ea, uint16 data)
+static void WRITE_EA_16(m68ki_cpu_core *state, int ea, uint16 data)
 {
        int mode = (ea >> 3) & 0x7;
        int reg = (ea & 0x7);
@@ -787,31 +919,31 @@ static void WRITE_EA_16(int ea, uint16 data)
                case 2:         // (An)
                {
                        uint32 ea = REG_A[reg];
-                       m68ki_write_16(ea, data);
+                       m68ki_write_16(state, ea, data);
                        break;
                }
                case 3:         // (An)+
                {
                        uint32 ea = EA_AY_PI_16();
-                       m68ki_write_16(ea, data);
+                       m68ki_write_16(state, ea, data);
                        break;
                }
                case 4:         // -(An)
                {
                        uint32 ea = EA_AY_PD_16();
-                       m68ki_write_16(ea, data);
+                       m68ki_write_16(state, ea, data);
                        break;
                }
                case 5:         // (d16, An)
                {
                        uint32 ea = EA_AY_DI_16();
-                       m68ki_write_16(ea, data);
+                       m68ki_write_16(state, ea, data);
                        break;
                }
                case 6:         // (An) + (Xn) + d8
                {
                        uint32 ea = EA_AY_IX_16();
-                       m68ki_write_16(ea, data);
+                       m68ki_write_16(state, ea, data);
                        break;
                }
                case 7:
@@ -820,16 +952,16 @@ static void WRITE_EA_16(int ea, uint16 data)
                        {
                                case 1:         // (xxx).W
                                {
-                                       uint32 d1 = OPER_I_16();
-                                       uint32 d2 = OPER_I_16();
+                                       uint32 d1 = OPER_I_16(state);
+                                       uint32 d2 = OPER_I_16(state);
                                        uint32 ea = (d1 << 16) | d2;
-                                       m68ki_write_16(ea, data);
+                                       m68ki_write_16(state, ea, data);
                                        break;
                                }
                                case 2:         // (d16, PC)
                                {
                                        uint32 ea = EA_PCDI_16();
-                                       m68ki_write_16(ea, data);
+                                       m68ki_write_16(state, ea, data);
                                        break;
                                }
                                default:        fatalerror("M68kFPU: WRITE_EA_16: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
@@ -840,7 +972,7 @@ static void WRITE_EA_16(int ea, uint16 data)
        }
 }
 
-static void WRITE_EA_32(int ea, uint32 data)
+static void WRITE_EA_32(m68ki_cpu_core *state, int ea, uint32 data)
 {
        int mode = (ea >> 3) & 0x7;
        int reg = (ea & 0x7);
@@ -860,49 +992,55 @@ static void WRITE_EA_32(int ea, uint32 data)
                case 2:         // (An)
                {
                        uint32 ea = REG_A[reg];
-                       m68ki_write_32(ea, data);
+                       m68ki_write_32(state, ea, data);
                        break;
                }
                case 3:         // (An)+
                {
                        uint32 ea = EA_AY_PI_32();
-                       m68ki_write_32(ea, data);
+                       m68ki_write_32(state, ea, data);
                        break;
                }
                case 4:         // -(An)
                {
                        uint32 ea = EA_AY_PD_32();
-                       m68ki_write_32(ea, data);
+                       m68ki_write_32(state, ea, data);
                        break;
                }
                case 5:         // (d16, An)
                {
                        uint32 ea = EA_AY_DI_32();
-                       m68ki_write_32(ea, data);
+                       m68ki_write_32(state, ea, data);
                        break;
                }
                case 6:         // (An) + (Xn) + d8
                {
                        uint32 ea = EA_AY_IX_32();
-                       m68ki_write_32(ea, data);
+                       m68ki_write_32(state, ea, data);
                        break;
                }
                case 7:
                {
                        switch (reg)
                        {
+                               case 0:     // (xxx).W
+                               {
+                                       uint32 ea = OPER_I_16(state);
+                                       m68ki_write_32(state, ea, data);
+                                       break;
+                               }
                                case 1:         // (xxx).L
                                {
-                                       uint32 d1 = OPER_I_16();
-                                       uint32 d2 = OPER_I_16();
+                                       uint32 d1 = OPER_I_16(state);
+                                       uint32 d2 = OPER_I_16(state);
                                        uint32 ea = (d1 << 16) | d2;
-                                       m68ki_write_32(ea, data);
+                                       m68ki_write_32(state, ea, data);
                                        break;
                                }
                                case 2:         // (d16, PC)
                                {
                                        uint32 ea = EA_PCDI_32();
-                                       m68ki_write_32(ea, data);
+                                       m68ki_write_32(state, ea, data);
                                        break;
                                }
                                default:        fatalerror("M68kFPU: WRITE_EA_32: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
@@ -913,7 +1051,7 @@ static void WRITE_EA_32(int ea, uint32 data)
        }
 }
 
-static void WRITE_EA_64(int ea, uint64 data)
+static void WRITE_EA_64(m68ki_cpu_core *state, int ea, uint64 data)
 {
        int mode = (ea >> 3) & 0x7;
        int reg = (ea & 0x7);
@@ -923,8 +1061,16 @@ static void WRITE_EA_64(int ea, uint64 data)
                case 2:         // (An)
                {
                        uint32 ea = REG_A[reg];
-                       m68ki_write_32(ea, (uint32)(data >> 32));
-                       m68ki_write_32(ea+4, (uint32)(data));
+                       m68ki_write_32(state, ea, (uint32) (data >> 32));
+                       m68ki_write_32(state, ea + 4, (uint32) (data));
+                       break;
+               }
+               case 3:     // (An)+
+               {
+                       uint32 ea = REG_A[reg];
+                       REG_A[reg] += 8;
+                       m68ki_write_32(state, ea + 0, (uint32) (data >> 32));
+                       m68ki_write_32(state, ea + 4, (uint32) (data));
                        break;
                }
                case 4:         // -(An)
@@ -932,24 +1078,56 @@ static void WRITE_EA_64(int ea, uint64 data)
                        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));
+                       m68ki_write_32(state, ea + 0, (uint32) (data >> 32));
+                       m68ki_write_32(state, 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));
+                       m68ki_write_32(state, ea + 0, (uint32) (data >> 32));
+                       m68ki_write_32(state, ea + 4, (uint32) (data));
+                       break;
+               }
+               case 6:     // (An) + (Xn) + d8
+               {
+                       uint32 ea = EA_AY_IX_32();
+                       m68ki_write_32(state, ea + 0, (uint32) (data >> 32));
+                       m68ki_write_32(state, ea + 4, (uint32) (data));
+                       break;
+               }
+               case 7:
+               {
+                       switch (reg)
+                       {
+                               case 1:     // (xxx).L
+                               {
+                                       uint32 d1 = OPER_I_16(state);
+                                       uint32 d2 = OPER_I_16(state);
+                                       uint32 ea = (d1 << 16) | d2;
+                                       m68ki_write_32(state, ea + 0, (uint32) (data >> 32));
+                                       m68ki_write_32(state, ea + 4, (uint32) (data));
+                                       break;
+                               }
+                               case 2:     // (d16, PC)
+                               {
+                                       uint32 ea = EA_PCDI_32();
+                                       m68ki_write_32(state, ea + 0, (uint32) (data >> 32));
+                                       m68ki_write_32(state, 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(int mode, int reg, floatx80 fpr, uint32 di_mode_ea)
+static void WRITE_EA_FPE(m68ki_cpu_core *state, uint32 ea, floatx80 fpr)
 {
-
+       int mode = (ea >> 3) & 0x7;
+       int reg = (ea & 0x7);
 
        switch (mode)
        {
@@ -957,7 +1135,7 @@ static void WRITE_EA_FPE(int mode, int reg, floatx80 fpr, uint32 di_mode_ea)
                {
                        uint32 ea;
                        ea = REG_A[reg];
-                       store_extended_float80(ea, fpr);
+                       store_extended_float80(state, ea, fpr);
                        break;
                }
 
@@ -965,7 +1143,7 @@ static void WRITE_EA_FPE(int mode, int reg, floatx80 fpr, uint32 di_mode_ea)
                {
                        uint32 ea;
                        ea = REG_A[reg];
-                       store_extended_float80(ea, fpr);
+                       store_extended_float80(state, ea, fpr);
                        REG_A[reg] += 12;
                        break;
                }
@@ -975,15 +1153,13 @@ static void WRITE_EA_FPE(int mode, int reg, floatx80 fpr, uint32 di_mode_ea)
                        uint32 ea;
                        REG_A[reg] -= 12;
                        ea = REG_A[reg];
-                       store_extended_float80(ea, fpr);
+                       store_extended_float80(state, ea, fpr);
                        break;
                }
-         case 5:               // (d16, An)  (added by JFF)
+         case 5:               // (d16, An)
                {
-                 // EA_AY_DI_32() should not be done here because fmovem would increase
-                 // PC each time, reading incorrect displacement & advancing PC too much
-                 // uint32 ea = EA_AY_DI_32();
-                 store_extended_float80(di_mode_ea, fpr);
+                 uint32 ea = EA_AY_DI_32();
+                       store_extended_float80(state, ea, fpr);
                 break;
 
                }
@@ -999,7 +1175,7 @@ static void WRITE_EA_FPE(int mode, int reg, floatx80 fpr, uint32 di_mode_ea)
        }
 }
 
-static void WRITE_EA_PACK(int ea, int k, floatx80 fpr)
+static void WRITE_EA_PACK(m68ki_cpu_core *state, int ea, int k, floatx80 fpr)
 {
        int mode = (ea >> 3) & 0x7;
        int reg = (ea & 0x7);
@@ -1010,7 +1186,7 @@ static void WRITE_EA_PACK(int ea, int k, floatx80 fpr)
                {
                        uint32 ea;
                        ea = REG_A[reg];
-                       store_pack_float80(ea, k, fpr);
+                       store_pack_float80(state, ea, k, fpr);
                        break;
                }
 
@@ -1018,7 +1194,7 @@ static void WRITE_EA_PACK(int ea, int k, floatx80 fpr)
                {
                        uint32 ea;
                        ea = REG_A[reg];
-                       store_pack_float80(ea, k, fpr);
+                       store_pack_float80(state, ea, k, fpr);
                        REG_A[reg] += 12;
                        break;
                }
@@ -1028,7 +1204,7 @@ static void WRITE_EA_PACK(int ea, int k, floatx80 fpr)
                        uint32 ea;
                        REG_A[reg] -= 12;
                        ea = REG_A[reg];
-                       store_pack_float80(ea, k, fpr);
+                       store_pack_float80(state, ea, k, fpr);
                        break;
                }
 
@@ -1045,7 +1221,7 @@ static void WRITE_EA_PACK(int ea, int k, floatx80 fpr)
 }
 
 
-static void fpgen_rm_reg(uint16 w2)
+static void fpgen_rm_reg(m68ki_cpu_core *state, uint16 w2)
 {
        int ea = REG_IR & 0x3f;
        int rm = (w2 >> 14) & 0x1;
@@ -1062,45 +1238,42 @@ static void fpgen_rm_reg(uint16 w2)
                {
                        case 0:         // Long-Word Integer
                        {
-                               sint32 d = READ_EA_32(ea);
+                               sint32 d = READ_EA_32(state, ea);
                                source = int32_to_floatx80(d);
                                break;
                        }
                        case 1:         // Single-precision Real
                        {
-                               uint32 d = READ_EA_32(ea);
-                               source = float32_to_floatx80(d);
+                               uint32 d = READ_EA_32(state, ea);
+                               source = float32_to_floatx80(d, &status);
                                break;
                        }
                        case 2:         // Extended-precision Real
                        {
-                       int imode = (ea >> 3) & 0x7;
-                       int reg = (ea & 0x7);
-                       uint32 di_mode_ea = imode == 5 ? (REG_A[reg]+MAKE_INT_16(m68ki_read_imm_16())) : 0;
-                       source = READ_EA_FPE(imode,reg,di_mode_ea);
-                               break;
+                               source = READ_EA_FPE(state, ea);
+                               break;
                        }
                        case 3:         // Packed-decimal Real
                        {
-                               source = READ_EA_PACK(ea);
+                               source = READ_EA_PACK(state, ea);
                                break;
                        }
                        case 4:         // Word Integer
                        {
-                               sint16 d = READ_EA_16(ea);
+                               sint16 d = READ_EA_16(state, ea);
                                source = int32_to_floatx80((sint32)d);
                                break;
                        }
                        case 5:         // Double-precision Real
                        {
-                               uint64 d = READ_EA_64(ea);
+                               uint64 d = READ_EA_64(state, ea);
 
-                               source = float64_to_floatx80(d);
+                               source = float64_to_floatx80(d, &status);
                                break;
                        }
                        case 6:         // Byte Integer
                        {
-                               sint8 d = READ_EA_8(ea);
+                               sint8 d = READ_EA_8(state, ea);
                                source = int32_to_floatx80((sint32)d);
                                break;
                        }
@@ -1158,6 +1331,59 @@ static void fpgen_rm_reg(uint16 w2)
                                        case 0x34:      // 10^2
                                                source = int32_to_floatx80((sint32)10*10);
                                                break;
+                                       case 0x35:  // 10^4
+                                               source = int32_to_floatx80((sint32)1000*10);
+                                               break;
+
+                                       case 0x36:  // 1.0e8
+                                               source = int32_to_floatx80((sint32)10000000*10);
+                                               break;
+
+                                       case 0x37:  // 1.0e16 - can't get the right precision from s32 so go "direct" with constants from h/w
+                                               source.high = 0x4034;
+                                               source.low = U64(0x8e1bc9bf04000000);
+                                               break;
+
+                                       case 0x38:  // 1.0e32
+                                               source.high = 0x4069;
+                                               source.low = U64(0x9dc5ada82b70b59e);
+                                               break;
+
+                                       case 0x39:  // 1.0e64
+                                               source.high = 0x40d3;
+                                               source.low = U64(0xc2781f49ffcfa6d5);
+                                               break;
+
+                                       case 0x3a:  // 1.0e128
+                                               source.high = 0x41a8;
+                                               source.low = U64(0x93ba47c980e98ce0);
+                                               break;
+
+                                       case 0x3b:  // 1.0e256
+                                               source.high = 0x4351;
+                                               source.low = U64(0xaa7eebfb9df9de8e);
+                                               break;
+
+                                       case 0x3c:  // 1.0e512
+                                               source.high = 0x46a3;
+                                               source.low = U64(0xe319a0aea60e91c7);
+                                               break;
+
+                                       case 0x3d:  // 1.0e1024
+                                               source.high = 0x4d48;
+                                               source.low = U64(0xc976758681750c17);
+                                               break;
+
+                                       case 0x3e:  // 1.0e2048
+                                               source.high = 0x5a92;
+                                               source.low = U64(0x9e8b3b5dc53d5de5);
+                                               break;
+
+                                       case 0x3f:  // 1.0e4096
+                                               source.high = 0x7525;
+                                               source.low = U64(0xc46052028a20979b);
+                                               break;
+
 
                                        default:
                                                fatalerror("fmove_rm_reg: unknown constant ROM offset %x at %08x\n", w2&0x7f, REG_PC-4);
@@ -1166,7 +1392,8 @@ static void fpgen_rm_reg(uint16 w2)
 
                                // handle it right here, the usual opmode bits aren't valid in the FMOVECR case
                                REG_FP[dst] = source;
-                       SET_CONDITION_CODES(REG_FP[dst]); // JFF when destination is a register, we HAVE to update FPCR
+                               //FIXME mame doesn't use SET_CONDITION_CODES here
+                               SET_CONDITION_CODES(state, REG_FP[dst]); // JFF when destination is a register, we HAVE to update FPCR
                                USE_CYCLES(4);
                                return;
                        }
@@ -1178,116 +1405,338 @@ static void fpgen_rm_reg(uint16 w2)
                source = REG_FP[src];
        }
 
-
+       // For FD* and FS* prefixes we already converted the source to floatx80
+       // so we can treat these as their parent op.
 
        switch (opmode)
        {
+               case 0x44:              // FDMOVE
+               case 0x40:              // FSMOVE
                case 0x00:              // FMOVE
                {
                        REG_FP[dst] = source;
-                   SET_CONDITION_CODES(REG_FP[dst]);  // JFF needs update condition codes
+                       SET_CONDITION_CODES(state, REG_FP[dst]);
                        USE_CYCLES(4);
                        break;
                }
-               case 0x01:              // Fsint
+               case 0x01:              // FINT
                {
                        sint32 temp;
-                       temp = floatx80_to_int32(source);
+                       temp = floatx80_to_int32(source, &status);
                        REG_FP[dst] = int32_to_floatx80(temp);
-                       SET_CONDITION_CODES(REG_FP[dst]);  // JFF needs update condition codes
+                       //FIXME mame doesn't use SET_CONDITION_CODES here
+                       SET_CONDITION_CODES(state, REG_FP[dst]);  // JFF needs update condition codes
+                       USE_CYCLES(4);
                        break;
                }
-               case 0x03:              // FsintRZ
+               case 0x02:              // FSINH
+               {
+                       REG_FP[dst] = floatx80_sinh(source, &status);
+                       SET_CONDITION_CODES(state, REG_FP[dst]);
+                       USE_CYCLES(75);
+                       break;
+               }
+               case 0x03:              // FINTRZ
                {
                        sint32 temp;
-                       temp = floatx80_to_int32_round_to_zero(source);
+                       temp = floatx80_to_int32_round_to_zero(source, &status);
                        REG_FP[dst] = int32_to_floatx80(temp);
-                       SET_CONDITION_CODES(REG_FP[dst]);  // JFF needs update condition codes
+                       //FIXME mame doesn't use SET_CONDITION_CODES here
+                       SET_CONDITION_CODES(state, REG_FP[dst]);  // JFF needs update condition codes
                        break;
                }
+               case 0x45:              // FDSQRT
+               case 0x41:              // FSSQRT
                case 0x04:              // FSQRT
+               case 0x05:              // FSQRT
                {
-                       REG_FP[dst] = floatx80_sqrt(source);
-                       SET_CONDITION_CODES(REG_FP[dst]);
+                       REG_FP[dst] = floatx80_sqrt(source, &status);
+                       SET_CONDITION_CODES(state, REG_FP[dst]);
                        USE_CYCLES(109);
                        break;
                }
+               case 0x06:      // FLOGNP1
+               case 0x07:      // FLOGNP1
+               {
+                       REG_FP[dst] = floatx80_lognp1 (source, &status);
+                       SET_CONDITION_CODES(state, REG_FP[dst]);
+                       USE_CYCLES(594); // for MC68881
+                       break;
+               }
+               case 0x08:      // FETOXM1
+               {
+                       REG_FP[dst] = floatx80_etoxm1(source, &status);
+                       SET_CONDITION_CODES(state, REG_FP[dst]);
+                       USE_CYCLES(6);
+                       break;
+               }
+               case 0x09:      // FTANH
+               {
+                       REG_FP[dst] = floatx80_tanh(source, &status);
+                       SET_CONDITION_CODES(state, REG_FP[dst]);
+                       USE_CYCLES(75);
+                       break;
+               }
+               case 0x0a:      // FATAN
+               case 0x0b:      // FATAN
+               {
+                       REG_FP[dst] = floatx80_atan(source, &status);
+                       SET_CONDITION_CODES(state, REG_FP[dst]);
+                       USE_CYCLES(75);
+                       break;
+               }
+               case 0x0c:      // FASIN
+               {
+                       REG_FP[dst] = floatx80_asin(source, &status);
+                       SET_CONDITION_CODES(state, REG_FP[dst]);
+                       USE_CYCLES(75);
+                       break;
+               }
+               case 0x0d:      // FATANH
+               {
+                       REG_FP[dst] = floatx80_atanh(source, &status);
+                       SET_CONDITION_CODES(state, REG_FP[dst]);
+                       USE_CYCLES(75);
+                       break;
+               }
+               case 0x0e:      // FSIN
+               {
+                       REG_FP[dst] = floatx80_sin(source, &status);
+                       SET_CONDITION_CODES(state, REG_FP[dst]);
+                       USE_CYCLES(75);
+                       break;
+               }
+               case 0x0f:      // FTAN
+               {
+                       REG_FP[dst] = floatx80_tan(source, &status);
+                       SET_CONDITION_CODES(state, REG_FP[dst]);
+                       USE_CYCLES(75);
+                       break;
+               }
+               case 0x10:      // FETOX
+               {
+                       REG_FP[dst] = floatx80_etox(source, &status);
+                       SET_CONDITION_CODES(state, REG_FP[dst]);
+                       USE_CYCLES(75);
+                       break;
+               }
+               case 0x11:      // FTWOTOX
+               {
+                       REG_FP[dst] = floatx80_twotox(source, &status);
+                       SET_CONDITION_CODES(state, REG_FP[dst]);
+                       USE_CYCLES(75);
+                       break;
+               }
+               case 0x12:      // FTENTOX
+               case 0x13:      // FTENTOX
+               {
+                       REG_FP[dst] = floatx80_tentox(source, &status);
+                       SET_CONDITION_CODES(state, REG_FP[dst]);
+                       USE_CYCLES(75);
+                       break;
+               }
+               case 0x14:      // FLOGN
+               {
+                       REG_FP[dst] = floatx80_logn(source, &status);
+                       SET_CONDITION_CODES(state, REG_FP[dst]);
+                       USE_CYCLES(548); // for MC68881
+                       break;
+               }
+               case 0x15:      // FLOG10
+               {
+                       REG_FP[dst] = floatx80_log10(source, &status);
+                       SET_CONDITION_CODES(state, REG_FP[dst]);
+                       USE_CYCLES(604); // for MC68881
+                       break;
+               }
+               case 0x16:      // FLOG2
+               case 0x17:      // FLOG2
+               {
+                       REG_FP[dst] = floatx80_log2(source, &status);
+                       SET_CONDITION_CODES(state, REG_FP[dst]);
+                       USE_CYCLES(604); // for MC68881
+                       break;
+               }
+               case 0x5C:              // FDABS
+               case 0x58:              // FSABS
                case 0x18:              // FABS
                {
                        REG_FP[dst] = source;
                        REG_FP[dst].high &= 0x7fff;
-                       SET_CONDITION_CODES(REG_FP[dst]);
+                       SET_CONDITION_CODES(state, REG_FP[dst]);
                        USE_CYCLES(3);
                        break;
                }
+               case 0x19:      // FCOSH
+               {
+                       REG_FP[dst] = floatx80_cosh(source, &status);
+                       SET_CONDITION_CODES(state, REG_FP[dst]);
+                       USE_CYCLES(64);
+                       break;
+               }
+               case 0x5e:              // FDNEG
+               case 0x5a:              // FSNEG
                case 0x1a:              // FNEG
+               case 0x1b:              // FNEG
                {
                        REG_FP[dst] = source;
                        REG_FP[dst].high ^= 0x8000;
-                       SET_CONDITION_CODES(REG_FP[dst]);
+                       SET_CONDITION_CODES(state, REG_FP[dst]);
                        USE_CYCLES(3);
                        break;
                }
+               case 0x1c:      // FACOS
+               {
+                       REG_FP[dst] = floatx80_acos(source, &status);
+                       SET_CONDITION_CODES(state, REG_FP[dst]);
+                       USE_CYCLES(604); // for MC68881
+                       break;
+                       break;
+               }
+               case 0x1d:      // FCOS
+               {
+                       REG_FP[dst] = floatx80_cos(source, &status);
+                       SET_CONDITION_CODES(state, REG_FP[dst]);
+                       USE_CYCLES(75);
+                       break;
+               }
                case 0x1e:              // FGETEXP
                {
-                       sint16 temp;
-                       temp = source.high;     // get the exponent
-                       temp -= 0x3fff; // take off the bias
-                       REG_FP[dst] = double_to_fx80((double)temp);
-                       SET_CONDITION_CODES(REG_FP[dst]);
+                       REG_FP[dst] = floatx80_getexp(source, &status);
+                       SET_CONDITION_CODES(state, REG_FP[dst]);
+                       USE_CYCLES(6);
+                       break;
+               }
+               case 0x1f:      // FGETMAN
+               {
+                       REG_FP[dst] = floatx80_getman(source, &status);
+                       SET_CONDITION_CODES(state, REG_FP[dst]);
                        USE_CYCLES(6);
                        break;
                }
-           case 0x60:          // FSDIVS (JFF) (source has already been converted to floatx80)
+               case 0x64:              // FDDIV
+               case 0x60:              // FSDIV
                case 0x20:              // FDIV
                {
-                       REG_FP[dst] = floatx80_div(REG_FP[dst], source);
-                   SET_CONDITION_CODES(REG_FP[dst]); // JFF
+                       REG_FP[dst] = floatx80_div(REG_FP[dst], source, &status);
+                       //FIXME mame doesn't use SET_CONDITION_CODES here
+                       SET_CONDITION_CODES(state, REG_FP[dst]); // JFF
                        USE_CYCLES(43);
                        break;
                }
+               case 0x21:      // FMOD
+               {
+                       sint8 const mode = status.float_rounding_mode;
+                       status.float_rounding_mode = float_round_to_zero;
+                       uint64_t q;
+                       flag s;
+                       REG_FP[dst] = floatx80_rem(REG_FP[dst], source, &q, &s, &status);
+                       SET_CONDITION_CODES(state, REG_FP[dst]);
+                       status.float_rounding_mode = mode;
+                       USE_CYCLES(43);   // guess
+                       break;
+               }
+               case 0x66:              // FDADD
+               case 0x62:              // FSADD
                case 0x22:              // FADD
                {
-                       REG_FP[dst] = floatx80_add(REG_FP[dst], source);
-                       SET_CONDITION_CODES(REG_FP[dst]);
+                       REG_FP[dst] = floatx80_add(REG_FP[dst], source, &status);
+                       SET_CONDITION_CODES(state, REG_FP[dst]);
                        USE_CYCLES(9);
                        break;
                }
-               case 0x63:              // FSMULS (JFF) (source has already been converted to floatx80)
+               case 0x67:              // FDMUL
+               case 0x63:              // FSMUL
                case 0x23:              // FMUL
                {
-                       REG_FP[dst] = floatx80_mul(REG_FP[dst], source);
-                       SET_CONDITION_CODES(REG_FP[dst]);
+                       REG_FP[dst] = floatx80_mul(REG_FP[dst], source, &status);
+                       SET_CONDITION_CODES(state, REG_FP[dst]);
                        USE_CYCLES(11);
                        break;
                }
+               case 0x24:      // FSGLDIV
+               {
+                       REG_FP[dst] = floatx80_sgldiv(REG_FP[dst], source, &status);
+                       USE_CYCLES(43); //  // ? (value is from FDIV)
+                       break;
+               }
                case 0x25:              // FREM
                {
-                       REG_FP[dst] = floatx80_rem(REG_FP[dst], source);
-                       SET_CONDITION_CODES(REG_FP[dst]);
+                       sint8 const mode = status.float_rounding_mode;
+                       status.float_rounding_mode = float_round_nearest_even;
+                       uint64_t q;
+                       flag s;
+                       REG_FP[dst] = floatx80_rem(REG_FP[dst], source, &q, &s, &status);
+                       SET_CONDITION_CODES(state, REG_FP[dst]);
+                       status.float_rounding_mode = mode;
                        USE_CYCLES(43); // guess
                        break;
                }
-               case 0x28:              // FSUB
+               case 0x26:      // FSCALE
                {
-                       REG_FP[dst] = floatx80_sub(REG_FP[dst], source);
-                       SET_CONDITION_CODES(REG_FP[dst]);
+                       REG_FP[dst] = floatx80_scale(REG_FP[dst], source, &status);
+                       SET_CONDITION_CODES(state, REG_FP[dst]);
+                       USE_CYCLES(46);   // (better?) guess
+                       break;
+               }
+               case 0x27:      // FSGLMUL
+               {
+                       REG_FP[dst] = floatx80_sglmul(REG_FP[dst], source, &status);
+                       SET_CONDITION_CODES(state, REG_FP[dst]);
+                       USE_CYCLES(11); // ? (value is from FMUL)
+                       break;
+               }
+               case 0x6c:              // FDSUB
+               case 0x68:              // FSSUB
+               case 0x28:              // FSUB
+               case 0x29:              // FSUB
+               case 0x2a:              // FSUB
+               case 0x2b:              // FSUB
+               case 0x2c:              // FSUB
+               case 0x2d:              // FSUB
+               case 0x2e:              // FSUB
+               case 0x2f:              // FSUB
+               {
+                       REG_FP[dst] = floatx80_sub(REG_FP[dst], source, &status);
+                       SET_CONDITION_CODES(state, REG_FP[dst]);
                        USE_CYCLES(9);
                        break;
                }
+               case 0x30:      // FSINCOS
+               case 0x31:      // FSINCOS
+               case 0x32:      // FSINCOS
+               case 0x33:      // FSINCOS
+               case 0x34:      // FSINCOS
+               case 0x35:      // FSINCOS
+               case 0x36:      // FSINCOS
+               case 0x37:      // FSINCOS
+               {
+                       REG_FP[dst] = floatx80_cos(source, &status);
+                       REG_FP[w2&7] = floatx80_sin(source, &status);
+                       SET_CONDITION_CODES(state, REG_FP[dst]);
+                       USE_CYCLES(75);
+
+                       break;
+               }
                case 0x38:              // FCMP
+               case 0x39:              // FCMP
+               case 0x3c:              // FCMP
+               case 0x3d:              // FCMP
                {
                        floatx80 res;
-                       res = floatx80_sub(REG_FP[dst], source);
-                       SET_CONDITION_CODES(res);
+                       res = floatx80_sub(REG_FP[dst], source, &status);
+                       SET_CONDITION_CODES(state, res);
                        USE_CYCLES(7);
                        break;
                }
                case 0x3a:              // FTST
+               case 0x3b:              // FTST
+               case 0x3e:              // FTST
+               case 0x3f:              // FTST
                {
                        floatx80 res;
                        res = source;
-                       SET_CONDITION_CODES(res);
+                       SET_CONDITION_CODES(state, res);
                        USE_CYCLES(7);
                        break;
                }
@@ -1296,7 +1745,7 @@ static void fpgen_rm_reg(uint16 w2)
        }
 }
 
-static void fmove_reg_mem(uint16 w2)
+static void fmove_reg_mem(m68ki_cpu_core *state, uint16 w2)
 {
        int ea = REG_IR & 0x3f;
        int src = (w2 >>  7) & 0x7;
@@ -1307,53 +1756,60 @@ static void fmove_reg_mem(uint16 w2)
        {
                case 0:         // Long-Word Integer
                {
-                       sint32 d = (sint32)floatx80_to_int32(REG_FP[src]);
-                       WRITE_EA_32(ea, d);
+                       sint32 d = (sint32)floatx80_to_int32(REG_FP[src], &status);
+                       WRITE_EA_32(state, ea, d);
                        break;
                }
                case 1:         // Single-precision Real
                {
-                       uint32 d = floatx80_to_float32(REG_FP[src]);
-                       WRITE_EA_32(ea, d);
+                       uint32 d = floatx80_to_float32(REG_FP[src], &status);
+                       WRITE_EA_32(state, ea, d);
                        break;
                }
                case 2:         // Extended-precision Real
                {
-                       int mode = (ea >> 3) & 0x7;
-                       int reg = (ea & 0x7);
-                       uint32 di_mode_ea = mode == 5 ? (REG_A[reg]+MAKE_INT_16(m68ki_read_imm_16())) : 0;
-                       WRITE_EA_FPE(mode, reg, REG_FP[src], di_mode_ea);
+                       WRITE_EA_FPE(state, 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(ea, k, REG_FP[src]);
+                       WRITE_EA_PACK(state, ea, k, REG_FP[src]);
                        break;
                }
                case 4:         // Word Integer
                {
-                       WRITE_EA_16(ea, (sint16)floatx80_to_int32(REG_FP[src]));
+                       sint32 value = floatx80_to_int32(REG_FP[src], &status);
+                       if (value > 0x7fff || value < -0x8000 )
+                       {
+                               REG_FPSR |= FPES_OE | FPAE_IOP;
+                       }
+                       WRITE_EA_16(state, ea, (sint16) value);
                        break;
                }
                case 5:         // Double-precision Real
                {
                        uint64 d;
 
-                       d = floatx80_to_float64(REG_FP[src]);
+                       d = floatx80_to_float64(REG_FP[src], &status);
 
-                       WRITE_EA_64(ea, d);
+                       WRITE_EA_64(state, ea, d);
                        break;
                }
                case 6:         // Byte Integer
                {
-                       WRITE_EA_8(ea, (sint8)floatx80_to_int32(REG_FP[src]));
+                       sint32 value = floatx80_to_int32(REG_FP[src], &status);
+                       if (value > 127 || value < -128)
+                       {
+                               REG_FPSR |= FPES_OE | FPAE_IOP;
+                       }
+                       WRITE_EA_8(state, ea, (sint8) value);
                        break;
                }
                case 7:         // Packed-decimal Real with Dynamic K-factor
                {
-                       WRITE_EA_PACK(ea, REG_D[k>>4], REG_FP[src]);
+                       WRITE_EA_PACK(state, ea, REG_D[k >> 4], REG_FP[src]);
                        break;
                }
        }
@@ -1361,34 +1817,107 @@ static void fmove_reg_mem(uint16 w2)
        USE_CYCLES(12);
 }
 
-static void fmove_fpcr(uint16 w2)
+static void fmove_fpcr(m68ki_cpu_core *state, uint16 w2)
 {
        int ea = REG_IR & 0x3f;
        int dir = (w2 >> 13) & 0x1;
-       int reg = (w2 >> 10) & 0x7;
+       int regsel = (w2 >> 10) & 0x7;
+       int mode = (ea >> 3) & 0x7;
 
-       if (dir)        // From system control reg to <ea>
+       if ((mode == 5) || (mode == 6))
        {
-               if (reg & 4) WRITE_EA_32(ea, REG_FPCR);
-               if (reg & 2) WRITE_EA_32(ea, REG_FPSR);
-               if (reg & 1) WRITE_EA_32(ea, REG_FPIAR);
+               uint32 address = 0xffffffff;    // force a bus error if this doesn't get assigned
+
+               if (mode == 5)
+               {
+                       address = EA_AY_DI_32();
+               }
+               else if (mode == 6)
+               {
+                       address = EA_AY_IX_32();
+               }
+
+               if (dir)        // From system control reg to <ea>
+               {
+                       if (regsel & 4) { m68ki_write_32(state, address, REG_FPCR); address += 4; }
+                       if (regsel & 2) { m68ki_write_32(state, address, REG_FPSR); address += 4; }
+                       if (regsel & 1) { m68ki_write_32(state, address, REG_FPIAR); address += 4; }
+               }
+               else            // From <ea> to system control reg
+               {
+                       if (regsel & 4) { REG_FPCR = m68ki_read_32(state, address); address += 4; }
+                       if (regsel & 2) { REG_FPSR = m68ki_read_32(state, address); address += 4; }
+                       if (regsel & 1) { REG_FPIAR = m68ki_read_32(state, address); address += 4; }
+               }
        }
-       else            // From <ea> to system control reg
+       else
        {
-      if (reg & 4) 
+               if (dir)    // From system control reg to <ea>
+               {
+                       if (regsel & 4) WRITE_EA_32(state, ea, REG_FPCR);
+                       if (regsel & 2) WRITE_EA_32(state, ea, REG_FPSR);
+                       if (regsel & 1) WRITE_EA_32(state, ea, REG_FPIAR);
+               }
+               else        // From <ea> to system control reg
                {
-                 REG_FPCR = READ_EA_32(ea);
-                 // JFF: need to update rounding mode from softfloat module
-                 float_rounding_mode = (REG_FPCR >> 4) & 0x3;
+                       if (regsel & 4) REG_FPCR = READ_EA_32(state, ea);
+                       if (regsel & 2) REG_FPSR = READ_EA_32(state, ea);
+                       if (regsel & 1) REG_FPIAR = READ_EA_32(state, ea);
+               }
+       }
+
+       // FIXME: (2011-12-18 ost)
+       // rounding_mode and rounding_precision of softfloat.c should be set according to current fpcr
+       // but:  with this code on Apollo the following programs in /systest/fptest will fail:
+       // 1. Single Precision Whetstone will return wrong results never the less
+       // 2. Vector Test will fault with 00040004: reference to illegal address
+
+       if ((regsel & 4) && dir == 0)
+       {
+               int rnd = (REG_FPCR >> 4) & 3;
+               int prec = (REG_FPCR >> 6) & 3;
+
+//      logerror("m68k_fpsp:fmove_fpcr fpcr=%04x prec=%d rnd=%d\n", m_fpcr, prec, rnd);
+
+#ifdef FLOATX80
+               switch (prec)
+               {
+               case 0: // Extend (X)
+                       status.floatx80_rounding_precision = 80;
+                       break;
+               case 1: // Single (S)
+                       status.floatx80_rounding_precision = 32;
+                       break;
+               case 2: // Double (D)
+                       status.floatx80_rounding_precision = 64;
+                       break;
+               case 3: // Undefined
+                       status.floatx80_rounding_precision = 80;
+                       break;
+               }
+#endif
+
+               switch (rnd)
+               {
+               case 0: // To Nearest (RN)
+                       status.float_rounding_mode = float_round_nearest_even;
+                       break;
+               case 1: // To Zero (RZ)
+                       status.float_rounding_mode = float_round_to_zero;
+                       break;
+               case 2: // To Minus Infinitiy (RM)
+                       status.float_rounding_mode = float_round_down;
+                       break;
+               case 3: // To Plus Infinitiy (RP)
+                       status.float_rounding_mode = float_round_up;
+                       break;
                }
-               if (reg & 2) REG_FPSR = READ_EA_32(ea);
-               if (reg & 1) REG_FPIAR = READ_EA_32(ea);
        }
 
        USE_CYCLES(10);
 }
 
-static void fmovem(uint16 w2)
+static void fmovem(m68ki_cpu_core *state, uint16 w2)
 {
        int i;
        int ea = REG_IR & 0x3f;
@@ -1396,193 +1925,192 @@ static void fmovem(uint16 w2)
        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();
+                       break;
+               case 6:     // (An) + (Xn) + d8
+                       mem_addr= EA_AY_IX_32();
+                       break;
+       }
+
        if (dir)        // From FP regs to mem
        {
                switch (mode)
-       {
-               case 2:         // (JFF): Static register list, postincrement or control addressing mode.     
-           {
-             int imode = (ea >> 3) & 0x7;
-             int reg = (ea & 0x7);
-             int di_mode = imode == 5;       
-             uint32 di_mode_ea = di_mode ? (REG_A[reg]+MAKE_INT_16(m68ki_read_imm_16())) : 0;
-             for (i=0; i < 8; i++)
+               {
+                       case 1: // Dynamic register list, postincrement or control addressing mode.
+                               // FIXME: not really tested, but seems to work
+                               reglist = REG_D[(reglist >> 4) & 7];
+                               /* fall through */
+                               /* no break */
+                       case 0:     // Static register list, predecrement or control addressing mode
                        {
-                         if (reglist & (1 << i))
-                           {
-                             WRITE_EA_FPE(imode,reg, REG_FP[7-i],di_mode_ea);
-                             USE_CYCLES(2);
-                             if (di_mode)
+                               for (i=0; i < 8; i++)
                                {
-                                 di_mode_ea += 12;
+                                       if (reglist & (1 << i))
+                                       {
+                                               switch (ea >> 3)
+                                               {
+                                                       case 5:     // (d16, An)
+                                                       case 6:     // (An) + (Xn) + d8
+                                                               store_extended_float80(state, mem_addr, REG_FP[i]);
+                                                               mem_addr += 12;
+                                                               break;
+                                                       default:
+                                                               WRITE_EA_FPE(state, ea, REG_FP[i]);
+                                                               break;
+                                               }
+
+                                               USE_CYCLES(2);
+                                       }
                                }
-                       }
+                               break;
                        }
-             break;
-                }
-                       case 0:         // Static register list, predecrement addressing mode
+
+                       case 2:         // Static register list, postdecrement or control addressing mode.     
                        {
-             int imode = (ea >> 3) & 0x7;
-             int reg = (ea & 0x7);
-             // the "di_mode_ea" parameter kludge is required here else WRITE_EA_FPE would have
-             // to call EA_AY_DI_32() (that advances PC & reads displacement) each time
-             // when the proper behaviour is 1) read once, 2) increment ea for each matching register
-             // this forces to pre-read the mode (named "imode") so we can decide to read displacement, only once
-             int di_mode = imode == 5;       
-             uint32 di_mode_ea =  di_mode ? (REG_A[reg]+MAKE_INT_16(m68ki_read_imm_16())) : 0;
                                for (i=0; i < 8; i++)
                                {
                                        if (reglist & (1 << i))
                                        {
-                                           WRITE_EA_FPE(imode,reg, REG_FP[i],di_mode_ea);
-                                               USE_CYCLES(2);
-                                           if (di_mode)
+                                               switch (ea >> 3)
                                                {
-                                                 di_mode_ea += 12;
+                                                       case 5:     // (d16, An)
+                                                       case 6:     // (An) + (Xn) + d8
+                                                               store_extended_float80(state, mem_addr, REG_FP[7 - i]);
+                                                               mem_addr += 12;
+                                                               break;
+                                                       default:
+                                                               WRITE_EA_FPE(state, ea, REG_FP[7 - i]);
+                                                               break;
                                                }
+
+                                               USE_CYCLES(2);
                                        }
                                }
                                break;
                        }
 
-                       default:        fatalerror("040fpu0: FMOVEM: mode %d unimplemented at %08X\n", mode, REG_PC-4);
+                       default:        fatalerror("M680x0: 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
+                       case 3: // Dynamic register list, predecrement addressing mode.
+                               // FIXME: not really tested, but seems to work
+                               reglist = REG_D[(reglist >> 4) & 7];
+                               /* fall through */
+                               /* no break */
+                       case 2:         // Static register list, postincrement or control addressing mode
                        {
-                     int imode = (ea >> 3) & 0x7;
-                     int reg = (ea & 0x7);
-                     int di_mode = imode == 5;     
-                     uint32 di_mode_ea = di_mode ? (REG_A[reg]+MAKE_INT_16(m68ki_read_imm_16())) : 0;
                                for (i=0; i < 8; i++)
                                {
                                        if (reglist & (1 << i))
                                        {
-                                               REG_FP[7-i] = READ_EA_FPE(imode,reg,di_mode_ea);
-                                               USE_CYCLES(2);
-                                           if (di_mode)
+                                               switch (ea >> 3)
                                                {
-                                                 di_mode_ea += 12;
+                                                       case 5:     // (d16, An)
+                                                       case 6:     // (An) + (Xn) + d8
+                                                               REG_FP[7-i] = load_extended_float80(state, mem_addr);
+                                                               mem_addr += 12;
+                                                               break;
+                                                       default:
+                                                               REG_FP[7-i] = READ_EA_FPE(state, ea);
+                                                               break;
                                                }
+                                               USE_CYCLES(2);
                                        }
                                }
                                break;
                        }
 
-                       default:        fatalerror("040fpu0: FMOVEM: mode %d unimplemented at %08X\n", mode, REG_PC-4);
+                       default:        fatalerror("M680x0: FMOVEM: mode %d unimplemented at %08X\n", mode, REG_PC-4);
                }
        }
 }
 
-static void fscc()
+static void fscc(m68ki_cpu_core *state)
 {
-  // added by JFF, this seems to work properly now 
-  int condition = OPER_I_16() & 0x3f;
-
-  int cc = TEST_CONDITION(condition);
-  int mode = (REG_IR & 0x38) >> 3;
-  int v = (cc ? 0xff : 0x00);
-  
-  switch (mode)
-  {
-  case 0:  // fscc Dx
-    {
-      // If the specified floating-point condition is true, sets the byte integer operand at
-      // the destination to TRUE (all ones); otherwise, sets the byte to FALSE (all zeros).
-      
-      REG_D[REG_IR & 7] = (REG_D[REG_IR & 7] & 0xFFFFFF00) | v;
-      break;
-    }
-    case 5: // (disp,Ax)
-    {
-    int reg = REG_IR & 7;
-    uint32 ea = REG_A[reg]+MAKE_INT_16(m68ki_read_imm_16());
-    m68ki_write_8(ea,v);
-    break;
-    }
-    
-  default:
-    {
-      // unimplemented see fpu_uae.cpp around line 1300
-      fatalerror("040fpu0: fscc: mode %d not implemented at %08X\n", mode, REG_PC-4);
-    }
-    }
-  USE_CYCLES(7);  // JFF unsure of the number of cycles!!
+       int ea = REG_IR & 0x3f;
+       int condition = (sint16)(OPER_I_16(state));
+
+       WRITE_EA_8(state, ea, TEST_CONDITION(state, condition) ? 0xff : 0);
+       USE_CYCLES(7);  // ???
 }
-static void fbcc16(void)
+static void fbcc16(m68ki_cpu_core *state)
 {
        sint32 offset;
        int condition = REG_IR & 0x3f;
 
-       offset = (sint16)(OPER_I_16());
+       offset = (sint16)(OPER_I_16(state));
 
        // TODO: condition and jump!!!
-       if (TEST_CONDITION(condition))
+       if (TEST_CONDITION(state, condition))
        {
                m68ki_trace_t0();                          /* auto-disable (see m68kcpu.h) */
-               m68ki_branch_16(offset-2);
+               m68ki_branch_16(state, offset - 2);
        }
 
        USE_CYCLES(7);
-       }
+}
 
-static void fbcc32(void)
+static void fbcc32(m68ki_cpu_core *state)
 {
        sint32 offset;
        int condition = REG_IR & 0x3f;
 
-       offset = OPER_I_32();
+       offset = OPER_I_32(state);
 
        // TODO: condition and jump!!!
-       if (TEST_CONDITION(condition))
+       if (TEST_CONDITION(state, condition))
        {
                m68ki_trace_t0();                          /* auto-disable (see m68kcpu.h) */
-               m68ki_branch_32(offset-4);
+               m68ki_branch_32(state, offset - 4);
        }
 
        USE_CYCLES(7);
 }
 
 
-void m68040_fpu_op0()
+void m68040_fpu_op0(m68ki_cpu_core *state)
 {
-       m68ki_cpu.fpu_just_reset = 0;
+       state->fpu_just_reset = 0;
 
        switch ((REG_IR >> 6) & 0x3)
        {
                case 0:
                {
-                       uint16 w2 = OPER_I_16();
+                       uint16 w2 = OPER_I_16(state);
                        switch ((w2 >> 13) & 0x7)
                        {
                                case 0x0:       // FPU ALU FP, FP
                                case 0x2:       // FPU ALU ea, FP
                                {
-                                       fpgen_rm_reg(w2);
+                                       fpgen_rm_reg(state, w2);
                                        break;
                                }
 
                                case 0x3:       // FMOVE FP, ea
                                {
-                                       fmove_reg_mem(w2);
+                                       fmove_reg_mem(state, w2);
                                        break;
                                }
 
                                case 0x4:       // FMOVEM ea, FPCR
                                case 0x5:       // FMOVEM FPCR, ea
                                {
-                                       fmove_fpcr(w2);
+                                       fmove_fpcr(state, w2);
                                        break;
                                }
 
                                case 0x6:       // FMOVEM ea, list
                                case 0x7:       // FMOVEM list, ea
                                {
-                                       fmovem(w2);
+                                       fmovem(state, w2);
                                        break;
                                }
 
@@ -1591,53 +2119,78 @@ void m68040_fpu_op0()
                        break;
                }
 
-           case 1:           // FScc (JFF)
+               case 1:           // FBcc disp16
                {
-                 fscc();
-                 break;
+                       switch ((REG_IR >> 3) & 0x7) {
+                       case 1: // FDBcc
+                               // TODO:
+                               printf("M68kFPU: unimplemented FDBcc main op %d with mode %d at %08X\n", (REG_IR >> 6) & 0x3, (REG_IR >> 3) & 0x7, REG_PC-4);
+                               break;
+                       default: // FScc (?)
+                               fscc(state);
+                               return;
+                       }
+                       fatalerror("M68kFPU: unimplemented main op %d with mode %d at %08X\n", (REG_IR >> 6) & 0x3, (REG_IR >> 3) & 0x7, REG_PC-4);
+                       break;
                }
-               case 2:         // FBcc disp16
+               case 2:     // FBcc disp16
                {
-                       fbcc16();
+                       fbcc16(state);
                        break;
                }
-               case 3:         // FBcc disp32
+               case 3:     // FBcc disp32
                {
-                       fbcc32();
+                       fbcc32(state);
                        break;
                }
 
-      default: fatalerror("M68kFPU: unimplemented main op %d at %08X\n", (m68ki_cpu.ir >> 6) & 0x3,  REG_PC-4);
+               default:    fatalerror("M68kFPU: unimplemented main op %d\n", (REG_IR >> 6) & 0x3);
        }
 }
 
-static void perform_fsave(uint32 addr, int inc)
+static int perform_fsave(m68ki_cpu_core *state, uint32 addr, int inc)
 {
+       if(state->cpu_type & CPU_TYPE_040)
+       {
+               if(inc)
+               {
+                       m68ki_write_32(state, addr, 0x41000000);
+                       return 4 -4;
+               }
+               else
+               {
+                       m68ki_write_32(state, addr, 0x41000000);
+                       return -4 +4;
+               }
+       }
+
        if (inc)
        {
                // 68881 IDLE, version 0x1f
-               m68ki_write_32(addr, 0x1f180000);
-               m68ki_write_32(addr+4, 0);
-               m68ki_write_32(addr+8, 0);
-               m68ki_write_32(addr+12, 0);
-               m68ki_write_32(addr+16, 0);
-               m68ki_write_32(addr+20, 0);
-               m68ki_write_32(addr+24, 0x70000000);
+               m68ki_write_32(state, addr, 0x1f180000);
+               m68ki_write_32(state, addr + 4, 0);
+               m68ki_write_32(state, addr + 8, 0);
+               m68ki_write_32(state, addr + 12, 0);
+               m68ki_write_32(state, addr + 16, 0);
+               m68ki_write_32(state, addr + 20, 0);
+               m68ki_write_32(state, addr + 24, 0x70000000);
+               return 7*4 -4;
        }
        else
        {
-               m68ki_write_32(addr, 0x70000000);
-               m68ki_write_32(addr-4, 0);
-               m68ki_write_32(addr-8, 0);
-               m68ki_write_32(addr-12, 0);
-               m68ki_write_32(addr-16, 0);
-               m68ki_write_32(addr-20, 0);
-               m68ki_write_32(addr-24, 0x1f180000);
+               m68ki_write_32(state, addr + 4 - 4, 0x70000000);
+               m68ki_write_32(state, addr + 4 - 8, 0);
+               m68ki_write_32(state, addr + 4 - 12, 0);
+               m68ki_write_32(state, addr + 4 - 16, 0);
+               m68ki_write_32(state, addr + 4 - 20, 0);
+               m68ki_write_32(state, addr + 4 - 24, 0);
+               m68ki_write_32(state, addr + 4 - 28, 0x1f180000);
+               return -7*4 +4;
        }
 }
 
 // FRESTORE on a NULL frame reboots the FPU - all registers to NaN, the 3 status regs to 0
-static void do_frestore_null()
+static void do_frestore_null(m68ki_cpu_core *state)
 {
        int i;
 
@@ -1652,15 +2205,67 @@ static void do_frestore_null()
 
        // 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!)
-       m68ki_cpu.fpu_just_reset = 1;
+       state->fpu_just_reset = 1;
+}
+
+void m68040_do_fsave(m68ki_cpu_core *state, uint32 addr, int reg, int inc)
+{
+       if (state->fpu_just_reset)
+       {
+               m68ki_write_32(state, addr, 0);
+       }
+       else
+       {
+               // we normally generate an IDLE frame
+               int delta = perform_fsave(state, addr, inc);
+               if(reg != -1)
+                       REG_A[reg] += delta;
+       }
+}
+
+void m68040_do_frestore(m68ki_cpu_core *state, uint32 addr, int reg)
+{
+       uint32 temp = m68ki_read_32(state, addr);
+       // check for nullptr frame
+       if (temp & 0xff000000)
+       {
+               // we don't handle non-nullptr frames
+               state->fpu_just_reset = 0;
+
+               if (reg != -1)
+               {
+                       uint8 m40 = !!(state->cpu_type & CPU_TYPE_040);
+                       // how about an IDLE frame?
+                       if (!m40 && ((temp & 0x00ff0000) == 0x00180000))
+                       {
+                               REG_A[reg] += 7*4-4;
+                       }
+                       else if (m40 && ((temp & 0xffff0000) == 0x41000000))
+                       {
+//                             REG_A[reg] += 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(state);
+       }
 }
 
-void m68040_fpu_op1()
+void m68040_fpu_op1(m68ki_cpu_core *state)
 {
        int ea = REG_IR & 0x3f;
        int mode = (ea >> 3) & 0x7;
        int reg = (ea & 0x7);
-       uint32 addr, temp;
+       uint32 addr;
 
        switch ((REG_IR >> 6) & 0x3)
        {
@@ -1668,40 +2273,56 @@ void m68040_fpu_op1()
                {
                        switch (mode)
                        {
-                               case 3: // (An)+
-                                       addr = EA_AY_PI_32();
+                               case 2: // (An)
+                                       addr = REG_A[reg];
+                                       m68040_do_fsave(state, addr, -1, 1);
+                                       break;
 
-                                       if (m68ki_cpu.fpu_just_reset)
-                                       {
-                                               m68ki_write_32(addr, 0);
-                                       }
-                                       else
-                                       {
-                                               // we normally generate an IDLE frame
-                                               REG_A[reg] += 6*4;
-                                               perform_fsave(addr, 1);
-                                       }
+                               case 3: // (An)+
+                                       addr = EA_AY_PI_32();
+                                       printf("FSAVE mode %d, reg A%d=0x%08x\n",mode,reg,REG_A[reg]);
+                                       m68040_do_fsave(state, addr, -1, 1); // FIXME: -1 was reg
                                        break;
 
                                case 4: // -(An)
-                                       addr = EA_AY_PD_32();
+                                       addr = EA_AY_PD_32();
+                                       m68040_do_fsave(state, addr, reg, 0); // FIXME: -1 was reg
+                                       break;
+                               case 5: // (D16, An)
+                                       addr = EA_AY_DI_16();
+                                       m68040_do_fsave(state, addr, -1, 1);
+                                       break;
 
-                                       if (m68ki_cpu.fpu_just_reset)
-                                       {
-                                               m68ki_write_32(addr, 0);
-                                       }
-                                       else
+                               case 6: // (An) + (Xn) + d8
+                                       addr = EA_AY_IX_16();
+                                       m68040_do_fsave(state, addr, -1, 1);
+                                       break;
+
+                               case 7: //
+                               {
+                                       switch (reg)
                                        {
-                                               // we normally generate an IDLE frame
-                                               REG_A[reg] -= 6*4;
-                                               perform_fsave(addr, 0);
+                                               case 1:     // (abs32)
+                                               {
+                                                       addr = EA_AL_32();
+                                                       m68040_do_fsave(state, addr, -1, 1);
+                                                       break;
+                                               }
+                                               case 2:     // (d16, PC)
+                                               {
+                                                       addr = EA_PCDI_16();
+                                                       m68040_do_fsave(state, addr, -1, 1);
+                                                       break;
+                                               }
+                                               default:
+                                                       fatalerror("M68kFPU: FSAVE unhandled mode %d reg %d at %x\n", mode, reg, REG_PC);
                                        }
-                                       break;
+                               }
+                               break;
 
                                default:
                                        fatalerror("M68kFPU: FSAVE unhandled mode %d reg %d at %x\n", mode, reg, REG_PC);
                        }
-                       break;
                }
                break;
 
@@ -1711,59 +2332,80 @@ void m68040_fpu_op1()
                        {
                                case 2: // (An)
                                        addr = REG_A[reg];
-                                       temp = m68ki_read_32(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
-                                               m68ki_cpu.fpu_just_reset = 0;
-                                       }
-                                       else
-                                       {
-                                               do_frestore_null();
-                                       }
+                                       m68040_do_frestore(state, addr, -1);
                                        break;
 
                                case 3: // (An)+
-                                       addr = EA_AY_PI_32();
-                                       temp = m68ki_read_32(addr);
+                                       addr = EA_AY_PI_32();
+                                       m68040_do_frestore(state, addr, reg);
+                                       break;
 
-                                       // check for NULL frame
-                                       if (temp & 0xff000000)
-                                       {
-                                               m68ki_cpu.fpu_just_reset = 0;
+                               case 5: // (D16, An)
+                                       addr = EA_AY_DI_16();
+                                       m68040_do_frestore(state, addr, -1);
+                                       break;
 
-                                               // how about an IDLE frame?
-                                               if ((temp & 0x00ff0000) == 0x00180000)
-                                               {
-                                                       REG_A[reg] += 6*4;
-                                               } // check UNIMP
-                                               else if ((temp & 0x00ff0000) == 0x00380000)
+                               case 6: // (An) + (Xn) + d8
+                                       addr = EA_AY_IX_16();
+                                       m68040_do_frestore(state, addr, -1);
+                                       break;
+
+                               case 7: //
+                               {
+                                       switch (reg)
+                                       {
+                                               case 1:     // (abs32)
                                                {
-                                                       REG_A[reg] += 14*4;
-                                               } // check BUSY
-                                               else if ((temp & 0x00ff0000) == 0x00b40000)
+                                                       addr = EA_AL_32();
+                                                       m68040_do_frestore(state, addr, -1);
+                                                       break;
+                                               }
+                                               case 2:     // (d16, PC)
                                                {
-                                                       REG_A[reg] += 45*4;
+                                                       addr = EA_PCDI_16();
+                                                       m68040_do_frestore(state, addr, -1);
+                                                       break;
                                                }
+                                               default:
+                                                       fatalerror("M68kFPU: FRESTORE unhandled mode %d reg %d at %x\n", mode, reg, REG_PC);
                                        }
-                                       else
-                                       {
-                                               do_frestore_null();
-                                       }
-                                       break;
+                               }
+                               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", (REG_IR >> 6) & 0x3, REG_PC-2);
+               default:    fatalerror("m68040_fpu_op1: unimplemented op %d at %08X\n", (REG_IR >> 6) & 0x3, REG_PC-2);
        }
 }
 
+void m68881_ftrap(m68ki_cpu_core *state)
+{
+       uint16 w2  = OPER_I_16(state);
+
+       // now check the condition
+       if (TEST_CONDITION(state, w2 & 0x3f))
+       {
+               // trap here
+               m68ki_exception_trap(state, EXCEPTION_TRAPV);
+       }
+       else    // fall through, requires eating the operand
+       {
+               switch (REG_IR & 0x7)
+               {
+                       case 2: // word operand
+                               OPER_I_16(state);
+                               break;
 
+                       case 3: // long word operand
+                               OPER_I_32(state);
+                               break;
 
+                       case 4: // no operand
+                               break;
+               }
+       }
+}