]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
CPU tester FPU updates/fixes. Don't set flags if exception, unimplemented instruction...
authorToni Wilen <twilen@winuae.net>
Sat, 11 Apr 2020 07:32:21 +0000 (10:32 +0300)
committerToni Wilen <twilen@winuae.net>
Sat, 11 Apr 2020 07:32:21 +0000 (10:32 +0300)
fpp.cpp

diff --git a/fpp.cpp b/fpp.cpp
index be0eee811775abaf38779b3af2cf59080906d610..a7b369cbb4d7811a16a5790ed6e11389d889f2ee 100644 (file)
--- a/fpp.cpp
+++ b/fpp.cpp
@@ -375,7 +375,7 @@ static bool fp_exception_pending(bool pre)
        if (support_exceptions && !jit_fpu()) {
                if (regs.fp_exp_pend) {
                        if (warned > 0) {
-                               write_log (_T("FPU ARITHMETIC EXCEPTION (%d)\n"), regs.fp_exp_pend);
+                               write_log (_T("FPU ARITHMETIC EXCEPTION (%d) PC=%08x\n"), regs.fp_exp_pend, M68K_GETPC);
                        }
                        regs.fpu_exp_pre = pre;
                        Exception(regs.fp_exp_pend);
@@ -387,7 +387,11 @@ static bool fp_exception_pending(bool pre)
        // no arithmetic exceptions pending, check for unimplemented datatype
        if (regs.fp_unimp_pend) {
                if (warned > 0) {
-                       write_log (_T("FPU unimplemented datatype exception (%s)\n"), pre ? _T("pre") : _T("mid/post"));
+                       write_log (_T("FPU unimplemented datatype exception (%s) PC=%08x\n"), pre ? _T("pre") : _T("mid/post"), M68K_GETPC);
+               }
+               if (fpu_mmu_fixup) {
+                       m68k_areg(regs, mmufixup[0].reg) = mmufixup[0].value;
+                       mmufixup[0].reg = -1;
                }
                regs.fpu_exp_pre = pre;
                Exception(55);
@@ -404,6 +408,10 @@ static void fp_unimp_instruction_exception_pending(void)
                if (warned > 0) {
                        write_log (_T("FPU UNIMPLEMENTED INSTRUCTION/FPU DISABLED EXCEPTION PC=%08x\n"), M68K_GETPC);
                }
+               if (fpu_mmu_fixup) {
+                       m68k_areg(regs, mmufixup[0].reg) = mmufixup[0].value;
+                       mmufixup[0].reg = -1;
+               }
                regs.fpu_exp_pre = true;
                Exception(11);
                regs.fp_unimp_ins = false;
@@ -429,12 +437,11 @@ static uae_u32 fpsr_get_vector(uae_u32 exception)
        return 0;
 }
 
-static void fpsr_check_arithmetic_exception(uae_u32 mask, fpdata *src, uae_u32 opcode, uae_u16 extra, uae_u32 ea)
+static bool fpsr_check_arithmetic_exception(uae_u32 mask, fpdata *src, uae_u32 opcode, uae_u16 extra, uae_u32 ea, bool easet)
 {
        if (!support_exceptions || jit_fpu())
-               return;
+               return false;
 
-       bool nonmaskable;
        uae_u32 exception;
        // Any exception status bit and matching exception enable bits set?
        exception = regs.fpsr & regs.fpcr & 0xff00;
@@ -445,10 +452,10 @@ static void fpsr_check_arithmetic_exception(uae_u32 mask, fpdata *src, uae_u32 o
 
        if (exception) {
                regs.fp_exp_pend = fpsr_get_vector(exception);
-               nonmaskable = (regs.fp_exp_pend != fpsr_get_vector(regs.fpsr & regs.fpcr));
+               bool nonmaskable = (regs.fp_exp_pend != fpsr_get_vector(regs.fpsr & regs.fpcr));
                if (warned > 0) {
-                       write_log(_T("FPU %s arithmetic exception pending: FPSR: %08x, FPCR: %04x (vector: %d)!\n"),
-                               nonmaskable ? _T("nonmaskable") : _T(""), regs.fpsr, regs.fpcr, regs.fp_exp_pend);
+                       write_log(_T("FPU %s arithmetic exception pending: FPSR: %08x, FPCR: %04x (vector: %d) PC=%08x!\n"),
+                               nonmaskable ? _T("nonmaskable") : _T(""), regs.fpsr, regs.fpcr, regs.fp_exp_pend, M68K_GETPC);
 #if EXCEPTION_FPP == 0
                        warned--;
 #endif 
@@ -457,11 +464,12 @@ static void fpsr_check_arithmetic_exception(uae_u32 mask, fpdata *src, uae_u32 o
                if (!support_exceptions || jit_fpu()) {
                        // log message and exit
                        regs.fp_exp_pend = 0;
-                       return;
+                       return false;
                }
 
                regs.fp_opword = opcode;
                regs.fp_ea = ea;
+               regs.fp_ea_set = easet;
 
                // data for FSAVE stack frame
                fpdata eo;
@@ -568,17 +576,28 @@ static void fpsr_check_arithmetic_exception(uae_u32 mask, fpdata *src, uae_u32 o
                                }
                        }
                }
+               return nonmaskable;
        }
+       return false;
 }
 
-static void fpsr_set_result(fpdata *result)
+// Flag that is always set immediately.
+static void fpsr_set_result_always(fpdata *result)
 {
 #ifdef JIT
        regs.fp_result = *result;
 #endif
-       // condition code byte
        regs.fpsr &= 0x00fffff8; // clear cc
        fpp_is_init(result);
+       if (fpp_is_neg(result)) {
+               regs.fpsr |= FPSR_CC_N;
+       }
+}
+
+// Flags that are set if instruction didn't generate exception.
+static void fpsr_set_result(fpdata *result)
+{
+       // condition code byte
        if (fpp_is_nan(result)) {
                regs.fpsr |= FPSR_CC_NAN;
        } else if (fpp_is_zero(result)) {
@@ -586,8 +605,6 @@ static void fpsr_set_result(fpdata *result)
        } else if (fpp_is_infinity(result)) {
                regs.fpsr |= FPSR_CC_I;
        }
-       if (fpp_is_neg(result))
-               regs.fpsr |= FPSR_CC_N;
 }
 static void fpsr_clear_status(void)
 {
@@ -598,6 +615,17 @@ static void fpsr_clear_status(void)
        fpp_clear_status();
 }
 
+static void updateaccrued(void)
+{
+       // update accrued exception byte
+       if (regs.fpsr & (FPSR_BSUN | FPSR_SNAN | FPSR_OPERR))
+               regs.fpsr |= FPSR_AE_IOP;  // IOP = BSUN || SNAN || OPERR
+       if ((regs.fpsr & FPSR_UNFL) && (regs.fpsr & FPSR_INEX2))
+               regs.fpsr |= FPSR_AE_UNFL; // UNFL = UNFL && INEX2
+       if (regs.fpsr & FPSR_DZ)
+               regs.fpsr |= FPSR_AE_DZ;   // DZ = DZ
+}
+
 static uae_u32 fpsr_make_status(void)
 {
        uae_u32 exception;
@@ -605,26 +633,24 @@ static uae_u32 fpsr_make_status(void)
        // get external status
        fpp_get_status(&regs.fpsr);
        
-       // update accrued exception byte
-       if (regs.fpsr & (FPSR_BSUN | FPSR_SNAN | FPSR_OPERR))
-               regs.fpsr |= FPSR_AE_IOP;  // IOP = BSUN || SNAN || OPERR
        if (regs.fpsr & FPSR_OVFL)
                regs.fpsr |= FPSR_AE_OVFL; // OVFL = OVFL
-       if ((regs.fpsr & FPSR_UNFL) && (regs.fpsr & FPSR_INEX2))
-               regs.fpsr |= FPSR_AE_UNFL; // UNFL = UNFL && INEX2
-       if (regs.fpsr & FPSR_DZ)
-               regs.fpsr |= FPSR_AE_DZ;   // DZ = DZ
        if (regs.fpsr & (FPSR_OVFL | FPSR_INEX2 | FPSR_INEX1))
                regs.fpsr |= FPSR_AE_INEX; // INEX = INEX1 || INEX2 || OVFL
-       
-       if (!support_exceptions || jit_fpu())
+
+       if (!support_exceptions || jit_fpu()) {
+               updateaccrued();
                return 0;
+       }
 
        // return exceptions that interrupt calculation
        exception = regs.fpsr & regs.fpcr & (FPSR_SNAN | FPSR_OPERR | FPSR_DZ);
-       if (currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented)
+       if (currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
                exception |= regs.fpsr & (FPSR_OVFL | FPSR_UNFL);
-
+       }
+       if (!exception) {
+               updateaccrued();
+       }
        return exception;
 }
 
@@ -861,6 +887,7 @@ bool fpu_get_constant(fpdata *fpd, int cr)
                                fpp_to_exten_fmovem(fpd, f[0], f[1], f[2]);
                        }
 
+                       fpsr_set_result_always(fpd);
                        fpsr_set_result(fpd);
                        regs.fpsr |= sr;
                        return false;
@@ -884,6 +911,7 @@ bool fpu_get_constant(fpdata *fpd, int cr)
        if (prec >= 2)
                fpp_round64(fpd);
        
+       fpsr_set_result_always(fpd);
        fpsr_set_result(fpd);
 
        return true;
@@ -915,7 +943,7 @@ static void fpu_format_error (void)
 }
 #endif
 
-static void fp_unimp_instruction(uae_u16 opcode, uae_u16 extra, uae_u32 ea, uaecptr oldpc, fpdata *src, int reg, int size)
+static void fp_unimp_instruction(uae_u16 opcode, uae_u16 extra, uae_u32 ea, bool easet, uaecptr oldpc, fpdata *src, int reg, int size)
 {
        if ((extra & 0x7f) == 4) // FSQRT 4->5
                extra |= 1;
@@ -951,6 +979,7 @@ static void fp_unimp_instruction(uae_u16 opcode, uae_u16 extra, uae_u32 ea, uaec
        }
        
        regs.fp_ea = ea;
+       regs.fp_ea_set = easet;
        regs.fp_unimp_ins = true;
        fp_unimp_instruction_exception_pending();
 
@@ -958,7 +987,7 @@ static void fp_unimp_instruction(uae_u16 opcode, uae_u16 extra, uae_u32 ea, uaec
 
 }
 
-static void fp_unimp_datatype(uae_u16 opcode, uae_u16 extra, uae_u32 ea, uaecptr oldpc, fpdata *src, uae_u32 *packed)
+static void fp_unimp_datatype(uae_u16 opcode, uae_u16 extra, uae_u32 ea, bool easet, uaecptr oldpc, fpdata *src, uae_u32 *packed)
 {
        uae_u32 reg = (extra >> 7) & 7;
        uae_u32 size = (extra >> 10) & 7;
@@ -966,6 +995,7 @@ static void fp_unimp_datatype(uae_u16 opcode, uae_u16 extra, uae_u32 ea, uaecptr
 
        regs.fp_opword = opcode;
        regs.fp_ea = ea;
+       regs.fp_ea_set = easet;
        regs.fp_unimp_pend = packed ? 2 : 1;
 
        if((extra & 0x7f) == 4) // FSQRT 4->5
@@ -1027,28 +1057,39 @@ static void fp_unimp_datatype(uae_u16 opcode, uae_u16 extra, uae_u32 ea, uaecptr
        regs.fp_exception = true;
 }
 
-static void fpu_op_illg(uae_u16 opcode, uae_u32 ea, uaecptr oldpc)
+static void fpu_op_illg(uae_u16 opcode, uae_u32 ea, bool easet, uaecptr oldpc)
 {
        if ((currprefs.cpu_model == 68060 && (currprefs.fpu_model == 0 || (regs.pcr & 2)))
                || (currprefs.cpu_model == 68040 && currprefs.fpu_model == 0)) {
                        regs.fp_unimp_ins  = true;
                        regs.fp_ea = ea;
+                       regs.fp_ea_set = easet;
                        fp_unimp_instruction_exception_pending();
                        return;
        }
        regs.fp_exception = true;
        m68k_setpc (oldpc);
-       op_illg (opcode);
+       op_illg(opcode);
 }
 
-static void fpu_noinst (uae_u16 opcode, uaecptr pc)
+static void fpu_unimpl(uae_u16 opcode, uaecptr pc)
+{
+#if EXCEPTION_FPP
+       write_log(_T("Unknown FPU instruction %04X %08X\n"), opcode, pc);
+#endif
+       regs.fp_exception = true;
+       m68k_setpc(pc);
+       Exception(55);
+}
+
+static void fpu_noinst(uae_u16 opcode, uaecptr pc)
 {
 #if EXCEPTION_FPP
        write_log (_T("Unknown FPU instruction %04X %08X\n"), opcode, pc);
 #endif
        regs.fp_exception = true;
-       m68k_setpc (pc);
-       op_illg (opcode);
+       m68k_setpc(pc);
+       op_illg(opcode);
 }
 
 static bool if_no_fpu(void)
@@ -1056,68 +1097,185 @@ static bool if_no_fpu(void)
        return (regs.pcr & 2) || currprefs.fpu_model <= 0;
 }
 
-static bool fault_if_no_fpu (uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc)
+static bool fault_if_no_fpu (uae_u16 opcode, uae_u16 extra, uaecptr ea, bool easet, uaecptr oldpc)
 {
        if (if_no_fpu()) {
 #if EXCEPTION_FPP
                write_log (_T("no FPU: %04X-%04X PC=%08X\n"), opcode, extra, oldpc);
 #endif
-#if SUPPORT_MMU
                if (fpu_mmu_fixup) {
                        m68k_areg (regs, mmufixup[0].reg) = mmufixup[0].value;
                        mmufixup[0].reg = -1;
                }
-#endif
-               fpu_op_illg(opcode, ea, oldpc);
+               fpu_op_illg(opcode, ea, easet, oldpc);
                return true;
        }
        return false;
 }
 
-static bool fault_if_unimplemented_680x0 (uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, fpdata *src, int reg)
+static bool fault_if_nonexisting_opmode(uae_u16 opcode, uae_u16 extra, uaecptr oldpc)
 {
-       if (fault_if_no_fpu (opcode, extra, ea, oldpc))
+       uae_u16 v = extra & 0x7f;
+
+       // if non-existing FPU instruction (opmode): exit immediately and generate normal frame 0 exception 11.
+
+       if (currprefs.fpu_model == 68881 || currprefs.fpu_model == 68882) {
+               if (currprefs.fpu_no_unimplemented) {
+                       if (v >= 0x40) {
+                               fpu_noinst(opcode, oldpc);
+                               return true;
+                       }
+                       return false;
+               }
+               // 6888x undocumented but existing opmodes
+               switch (v)
+               {
+               case 0x05:
+               case 0x07:
+               case 0x0b:
+               case 0x13:
+               case 0x17:
+               case 0x1b:
+               case 0x29:
+               case 0x2a:
+               case 0x2b:
+               case 0x2c:
+               case 0x2d:
+               case 0x2e:
+               case 0x2f:
+               case 0x39:
+               case 0x3b:
+               case 0x3c:
+               case 0x3d:
+               case 0x3e:
+               case 0x3f:
+                       return false;
+               }
+       }
+
+       switch (v)
+       {
+               case 0x05:
+               case 0x07:
+               case 0x0b:
+               case 0x13:
+               case 0x17:
+               case 0x1b:
+               case 0x29:
+               case 0x2a:
+               case 0x2b:
+               case 0x2c:
+               case 0x2d:
+               case 0x2e:
+               case 0x2f:
+               case 0x39:
+               case 0x3b:
+               case 0x3c:
+               case 0x3d:
+               case 0x3e:
+               case 0x3f:
+               case 0x42:
+               case 0x43:
+               case 0x46:
+               case 0x47:
+               case 0x48:
+               case 0x49:
+               case 0x4a:
+               case 0x4b:
+               case 0x4c:
+               case 0x4d:
+               case 0x4e:
+               case 0x4f:
+               case 0x50:
+               case 0x51:
+               case 0x52:
+               case 0x53:
+               case 0x54:
+               case 0x55:
+               case 0x56:
+               case 0x57:
+               case 0x59:
+               case 0x5b:
+               case 0x5d:
+               case 0x5f:
+               case 0x61:
+               case 0x65:
+               case 0x69:
+               case 0x6a:
+               case 0x6b:
+               case 0x6d:
+               case 0x6e:
+               case 0x6f:
+               case 0x70:
+               case 0x71:
+               case 0x72:
+               case 0x73:
+               case 0x74:
+               case 0x75:
+               case 0x76:
+               case 0x77:
+                       fpu_noinst(opcode, oldpc);
+                       return true;
+               case 0x78:
+               case 0x79:
+               case 0x7a:
+               case 0x7b:
+               case 0x7c:
+               case 0x7d:
+               case 0x7e:
+               case 0x7f:
+                       // Unexpected, isn't it?!
+                       Exception(4);
+                       return true;
+               break;
+       }
+       return false;
+}
+
+static bool fault_if_unimplemented_680x0 (uae_u16 opcode, uae_u16 extra, uaecptr ea, bool easet, uaecptr oldpc, fpdata *src, int reg)
+{
+       if (fault_if_no_fpu (opcode, extra, ea, easet, oldpc))
                return true;
        if (currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
                if ((extra & (0x8000 | 0x2000)) != 0)
                        return false;
                if ((extra & 0xfc00) == 0x5c00) {
                        // FMOVECR
-                       fp_unimp_instruction(opcode, extra, ea, oldpc, src, reg, -1);
+                       fp_unimp_instruction(opcode, extra, ea, easet, oldpc, src, reg, -1);
                        return true;
                }
                uae_u16 v = extra & 0x7f;
-               /* 68040/68060 only variants. 6888x = F-line exception. */
+               /* >=0x040 are 68040/68060 only variants. 6888x = F-line exception. */
                switch (v)
                {
                        case 0x00: /* FMOVE */
-                       case 0x40: /* FSMOVE */
-                       case 0x44: /* FDMOVE */
                        case 0x04: /* FSQRT */
+                       case 0x18: /* FABS */
+                       case 0x1a: /* FNEG */
+                       case 0x20: /* FDIV */
+                       case 0x22: /* FADD */
+                       case 0x23: /* FMUL */
+                       case 0x24: /* FSGLDIV */
+                       case 0x27: /* FSGLMUL */
+                       case 0x28: /* FSUB */
+                       case 0x38: /* FCMP */
+                       case 0x3a: /* FTST */
+                       case 0x40: /* FSMOVE */
                        case 0x41: /* FSSQRT */
+                       case 0x44: /* FDMOVE */
                        case 0x45: /* FDSQRT */
-                       case 0x18: /* FABS */
                        case 0x58: /* FSABS */
                        case 0x5c: /* FDABS */
-                       case 0x1a: /* FNEG */
                        case 0x5a: /* FSNEG */
                        case 0x5e: /* FDNEG */
-                       case 0x20: /* FDIV */
                        case 0x60: /* FSDIV */
-                       case 0x64: /* FDDIV */
-                       case 0x22: /* FADD */
                        case 0x62: /* FSADD */
-                       case 0x66: /* FDADD */
-                       case 0x23: /* FMUL */
                        case 0x63: /* FSMUL */
+                       case 0x64: /* FDDIV */
+                       case 0x66: /* FDADD */
                        case 0x67: /* FDMUL */
-                       case 0x24: /* FSGLDIV */
-                       case 0x27: /* FSGLMUL */
-                       case 0x28: /* FSUB */
                        case 0x68: /* FSSUB */
                        case 0x6c: /* FDSUB */
-                       case 0x38: /* FCMP */
-                       case 0x3a: /* FTST */
                                return false;
                        case 0x01: /* FINT */
                        case 0x03: /* FINTRZ */
@@ -1126,7 +1284,7 @@ static bool fault_if_unimplemented_680x0 (uae_u16 opcode, uae_u16 extra, uaecptr
                                return false;
                        }
                        default:
-                       fp_unimp_instruction(opcode, extra, ea, oldpc, src, reg, -1);
+                       fp_unimp_instruction(opcode, extra, ea, easet, oldpc, src, reg, -1);
                        return true;
                }
        }
@@ -1184,6 +1342,28 @@ static bool fault_if_unimplemented_6888x (uae_u16 opcode, uae_u16 extra, uaecptr
                        case 0x37: /* FSINCOS */
                        case 0x38: /* FCMP */
                        case 0x3a: /* FTST */
+
+                       // 6888x invalid opmodes execute existing FPU instruction.
+                       // Only opmodes 0x40-0x7f generate F-line exception.
+                       case 0x05:
+                       case 0x07:
+                       case 0x0b:
+                       case 0x13:
+                       case 0x17:
+                       case 0x1b:
+                       case 0x29:
+                       case 0x2a:
+                       case 0x2b:
+                       case 0x2c:
+                       case 0x2d:
+                       case 0x2e:
+                       case 0x2f:
+                       case 0x39:
+                       case 0x3b:
+                       case 0x3c:
+                       case 0x3d:
+                       case 0x3e:
+                       case 0x3f:
                                return false;
                        default:
                                fpu_noinst (opcode, oldpc);
@@ -1202,14 +1382,15 @@ static bool fault_if_60 (void)
        return false;
 }
 
-static bool fault_if_no_fpu_u (uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc)
+static bool fault_if_no_fpu_u (uae_u16 opcode, uae_u16 extra, uaecptr ea, bool easet, uaecptr oldpc)
 {
-       if (fault_if_no_fpu (opcode, extra, ea, oldpc))
+       if (fault_if_no_fpu (opcode, extra, ea, easet, oldpc))
                return true;
        if (currprefs.cpu_model == 68060 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
                // 68060 FTRAP, FDBcc or FScc are not implemented.
                regs.fp_unimp_ins = true;
                regs.fp_ea = ea;
+               regs.fp_ea_set = easet;
                fp_unimp_instruction_exception_pending();
                return true;
        }
@@ -1262,7 +1443,7 @@ static void fpu_null (void)
 }
 
 // 68040/060 does not support denormals
-static bool normalize_or_fault_if_no_denormal_support(uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, fpdata *src)
+static bool normalize_or_fault_if_no_denormal_support(uae_u16 opcode, uae_u16 extra, uaecptr ea, bool easet, uaecptr oldpc, fpdata *src)
 {
        if (!support_denormals)
                return false;
@@ -1272,7 +1453,7 @@ static bool normalize_or_fault_if_no_denormal_support(uae_u16 opcode, uae_u16 ex
                        if (fpp_is_zero(src)) {
                                fpp_normalize(src); // 68040/060 can only fix unnormal zeros
                        } else {
-                               fp_unimp_datatype(opcode, extra, ea, oldpc, src, NULL);
+                               fp_unimp_datatype(opcode, extra, ea, easet, oldpc, src, NULL);
                                return true;
                        }
                } else {
@@ -1281,7 +1462,7 @@ static bool normalize_or_fault_if_no_denormal_support(uae_u16 opcode, uae_u16 ex
        }
        return false;
 }
-static bool normalize_or_fault_if_no_denormal_support_dst(uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, fpdata *dst, fpdata *src)
+static bool normalize_or_fault_if_no_denormal_support_dst(uae_u16 opcode, uae_u16 extra, uaecptr ea, bool easet, uaecptr oldpc, fpdata *dst, fpdata *src)
 {
        if (!support_denormals)
                return false;
@@ -1291,7 +1472,7 @@ static bool normalize_or_fault_if_no_denormal_support_dst(uae_u16 opcode, uae_u1
                        if (fpp_is_zero(dst)) {
                                fpp_normalize(dst); // 68040/060 can only fix unnormal zeros
                        } else {
-                               fp_unimp_datatype(opcode, extra, ea, oldpc, src, NULL);
+                               fp_unimp_datatype(opcode, extra, ea, easet, oldpc, src, NULL);
                                return true;
                        }
                } else {
@@ -1302,22 +1483,22 @@ static bool normalize_or_fault_if_no_denormal_support_dst(uae_u16 opcode, uae_u1
 }
 
 // 68040/060 does not support packed decimal format
-static bool fault_if_no_packed_support(uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, fpdata *src, uae_u32 *packed)
+static bool fault_if_no_packed_support(uae_u16 opcode, uae_u16 extra, uaecptr ea, bool easet, uaecptr oldpc, fpdata *src, uae_u32 *packed)
 {
        if (currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
-               fp_unimp_datatype(opcode, extra, ea, oldpc, src, packed);
+               fp_unimp_datatype(opcode, extra, ea, easet, oldpc, src, packed);
                return true;
        }
        return false;
  }
 
 // 68040 does not support move to integer format
-static bool fault_if_68040_integer_nonmaskable(uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, fpdata *src)
+static bool fault_if_68040_integer_nonmaskable(uae_u16 opcode, uae_u16 extra, uaecptr ea, bool easet, uaecptr oldpc, fpdata *src)
 {
        if (currprefs.cpu_model == 68040 && currprefs.fpu_model && currprefs.fpu_mode > 0) {
                fpsr_make_status();
                if (regs.fpsr & (FPSR_SNAN | FPSR_OPERR)) {
-                       fpsr_check_arithmetic_exception(FPSR_SNAN | FPSR_OPERR, src, opcode, extra, ea);
+                       fpsr_check_arithmetic_exception(FPSR_SNAN | FPSR_OPERR, src, opcode, extra, ea, easet);
                        fp_exception_pending(false); // post
                        return true;
                }
@@ -1325,20 +1506,21 @@ static bool fault_if_68040_integer_nonmaskable(uae_u16 opcode, uae_u16 extra, ua
        return false;
 }
 
-static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr oldpc, uae_u32 *adp)
+static int get_fp_value(uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr oldpc, uae_u32 *adp, bool *adsetp)
 {
        int size, mode, reg;
        uae_u32 ad = 0;
+       bool adset = false;
        static const int sz1[8] = { 4, 4, 12, 12, 2, 8, 1, 0 };
        static const int sz2[8] = { 4, 4, 12, 12, 2, 8, 2, 0 };
        uae_u32 exts[3];
        int doext = 0;
 
        if (!(extra & 0x4000)) {
-               if (fault_if_no_fpu (opcode, extra, 0, oldpc))
+               if (fault_if_no_fpu (opcode, extra, 0, false, oldpc))
                        return -1;
                *src = regs.fp[(extra >> 10) & 7];
-               normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, src);
+               normalize_or_fault_if_no_denormal_support(opcode, extra, 0, false, oldpc, src);
                return 1;
        }
        mode = (opcode >> 3) & 7;
@@ -1347,7 +1529,7 @@ static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr old
 
        switch (mode) {
                case 0: // Dn
-                       if ((size == 0 || size == 1 ||size == 4 || size == 6) && fault_if_no_fpu (opcode, extra, 0, oldpc))
+                       if ((size == 0 || size == 1 ||size == 4 || size == 6) && fault_if_no_fpu (opcode, extra, 0, false, oldpc))
                                return -1;
                        switch (size)
                        {
@@ -1362,8 +1544,15 @@ static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr old
                                        break;
                                case 1:
                                        fpp_to_single (src, m68k_dreg (regs, reg));
-                                       normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, src);
+                                       normalize_or_fault_if_no_denormal_support(opcode, extra, 0, false, oldpc, src);
                                        break;
+                               case 3: // packed
+                                       if (currprefs.cpu_model == 68060) {
+                                               uae_u32 wrd[3];
+                                               if (fault_if_no_packed_support(opcode, extra, 0, false, oldpc, NULL, wrd))
+                                                       return 1;
+                                       }
+                                       return 0;
                                default:
                                        return 0;
                        }
@@ -1372,51 +1561,58 @@ static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr old
                        return 0;
                case 2: // (An)
                        ad = m68k_areg (regs, reg);
+                       adset = true;
                        break;
                case 3: // (An)+
                        // Also needed by fault_if_no_fpu 
-#if SUPPORT_MMU
                        mmufixup[0].reg = reg;
                        mmufixup[0].value = m68k_areg (regs, reg);
                        fpu_mmu_fixup = true;
-#endif
                        ad = m68k_areg (regs, reg);
+                       adset = true;
                        m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size];
                        break;
                case 4: // -(An)
                        // Also needed by fault_if_no_fpu 
-#if SUPPORT_MMU
                        mmufixup[0].reg = reg;
                        mmufixup[0].value = m68k_areg (regs, reg);
                        fpu_mmu_fixup = true;
-#endif
                        m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size];
                        ad = m68k_areg (regs, reg);
+                       adset = true;
                        // 68060 no fpu -(an): EA points to -4, not -12 if extended precision
-                       if (currprefs.cpu_model == 68060 && if_no_fpu() && sz1[size] == 12)
+                       // or unsupported packed datatype.
+                       if (currprefs.cpu_model == 68060 && ((if_no_fpu() && sz1[size] == 12) || size == 3)) {
                                ad += 8;
+                       }
                        break;
                case 5: // (d16,An)
                        ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_cp_next_iword ();
+                       adset = true;
                        break;
                case 6: // (d8,An,Xn)+
                        ad = x_cp_get_disp_ea_020 (m68k_areg (regs, reg), 0);
+                       adset = true;
                        break;
                case 7:
                        switch (reg)
                        {
                                case 0: // (xxx).W
                                        ad = (uae_s32) (uae_s16) x_cp_next_iword ();
+                                       adset = true;
                                        break;
                                case 1: // (xxx).L
                                        ad = x_cp_next_ilong ();
+                                       adset = true;
                                        break;
                                case 2: // (d16,PC)
                                        ad = m68k_getpc ();
                                        ad += (uae_s32) (uae_s16) x_cp_next_iword ();
+                                       adset = true;
                                        break;
                                case 3: // (d8,PC,Xn)+
                                        ad = x_cp_get_disp_ea_020 (m68k_getpc (), 0);
+                                       adset = true;
                                        break;
                                case 4: // #imm
                                        doext = 1;
@@ -1453,15 +1649,16 @@ static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr old
        }
 
 
-       if (fault_if_no_fpu (opcode, extra, ad, oldpc))
+       if (fault_if_no_fpu (opcode, extra, ad, adset, oldpc))
                return -1;
 
        *adp = ad;
+       *adsetp = adset;
        uae_u32 adold = ad;
 
        if (currprefs.fpu_model == 68060) {
                // Skip if 68040 because FSAVE frame can store both src and dst
-               if (fault_if_unimplemented_680x0(opcode, extra, ad, oldpc, src, -1)) {
+               if (fault_if_unimplemented_680x0(opcode, extra, ad, adset, oldpc, src, -1)) {
                        return -1;
                }
        }
@@ -1473,7 +1670,7 @@ static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr old
                        break;
                case 1: // S
                        fpp_to_single (src, (doext ? exts[0] : x_cp_get_long (ad)));
-                       normalize_or_fault_if_no_denormal_support(opcode, extra, adold, oldpc, src);
+                       normalize_or_fault_if_no_denormal_support(opcode, extra, adold, adset, oldpc, src);
                        break;
                case 2: // X
                        {
@@ -1484,14 +1681,14 @@ static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr old
                                ad += 4;
                                wrd3 = (doext ? exts[2] : x_cp_get_long (ad));
                                fpp_to_exten (src, wrd1, wrd2, wrd3);
-                               normalize_or_fault_if_no_denormal_support(opcode, extra, adold, oldpc, src);
+                               normalize_or_fault_if_no_denormal_support(opcode, extra, adold, adset, oldpc, src);
                        }
                        break;
                case 3: // P
                        {
                                uae_u32 wrd[3];
                                if (currprefs.cpu_model == 68060) {
-                                       if (fault_if_no_packed_support (opcode, extra, adold, oldpc, NULL, wrd))
+                                       if (fault_if_no_packed_support (opcode, extra, adold, adset, oldpc, NULL, wrd))
                                                return 1;
                                }
                                wrd[0] = (doext ? exts[0] : x_cp_get_long (ad));
@@ -1499,7 +1696,7 @@ static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr old
                                wrd[1] = (doext ? exts[1] : x_cp_get_long (ad));
                                ad += 4;
                                wrd[2] = (doext ? exts[2] : x_cp_get_long (ad));
-                               if (fault_if_no_packed_support (opcode, extra, adold, oldpc, NULL, wrd))
+                               if (fault_if_no_packed_support (opcode, extra, adold, adset, oldpc, NULL, wrd))
                                        return 1;
                                fpp_to_pack (src, wrd, 0);
                                fpp_normalize(src);
@@ -1516,7 +1713,7 @@ static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr old
                                ad += 4;
                                wrd2 = (doext ? exts[1] : x_cp_get_long (ad));
                                fpp_to_double (src, wrd1, wrd2);
-                               normalize_or_fault_if_no_denormal_support(opcode, extra, adold, oldpc, src);
+                               normalize_or_fault_if_no_denormal_support(opcode, extra, adold, adset, oldpc, src);
                        }
                        break;
                case 6: // B
@@ -1528,10 +1725,11 @@ static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr old
        return 1;
 }
 
-static int put_fp_value (fpdata *value, uae_u32 opcode, uae_u16 extra, uaecptr oldpc, uae_u32 *adp)
+static int put_fp_value2(fpdata *value, uae_u32 opcode, uae_u16 extra, uaecptr oldpc, uae_u32 *adp, bool *adsetp)
 {
        int size, mode, reg;
        uae_u32 ad = 0;
+       bool adset = false;
        static const int sz1[8] = { 4, 4, 12, 12, 2, 8, 1, 0 };
        static const int sz2[8] = { 4, 4, 12, 12, 2, 8, 2, 0 };
 
@@ -1554,38 +1752,41 @@ static int put_fp_value (fpdata *value, uae_u32 opcode, uae_u16 extra, uaecptr o
        {
                case 0: // Dn
 
-                       if ((size == 0 || size == 1 ||size == 4 || size == 6) && fault_if_no_fpu (opcode, extra, 0, oldpc))
+                       if ((size == 0 || size == 1 ||size == 4 || size == 6) && fault_if_no_fpu (opcode, extra, 0, false, oldpc))
                                return -1;
                        switch (size)
                        {
                                case 6: // B
-                                       if (normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, value))
+                                       if (normalize_or_fault_if_no_denormal_support(opcode, extra, 0, false, oldpc, value))
                                                return 1;
                                        m68k_dreg (regs, reg) = (uae_u32)(((fpp_to_int (value, 0) & 0xff)
                                                | (m68k_dreg (regs, reg) & ~0xff)));
-                                       if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, oldpc, value))
+                                       if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, adset, oldpc, value))
                                                return -1;
                                        break;
                                case 4: // W
-                                       if (normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, value))
+                                       if (normalize_or_fault_if_no_denormal_support(opcode, extra, 0, false, oldpc, value))
                                                return 1;
                                        m68k_dreg (regs, reg) = (uae_u32)(((fpp_to_int (value, 1) & 0xffff)
                                                | (m68k_dreg (regs, reg) & ~0xffff)));
-                                       if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, oldpc, value))
+                                       if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, adset, oldpc, value))
                                                return -1;
                                        break;
                                case 0: // L
