From 27ad7de49c293a1fc2ec21fd87ef17397f150bb6 Mon Sep 17 00:00:00 2001 From: arbee Date: Thu, 13 May 2021 20:31:07 -0400 Subject: [PATCH] m68k: backport FPU fixes from upstream Musashi [R. Belmont, Jean-Francois Fabre] --- src/devices/cpu/m68000/m68kfpu.cpp | 112 ++++++++++++++++++----------- 1 file changed, 71 insertions(+), 41 deletions(-) diff --git a/src/devices/cpu/m68000/m68kfpu.cpp b/src/devices/cpu/m68000/m68kfpu.cpp index f1108bc54ab..ed439f2fe5f 100644 --- a/src/devices/cpu/m68000/m68kfpu.cpp +++ b/src/devices/cpu/m68000/m68kfpu.cpp @@ -650,12 +650,9 @@ u64 m68000_base_device::READ_EA_64(int ea) return 0; } - -floatx80 m68000_base_device::READ_EA_FPE(int ea) +floatx80 m68000_base_device::READ_EA_FPE(int mode, int reg, uint32 di_mode_ea) { floatx80 fpr; - int mode = (ea >> 3) & 0x7; - int reg = (ea & 0x7); switch (mode) { @@ -682,16 +679,12 @@ floatx80 m68000_base_device::READ_EA_FPE(int ea) } case 5: // (d16, An) { - // FIXME: will fail for fmovem - u32 ea = EA_AY_DI_32(); - fpr = load_extended_float80(ea); + fpr = load_extended_float80(di_mode_ea); break; } case 6: // (An) + (Xn) + d8 { - // FIXME: will fail for fmovem - u32 ea = EA_AY_IX_32(); - fpr = load_extended_float80(ea); + fpr = load_extended_float80(di_mode_ea); break; } @@ -1075,11 +1068,8 @@ void m68000_base_device::WRITE_EA_64(int ea, u64 data) } } -void m68000_base_device::WRITE_EA_FPE(int ea, floatx80 fpr) +void m68000_base_device::WRITE_EA_FPE(int mode, int reg, floatx80 fpr, uint32 di_mode_ea) { - int mode = (ea >> 3) & 0x7; - int reg = (ea & 0x7); - switch (mode) { case 2: // (An) @@ -1110,8 +1100,9 @@ void m68000_base_device::WRITE_EA_FPE(int ea, floatx80 fpr) case 5: // (d16,An) { - u32 ea = EA_AY_DI_32(); - store_extended_float80(ea, fpr); + // EA_AY_DI_32() should not be done here because fmovem would increase + // PC each time, reading incorrect displacement & advancing PC too much. + store_extended_float80(di_mode_ea, fpr); break; } @@ -1199,7 +1190,10 @@ void m68000_base_device::fpgen_rm_reg(u16 w2) } case 2: // Extended-precision Real { - source = READ_EA_FPE(ea); + int imode = (ea >> 3) & 0x7; + int reg = (ea & 0x7); + uint32 di_mode_ea = imode == 5 ? (REG_A()[reg] + MAKE_INT_16(m68ki_read_imm_16())) : 0; + source = READ_EA_FPE(imode, reg, di_mode_ea); break; } case 3: // Packed-decimal Real @@ -1341,6 +1335,7 @@ void m68000_base_device::fpgen_rm_reg(u16 w2) // handle it right here, the usual opmode bits aren't valid in the FMOVECR case m_fpr[dst] = source; + SET_CONDITION_CODES(m_fpr[dst]); m_icount -= 4; return; } @@ -1368,6 +1363,7 @@ void m68000_base_device::fpgen_rm_reg(u16 w2) s32 temp; temp = floatx80_to_int32(source); m_fpr[dst] = int32_to_floatx80(temp); + SET_CONDITION_CODES(m_fpr[dst]); break; } case 0x03: // FINTRZ @@ -1375,6 +1371,7 @@ void m68000_base_device::fpgen_rm_reg(u16 w2) s32 temp; temp = floatx80_to_int32_round_to_zero(source); m_fpr[dst] = int32_to_floatx80(temp); + SET_CONDITION_CODES(m_fpr[dst]); break; } case 0x04: // FSQRT @@ -1463,9 +1460,11 @@ void m68000_base_device::fpgen_rm_reg(u16 w2) m_icount -= 6; break; } + case 0x60: // FSDIVS case 0x20: // FDIV { m_fpr[dst] = floatx80_div(m_fpr[dst], source); + SET_CONDITION_CODES(m_fpr[dst]); m_icount -= 43; break; } @@ -1486,6 +1485,7 @@ void m68000_base_device::fpgen_rm_reg(u16 w2) m_icount -= 9; break; } + case 0x63: // FSMULS (JFF) case 0x23: // FMUL { m_fpr[dst] = floatx80_mul(m_fpr[dst], source); @@ -1578,7 +1578,11 @@ void m68000_base_device::fmove_reg_mem(u16 w2) } case 2: // Extended-precision Real { - WRITE_EA_FPE(ea, m_fpr[src]); + int mode = (ea >> 3) & 0x7; + int reg = (ea & 0x7); + uint32 di_mode_ea = mode == 5 ? (REG_A()[reg] + MAKE_INT_16(m68ki_read_imm_16())) : 0; + + WRITE_EA_FPE(mode, reg, m_fpr[src], di_mode_ea); break; } case 3: // Packed-decimal Real with Static K-factor @@ -1670,7 +1674,11 @@ void m68000_base_device::fmove_fpcr(u16 w2) } else // From to system control reg { - if (regsel & 4) m_fpcr = READ_EA_32(ea); + if (regsel & 4) + { + m_fpcr = READ_EA_32(ea); + // should update softfloat rounding mode here + } if (regsel & 2) m_fpsr = READ_EA_32(ea); if (regsel & 1) m_fpiar = READ_EA_32(ea); } @@ -1756,20 +1764,23 @@ void m68000_base_device::fmovem(u16 w2) [[fallthrough]]; case 0: // Static register list, predecrement or control addressing mode { + // the "di_mode_ea" parameter kludge is required here else WRITE_EA_FPE would have + // to call EA_AY_DI_32() (that advances PC & reads displacement) each time + // when the proper behaviour is 1) read once, 2) increment ea for each matching register + // this forces to pre-read the mode (named "imode") so we can decide to read displacement, only once + int imode = (ea >> 3) & 0x7; + int reg = (ea & 0x7); + int di_mode = imode == 5; + uint32 di_mode_ea = di_mode ? (REG_A()[reg] + MAKE_INT_16(m68ki_read_imm_16())) : 0; + for (i=0; i < 8; i++) { if (reglist & (1 << i)) { - switch (ea >> 3) + WRITE_EA_FPE(imode, reg, m_fpr[i], di_mode_ea); + if (di_mode) { - case 5: // (d16, An) - case 6: // (An) + (Xn) + d8 - store_extended_float80(mem_addr, m_fpr[i]); - mem_addr += 12; - break; - default: - WRITE_EA_FPE(ea, m_fpr[i]); - break; + di_mode_ea += 12; } m_icount -= 2; @@ -1784,20 +1795,20 @@ void m68000_base_device::fmovem(u16 w2) [[fallthrough]]; case 2: // Static register list, postdecrement or control addressing mode { + int imode = (ea >> 3) & 0x7; + int reg = (ea & 0x7); + int di_mode = imode == 5; + + uint32 di_mode_ea = di_mode ? (REG_A()[reg] + MAKE_INT_16(m68ki_read_imm_16())) : 0; + for (i=0; i < 8; i++) { if (reglist & (1 << i)) { - switch (ea >> 3) + WRITE_EA_FPE(imode, reg, m_fpr[7 - i], di_mode_ea); + if (di_mode) { - case 5: // (d16, An) - case 6: // (An) + (Xn) + d8 - store_extended_float80(mem_addr, m_fpr[7-i]); - mem_addr += 12; - break; - default: - WRITE_EA_FPE(ea, m_fpr[7-i]); - break; + di_mode_ea += 12; } m_icount -= 2; @@ -1819,6 +1830,11 @@ void m68000_base_device::fmovem(u16 w2) [[fallthrough]]; case 2: // Static register list, postincrement or control addressing mode { + int imode = (ea >> 3) & 0x7; + int reg = (ea & 0x7); + int di_mode = imode == 5; + uint32 di_mode_ea = di_mode ? (REG_A()[reg] + MAKE_INT_16(m68ki_read_imm_16())) : 0; + for (i=0; i < 8; i++) { if (reglist & (1 << i)) @@ -1831,7 +1847,7 @@ void m68000_base_device::fmovem(u16 w2) mem_addr += 12; break; default: - m_fpr[7-i] = READ_EA_FPE(ea); + m_fpr[7 - i] = READ_EA_FPE(imode, reg, di_mode_ea); break; } m_icount -= 2; @@ -1847,10 +1863,24 @@ void m68000_base_device::fmovem(u16 w2) void m68000_base_device::fscc() { - int ea = m_ir & 0x3f; - int condition = (s16)(OPER_I_16()); + const int mode = (m_ir & 0x38) >> 3; + const int condition = OPER_I_16() & 0x3f; + const int v = (TEST_CONDITION(condition) ? 0xff : 0x00); + + switch (mode) + { + case 0: // Dx (handled specially because it only changes the low byte of Dx) + { + const int reg = m_ir & 7; + REG_D()[reg] = (REG_D()[reg] & 0xffffff00) | v; + } + break; + + default: + WRITE_EA_8(m_ir & 0x3f, v); + break; + } - WRITE_EA_8(ea, TEST_CONDITION(condition) ? 0xff : 0); m_icount -= 7; // ??? }