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);
// 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);
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;
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;
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
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;
}
}
}
+ 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)) {
} 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)
{
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;
// 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;
}
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;
if (prec >= 2)
fpp_round64(fpd);
+ fpsr_set_result_always(fpd);
fpsr_set_result(fpd);
return true;
}
#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;
}
regs.fp_ea = ea;
+ regs.fp_ea_set = easet;
regs.fp_unimp_ins = true;
fp_unimp_instruction_exception_pending();
}
-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;
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
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)
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 */
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;
}
}
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);
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;
}
}
// 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;
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 {
}
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;
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 {
}
// 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;
}
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;
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)
{
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;
}
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;
}
- 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;
}
}
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
{
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));
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);
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
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 };
{
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;
}
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:
}
*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);
{
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;
}
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);
}
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:
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;
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;
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;
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 ();
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;
void fpuop_scc (uae_u32 opcode, uae_u16 extra)
{
uae_u32 ad = 0;
+ bool adset = false;
int cc;
uaecptr pc = m68k_getpc () - 4;
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;
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 {
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;
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;
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;
}
}
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;
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);
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;
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;
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);
}
fpp_intrz(dst, src);
break;
case 0x04: /* FSQRT */
+ case 0x05:
fpp_sqrt(dst, src, PREC_NORMAL);
break;
case 0x41: /* FSSQRT */
fpp_sqrt(dst, src, PREC_DOUBLE);
break;
case 0x06: /* FLOGNP1 */
+ case 0x07:
fpp_lognp1(dst, src);
break;
case 0x08: /* FETOXM1 */
fpp_tanh(dst, src);
break;
case 0x0a: /* FATAN */
+ case 0x0b:
fpp_atan(dst, src);
break;
case 0x0c: /* FASIN */
fpp_twotox(dst, src);
break;
case 0x12: /* FTENTOX */
+ case 0x13:
fpp_tentox(dst, src);
break;
case 0x14: /* FLOGN */
fpp_log10(dst, src);
break;
case 0x16: /* FLOG2 */
+ case 0x17:
fpp_log2(dst, src);
break;
case 0x18: /* FABS */
fpp_cosh(dst, src);
break;
case 0x1a: /* FNEG */
+ case 0x1b:
fpp_neg(dst, src, PREC_NORMAL);
break;
case 0x5a: /* FSNEG */
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 */
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;
}
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;
}
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)
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;
// 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
}
} 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
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]);
fpp_set_fpiar(ext[2]);
} else {
// immediate as destination
- fpu_noinst (opcode, pc);
+ fpu_noinst(opcode, pc);
return;
}
} else if (extra & 0x2000) {
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
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) {
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)) {
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
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
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:
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)