-                                       if (normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, value))
+                                       if (normalize_or_fault_if_no_denormal_support(opcode, extra, 0, false, oldpc, value))
                                                return 1;
                                        m68k_dreg (regs, reg) = (uae_u32)fpp_to_int (value, 2);
-                                       if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, oldpc, value))
+                                       if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, adset, oldpc, value))
                                                return -1;
                                        break;
                                case 1: // S
-                                       if (normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, value))
+                                       if (normalize_or_fault_if_no_denormal_support(opcode, extra, 0, false, oldpc, value))
                                                return 1;
                                        m68k_dreg (regs, reg) = fpp_from_single (value);
                                        break;
+                               case 3: // packed
+                               case 7: // packed
+                                       return -2;
                                default:
                                        return 0;
                        }
@@ -1594,44 +1795,49 @@ static int put_fp_value (fpdata *value, uae_u32 opcode, uae_u16 extra, uaecptr o
                        return 0;
                case 2: // (An)
                        ad = m68k_areg (regs, reg);
+                       adset = true;
                        break;
                case 3: // (An)+
                        // Also needed by fault_if_no_fpu 
-#if SUPPORT_MMU
                        mmufixup[0].reg = reg;
                        mmufixup[0].value = m68k_areg (regs, reg);
                        fpu_mmu_fixup = true;
-#endif
                        ad = m68k_areg (regs, reg);
+                       adset = true;
                        m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size];
                        break;
                case 4: // -(An)
                        // Also needed by fault_if_no_fpu 
