From 7f537d11048c43bc7391c2daa507a68db4a41039 Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Sat, 11 Apr 2020 10:32:21 +0300 Subject: [PATCH] CPU tester FPU updates/fixes. Don't set flags if exception, unimplemented instruction exception fixes, support 6888x undocumented opmodes, keep state of EA calculation, etc. --- fpp.cpp | 590 +++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 431 insertions(+), 159 deletions(-) diff --git a/fpp.cpp b/fpp.cpp index be0eee81..a7b369cb 100644 --- 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(®s.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(®s.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) -- 2.47.3