-#if SUPPORT_MMU
                        mmufixup[0].reg = reg;
                        mmufixup[0].value = m68k_areg (regs, reg);
                        fpu_mmu_fixup = true;
-#endif
                        m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size];
                        ad = m68k_areg (regs, reg);
+                       adset = true;
                        // 68060 no fpu -(an): EA points to -4, not -12 if extended precision
-                       if (currprefs.cpu_model == 68060 && if_no_fpu() && sz1[size] == 12)
+                       // or if packed datatype
+                       if (currprefs.cpu_model == 68060 && ((if_no_fpu() && sz1[size] == 12) || size == 3 || size == 7)) {
                                ad += 8;
+                       }
                        break;
                case 5: // (d16,An)
                        ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_cp_next_iword ();
+                       adset = true;
                        break;
                case 6: // (d8,An,Xn)+
                        ad = x_cp_get_disp_ea_020 (m68k_areg (regs, reg), 0);
+                       adset = true;
                        break;
                case 7:
                        switch (reg)
                        {
                                case 0: // (xxx).W
                                        ad = (uae_s32) (uae_s16) x_cp_next_iword ();
+                                       adset = true;
                                        break;
                                case 1: // (xxx).L
                                        ad = x_cp_next_ilong ();
+                                       adset = true;
                                        break;
                                // Immediate and PC-relative modes are not supported
                                default:
@@ -1640,27 +1846,28 @@ static int put_fp_value (fpdata *value, uae_u32 opcode, uae_u16 extra, uaecptr o
        }
 
        *adp = ad;
+       *adsetp = adset;
 
-       if (fault_if_no_fpu (opcode, extra, ad, oldpc))
+       if (fault_if_no_fpu (opcode, extra, ad, adset, oldpc))
                return -1;
 
        switch (size)
        {
                case 0: // L
-                       if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value))
+                       if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, adset, oldpc, value))
                                return 1;
                        x_cp_put_long(ad, (uae_u32)fpp_to_int(value, 2));
-                       if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, oldpc, value))
+                       if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, adset, oldpc, value))
                                return -1;
                        break;
                case 1: // S
-                       if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value))
+                       if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, adset, oldpc, value))
                                return 1;
                        x_cp_put_long(ad, fpp_from_single(value));
                        break;
                case 2: // X
                        {
-                               if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value))
+                               if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, adset, oldpc, value))
                                        return 1;
                                uae_u32 wrd1, wrd2, wrd3;
                                fpp_from_exten(value, &wrd1, &wrd2, &wrd3);
@@ -1676,7 +1883,7 @@ static int put_fp_value (fpdata *value, uae_u32 opcode, uae_u16 extra, uaecptr o
                        {
                                uae_u32 wrd[3];
                                int kfactor;
-                               if (fault_if_no_packed_support (opcode, extra, ad, oldpc, value, wrd))
+                               if (fault_if_no_packed_support (opcode, extra, ad, adset, oldpc, value, wrd))
                                        return 1;
                                kfactor = size == 7 ? m68k_dreg (regs, (extra >> 4) & 7) : extra;
                                kfactor &= 127;
@@ -1692,15 +1899,15 @@ static int put_fp_value (fpdata *value, uae_u32 opcode, uae_u16 extra, uaecptr o
                        }
                        break;
                case 4: // W
-                       if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value))
+                       if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, adset, oldpc, value))
                                return 1;
                        x_cp_put_word(ad, (uae_s16)fpp_to_int(value, 1));
-                       if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, oldpc, value))
+                       if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, adset, oldpc, value))
                                return -1;
                        break;
                case 5: // D
                        {
-                               if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value))
+                               if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, adset, oldpc, value))
                                        return 1;
                                uae_u32 wrd1, wrd2;
                                fpp_from_double(value, &wrd1, &wrd2);
@@ -1710,10 +1917,10 @@ static int put_fp_value (fpdata *value, uae_u32 opcode, uae_u16 extra, uaecptr o
                        }
                        break;
                case 6: // B
-                       if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value))
+                       if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, adset, oldpc, value))
                                return 1;
                        x_cp_put_byte(ad, (uae_s8)fpp_to_int(value, 0));
-                       if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, oldpc, value))
+                       if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, adset, oldpc, value))
                                return -1;
                        break;
                default:
@@ -1722,7 +1929,7 @@ static int put_fp_value (fpdata *value, uae_u32 opcode, uae_u16 extra, uaecptr o
        return 1;
 }
 
-static int get_fp_ad (uae_u32 opcode, uae_u32 * ad)
+static int get_fp_ad (uae_u32 opcode, uae_u32 *ad, bool *adset)
 {
        int mode;
        int reg;
@@ -1736,34 +1943,43 @@ static int get_fp_ad (uae_u32 opcode, uae_u32 * ad)
                        return 0;
                case 2: // (An)
                        *ad = m68k_areg (regs, reg);
+                       *adset = true;
                        break;
                case 3: // (An)+
                        *ad = m68k_areg (regs, reg);
+                       *adset = true;
                        break;
                case 4: // -(An)
                        *ad = m68k_areg (regs, reg);
+                       *adset = true;
                        break;
                case 5: // (d16,An)
                        *ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_cp_next_iword ();
+                       *adset = true;
                        break;
                case 6: // (d8,An,Xn)+
                        *ad = x_cp_get_disp_ea_020 (m68k_areg (regs, reg), 0);
+                       *adset = true;
                        break;
                case 7:
                        switch (reg)
                        {
                                case 0: // (xxx).W
                                        *ad = (uae_s32) (uae_s16) x_cp_next_iword ();
+                                       *adset = true;
                                        break;
                                case 1: // (xxx).L
                                        *ad = x_cp_next_ilong ();
+                                       *adset = true;
                                        break;
                                case 2: // (d16,PC)
                                        *ad = m68k_getpc ();
                                        *ad += (uae_s32) (uae_s16) x_cp_next_iword ();
+                                       *adset = true;
                                        break;
                                case 3: // (d8,PC,Xn)+
                                        *ad = x_cp_get_disp_ea_020 (m68k_getpc (), 0);
+                                       *adset = true;
                                        break;
                                default:
                                        return 0;
@@ -1772,6 +1988,28 @@ static int get_fp_ad (uae_u32 opcode, uae_u32 * ad)
        return 1;
 }
 
+static int put_fp_value(fpdata *value, uae_u32 opcode, uae_u16 extra, uaecptr oldpc, uae_u32 *adp, bool *adsetp)
+{
+       int v = put_fp_value2(value, opcode, extra, oldpc, adp, adsetp);
+       if (v == -2) {
+               int size = (extra >> 10) & 7;
+               if (size == 3 || size == 7) {
+                       // 68040+ generates unimplemented effective mode exception even if destination EA is Dn or An.
+                       // Always invalid EAs (Destination PC-relative or immediate) generate expected f-line exception.
+                       uae_u32 wrd[3];
+                       if (fault_if_no_packed_support(opcode, extra, 0, false, oldpc, value, wrd)) {
+                               if (regs.fp_unimp_pend) {
+                                       fp_exception_pending(false);
+                               }
+                               return -1;
+                       }
+               }
+               return 0;
+       }
+       return v;
+}
+
+
 int fpp_cond (int condition)
 {
        int NotANumber, N, Z;
@@ -1899,7 +2137,7 @@ void fpuop_dbcc (uae_u32 opcode, uae_u16 extra)
                return;
 
        disp = (uae_s32) (uae_s16)x_cp_next_iword();
-       if (fault_if_no_fpu_u (opcode, extra, pc + disp, pc - 4))
+       if (fault_if_no_fpu_u (opcode, extra, pc + disp, true, pc - 4))
                return;
        regs.fpiar = pc - 4;
        maybe_idle_state ();
@@ -1907,7 +2145,7 @@ void fpuop_dbcc (uae_u32 opcode, uae_u16 extra)
        if (cc < 0) {
                if (cc == -2)
                        return; // BSUN
-               fpu_op_illg (opcode, 0, regs.fpiar);
+               fpu_op_illg (opcode, 0, false, regs.fpiar);
        } else if (!cc) {
                int reg = opcode & 0x7;
 
@@ -1925,6 +2163,7 @@ void fpuop_dbcc (uae_u32 opcode, uae_u16 extra)
 void fpuop_scc (uae_u32 opcode, uae_u16 extra)
 {
        uae_u32 ad = 0;
+       bool adset = false;
        int cc;
        uaecptr pc = m68k_getpc () - 4;
 
@@ -1940,13 +2179,13 @@ void fpuop_scc (uae_u32 opcode, uae_u16 extra)
                return;
 
        if (opcode & 0x38) {
-               if (get_fp_ad (opcode, &ad) == 0) {
+               if (get_fp_ad (opcode, &ad, &adset) == 0) {
                        fpu_noinst (opcode, regs.fpiar);
                        return;
                }
        }
 
-       if (fault_if_no_fpu_u (opcode, extra, ad, pc))
+       if (fault_if_no_fpu_u (opcode, extra, ad, adset, pc))
                return;
 
        regs.fpiar = pc;
@@ -1955,7 +2194,7 @@ void fpuop_scc (uae_u32 opcode, uae_u16 extra)
        if (cc < 0) {
                if (cc == -2)
                        return; // BSUN
-               fpu_op_illg (opcode, 0, regs.fpiar);
+               fpu_op_illg (opcode, 0, false, regs.fpiar);
        } else if ((opcode & 0x38) == 0) {
                m68k_dreg (regs, opcode & 7) = (m68k_dreg (regs, opcode & 7) & ~0xff) | (cc ? 0xff : 0x00);
        } else {
@@ -1975,7 +2214,7 @@ void fpuop_trapcc (uae_u32 opcode, uaecptr oldpc, uae_u16 extra)
        write_log(_T("FTRAPcc %04x %04x %08x\n"), opcode, extra, M68K_GETPC);
 #endif
 
-       if (fault_if_no_fpu_u (opcode, extra, 0, oldpc))
+       if (fault_if_no_fpu_u (opcode, extra, 0, false, oldpc))
                return;
 
        regs.fpiar = oldpc;
@@ -1984,13 +2223,13 @@ void fpuop_trapcc (uae_u32 opcode, uaecptr oldpc, uae_u16 extra)
        if (cc < 0) {
                if (cc == -2)
                        return; // BSUN
-               fpu_op_illg (opcode, 0, regs.fpiar);
+               fpu_op_illg (opcode, 0, false, regs.fpiar);
        } else if (cc) {
                Exception (7);
        }
 }
 
-void fpuop_bcc (uae_u32 opcode, uaecptr oldpc, uae_u32 extra)
+void fpuop_bcc(uae_u32 opcode, uaecptr oldpc, uae_u32 extra)
 {
        int cc;
 
@@ -2002,20 +2241,22 @@ void fpuop_bcc (uae_u32 opcode, uaecptr oldpc, uae_u32 extra)
        write_log(_T("FBcc %04x %04x %08x\n"), opcode, extra, M68K_GETPC);
 #endif
 
-       if (fault_if_no_fpu (opcode, extra, 0, oldpc - 2))
+       if (fault_if_no_fpu(opcode, extra, 0, false, oldpc - 2))
                return;
 
-       regs.fpiar = oldpc - 2;
-       maybe_idle_state ();
-       cc = fpp_cond (opcode & 0x3f);
+       if (currprefs.fpu_model == 68060) {
+               regs.fpiar = oldpc - 2;
+       }
+       maybe_idle_state();
+       cc = fpp_cond(opcode & 0x3f);
        if (cc < 0) {
                if (cc == -2)
                        return; // BSUN
-               fpu_op_illg (opcode, 0, regs.fpiar);
+               fpu_op_illg(opcode, 0, false, regs.fpiar);
        } else if (cc) {
                if ((opcode & 0x40) == 0)
                        extra = (uae_s32) (uae_s16) extra;
-               m68k_setpc (oldpc + extra);
+               m68k_setpc(oldpc + extra);
                regs.fp_branch = true;
        }
 }
@@ -2023,6 +2264,7 @@ void fpuop_bcc (uae_u32 opcode, uaecptr oldpc, uae_u32 extra)
 void fpuop_save (uae_u32 opcode)
 {
        uae_u32 ad, adp;
+       bool adset = false;
        int incr = (opcode & 0x38) == 0x20 ? -1 : 1;
        int fpu_version = get_fpu_version (currprefs.fpu_model);
        uaecptr pc = m68k_getpc () - 2;
@@ -2039,12 +2281,12 @@ void fpuop_save (uae_u32 opcode)
        if (fault_if_no_6888x (opcode, 0, pc))
                return;
 
-       if (get_fp_ad (opcode, &ad) == 0) {
-               fpu_op_illg (opcode, 0, pc);
+       if (get_fp_ad (opcode, &ad, &adset) == 0) {
+               fpu_op_illg (opcode, 0, false, pc);
                return;
        }
 
-       if (fault_if_no_fpu (opcode, 0, ad, pc))
+       if (fault_if_no_fpu (opcode, 0, ad, adset, pc))
                return;
 
 //     write_log(_T("FSAVE %08x %08x\n"), M68K_GETPC, ad);
@@ -2245,6 +2487,7 @@ void fpuop_restore (uae_u32 opcode)
        int fpu_model = currprefs.fpu_model;
        uaecptr pc = m68k_getpc () - 2;
        uae_u32 ad, ad_orig;
+       bool adset = false;
        uae_u32 d;
 
        regs.fp_exception = false;
@@ -2257,12 +2500,12 @@ void fpuop_restore (uae_u32 opcode)
        if (fault_if_no_6888x (opcode, 0, pc))
                return;
 
-       if (get_fp_ad (opcode, &ad) == 0) {
-               fpu_op_illg (opcode, 0, pc);
+       if (get_fp_ad (opcode, &ad, &adset) == 0) {
+               fpu_op_illg (opcode, 0, false, pc);
                return;
        }
 
-       if (fault_if_no_fpu (opcode, 0, ad, pc))
+       if (fault_if_no_fpu (opcode, 0, ad, adset, pc))
                return;
        ad_orig = ad;
        regs.fpiar = pc;
@@ -2367,7 +2610,7 @@ retry:
                                                if (v)
                                                        regs.fp[(cmdreg1b>>7)&7] = dst;
                                                
-                                               fpsr_check_arithmetic_exception(0, &src, regs.fp_opword, cmdreg1b, regs.fp_ea);
+                                               fpsr_check_arithmetic_exception(0, &src, regs.fp_opword, cmdreg1b, regs.fp_ea, regs.fp_ea_set);
                                        } else {
                                                write_log (_T("FRESTORE resume of opclass %d instruction not supported %08x\n"), opclass, ad_orig);
                                        }
@@ -2611,6 +2854,7 @@ static bool fp_arithmetic(fpdata *src, fpdata *dst, int extra)
                        fpp_intrz(dst, src);
                        break;
                case 0x04: /* FSQRT */
+               case 0x05:
                        fpp_sqrt(dst, src, PREC_NORMAL);
                        break;
                case 0x41: /* FSSQRT */
@@ -2620,6 +2864,7 @@ static bool fp_arithmetic(fpdata *src, fpdata *dst, int extra)
                        fpp_sqrt(dst, src, PREC_DOUBLE);
                        break;
                case 0x06: /* FLOGNP1 */
+               case 0x07:
                        fpp_lognp1(dst, src);
                        break;
                case 0x08: /* FETOXM1 */
@@ -2629,6 +2874,7 @@ static bool fp_arithmetic(fpdata *src, fpdata *dst, int extra)
                        fpp_tanh(dst, src);
                        break;
                case 0x0a: /* FATAN */
+               case 0x0b:
                        fpp_atan(dst, src);
                        break;
                case 0x0c: /* FASIN */
@@ -2650,6 +2896,7 @@ static bool fp_arithmetic(fpdata *src, fpdata *dst, int extra)
                        fpp_twotox(dst, src);
                        break;
                case 0x12: /* FTENTOX */
+               case 0x13:
                        fpp_tentox(dst, src);
                        break;
                case 0x14: /* FLOGN */
@@ -2659,6 +2906,7 @@ static bool fp_arithmetic(fpdata *src, fpdata *dst, int extra)
                        fpp_log10(dst, src);
                        break;
                case 0x16: /* FLOG2 */
+               case 0x17:
                        fpp_log2(dst, src);
                        break;
                case 0x18: /* FABS */
@@ -2674,6 +2922,7 @@ static bool fp_arithmetic(fpdata *src, fpdata *dst, int extra)
                        fpp_cosh(dst, src);
                        break;
                case 0x1a: /* FNEG */
+               case 0x1b:
                        fpp_neg(dst, src, PREC_NORMAL);
                        break;
                case 0x5a: /* FSNEG */
@@ -2741,6 +2990,13 @@ static bool fp_arithmetic(fpdata *src, fpdata *dst, int extra)
                        fpp_sglmul(dst, src);
                        break;
                case 0x28: /* FSUB */
+               case 0x29:
+               case 0x2a:
+               case 0x2b:
+               case 0x2c:
+               case 0x2d:
+               case 0x2e:
+               case 0x2f:
                        fpp_sub(dst, src, PREC_NORMAL);
                        break;
                case 0x68: /* FSSUB */
@@ -2762,16 +3018,24 @@ static bool fp_arithmetic(fpdata *src, fpdata *dst, int extra)
                        fpp_sin(dst, src);
                        break;
                case 0x38: /* FCMP */
+               case 0x39:
+               case 0x3c:
+               case 0x3d:
                {
                        fpp_cmp(dst, src);
                        fpsr_make_status();
+                       fpsr_set_result_always(dst);
                        fpsr_set_result(dst);
                        return false;
                }
                case 0x3a: /* FTST */
+               case 0x3b:
+               case 0x3e:
+               case 0x3f:
                {
                        fpp_tst(dst, src);
                        fpsr_make_status();
+                       fpsr_set_result_always(dst);
                        fpsr_set_result(dst);
                        return false;
                }
@@ -2780,10 +3044,13 @@ static bool fp_arithmetic(fpdata *src, fpdata *dst, int extra)
                        return false;
        }
 
-       fpsr_set_result(dst);
+       fpsr_set_result_always(dst);
 
-       if (fpsr_make_status())
+       if (fpsr_make_status()) {
                return false;
+       }
+
+       fpsr_set_result(dst);
 
        return true;
 }
@@ -2795,12 +3062,14 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra)
        fpdata src, dst;
        uaecptr pc = m68k_getpc () - 4;
        uaecptr ad = 0;
+       bool adset = false;
+       bool nonmaskable = false;
 
 #if DEBUG_FPP
        if (!isinrom ())
                write_log (_T("FPP %04x %04x at %08x\n"), opcode & 0xffff, extra, pc);
 #endif
-       if (fault_if_no_6888x (opcode, extra, pc))
+       if (fault_if_no_6888x(opcode, extra, pc))
                return;
 
        switch ((extra >> 13) & 0x7)
@@ -2813,14 +3082,15 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra)
                        regs.fpiar = pc;
                        fpsr_clear_status();
                        src = regs.fp[(extra >> 7) & 7];
-                       v = put_fp_value (&src, opcode, extra, pc, &ad);
+                       v = put_fp_value(&src, opcode, extra, pc, &ad, &adset);
                        if (v <= 0) {
-                               if (v == 0)
-                                       fpu_noinst (opcode, pc);
+                               if (v == 0) {
+                                       fpu_noinst(opcode, pc);
+                               }
                                return;
                        }
                        fpsr_make_status();
-                       fpsr_check_arithmetic_exception(0, &src, opcode, extra, ad);
+                       fpsr_check_arithmetic_exception(0, &src, opcode, extra, ad, adset);
                        fp_exception_pending(false); // post/mid instruction
                        return;
 
@@ -2829,7 +3099,7 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra)
                        // FMOVE Control Register <> Data or Address register
                        if ((opcode & 0x38) == 0) {
                                // Dn
-                               if (fault_if_no_fpu (opcode, extra, 0, pc))
+                               if (fault_if_no_fpu (opcode, extra, 0, false, pc))
                                        return;
                                // Only single selected control register is allowed
                                // All control register bits unset = FPIAR
@@ -2858,7 +3128,7 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra)
                                }
                        } else if ((opcode & 0x38) == 0x08) {
                                // An
-                               if (fault_if_no_fpu (opcode, extra, 0, pc))
+                               if (fault_if_no_fpu (opcode, extra, 0, false, pc))
                                        return;
                                // Only FPIAR can be moved to/from address register
                                // All bits unset = FPIAR
@@ -2890,7 +3160,7 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra)
                                                ext[1] = x_cp_next_ilong ();
                                        if (extra & 0x0400)
                                                ext[2] = x_cp_next_ilong ();
-                                       if (fault_if_no_fpu (opcode, extra, 0, pc))
+                                       if (fault_if_no_fpu (opcode, extra, 0, false, pc))
                                                return;
                                        if (extra & 0x1000)
                                                fpp_set_fpcr(ext[0]);
@@ -2900,7 +3170,7 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra)
                                                fpp_set_fpiar(ext[2]);
                                } else {
                                        // immediate as destination
-                                       fpu_noinst (opcode, pc);
+                                       fpu_noinst(opcode, pc);
                                        return;
                                }
                        } else if (extra & 0x2000) {
@@ -2908,11 +3178,11 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra)
                                uae_u32 ad;
                                int incr = 0;
 
-                               if (get_fp_ad (opcode, &ad) == 0) {
-                                       fpu_noinst (opcode, pc);
+                               if (get_fp_ad(opcode, &ad, &adset) == 0) {
+                                       fpu_noinst(opcode, pc);
                                        return;
                                }
-                               if (fault_if_no_fpu (opcode, extra, ad, pc))
+                               if (fault_if_no_fpu(opcode, extra, ad, adset, pc))
                                        return;
                                if ((opcode & 0x3f) >= 0x3a) {
                                        // PC relative modes not supported
@@ -2952,11 +3222,11 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra)
                                uae_u32 ad;
                                int incr = 0;
 
-                               if (get_fp_ad (opcode, &ad) == 0) {
+                               if (get_fp_ad (opcode, &ad, &adset) == 0) {
                                        fpu_noinst (opcode, pc);
                                        return;
                                }
-                               if (fault_if_no_fpu (opcode, extra, ad, pc))
+                               if (fault_if_no_fpu (opcode, extra, ad, adset, pc))
                                        return;
 
                                if((opcode & 0x38) == 0x20) {
@@ -2994,11 +3264,11 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra)
                                uae_u32 ad, list = 0;
                                int incr = 1;
                                int regdir = 1;
-                               if (get_fp_ad (opcode, &ad) == 0) {
+                               if (get_fp_ad (opcode, &ad, &adset) == 0) {
                                        fpu_noinst (opcode, pc);
                                        return;
                                }
-                               if (fault_if_no_fpu (opcode, extra, ad, pc))
+                               if (fault_if_no_fpu (opcode, extra, ad, adset, pc))
                                        return;
 
                                if ((extra & 0x2000) && ((opcode & 0x38) == 0x18 || (opcode & 0x3f) >= 0x3a)) {
@@ -3057,7 +3327,7 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra)
                        reg = (extra >> 7) & 7;
                        if ((extra & 0xfc00) == 0x5c00) {
                                // FMOVECR
-                               if (fault_if_unimplemented_680x0 (opcode, extra, ad, pc, &src, reg))
+                               if (fault_if_unimplemented_680x0 (opcode, extra, ad, adset, pc, &src, reg))
                                        return;
                                if (extra & 0x40) {
                                        // 6888x and ROM constant 0x40 - 0x7f: f-line
@@ -3067,33 +3337,35 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra)
                                fpsr_clear_status();
                                fpu_get_constant(&regs.fp[reg], extra & 0x7f);
                                fpsr_make_status();
-                               fpsr_check_arithmetic_exception(0, &src, opcode, extra, ad);
+                               fpsr_check_arithmetic_exception(0, &src, opcode, extra, ad, adset);
                                return;
                        }
 
                        // 6888x does not have special exceptions, check immediately
-                       if (fault_if_unimplemented_6888x (opcode, extra, pc))
+                       // 68040+ also generate immediate exception 11 if invalid opmode.
+                       if (fault_if_nonexisting_opmode(opcode, extra, pc))
                                return;
 
                        fpsr_clear_status();
 
-                       v = get_fp_value (opcode, extra, &src, pc, &ad);
+                       v = get_fp_value(opcode, extra, &src, pc, &ad, &adset);
                        if (v <= 0) {
-                               if (v == 0)
-                                       fpu_noinst (opcode, pc);
+                               if (v == 0) {
+                                       fpu_noinst(opcode, pc);
+                               }
                                return;
                        }
 
-                       if (fault_if_no_fpu (opcode, extra, ad, pc))
+                       if (fault_if_no_fpu (opcode, extra, ad, adset, pc))
                                return;
 
                        dst = regs.fp[reg];
 
                        if (fp_is_dyadic(extra))
-                               normalize_or_fault_if_no_denormal_support_dst(opcode, extra, ad, pc, &dst, &src);
+                               normalize_or_fault_if_no_denormal_support_dst(opcode, extra, ad, adset, pc, &dst, &src);
 
                        // check for 680x0 unimplemented instruction
-                       if (fault_if_unimplemented_680x0 (opcode, extra, ad, pc, &src, reg))
+                       if (fault_if_unimplemented_680x0 (opcode, extra, ad, adset, pc, &src, reg))
                                return;
 
                        // unimplemented datatype was checked in get_fp_value
@@ -3104,10 +3376,12 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra)
 
                        v = fp_arithmetic(&src, &dst, extra);
 
-                       fpsr_check_arithmetic_exception(0, &src, opcode, extra, ad);
+                       nonmaskable = fpsr_check_arithmetic_exception(0, &src, opcode, extra, ad, adset);
 
-                       if (v)
+                       // 68040 does not update destination register if nonmasked exception was generated
+                       if (v && (currprefs.fpu_model != 68040 || !nonmaskable)) {
                                regs.fp[reg] = dst;
+                       }
 
                        return;
                default:
@@ -3125,11 +3399,9 @@ void fpuop_arithmetic (uae_u32 opcode, uae_u16 extra)
        write_log(_T("FPUOP %04x %04x PC=%08x\n"), opcode, extra, M68K_GETPC);
 #endif
        fpuop_arithmetic2 (opcode, extra);
-#if SUPPORT_MMU
        if (fpu_mmu_fixup) {
                mmufixup[0].reg = -1;
        }
-#endif
 }
 
 static void get_features(void)