From a722fd6b53d26c61b48b4628c47e62f7ec4765f3 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Thu, 18 Feb 2021 00:37:17 +1000 Subject: [PATCH] PGXP: Make mult/div compute results instead of parameters Lets us call it from the recompiler. --- src/core/cpu_core.cpp | 8 +++--- src/core/pgxp.cpp | 63 +++++++++++++++++++++++++++++++------------ src/core/pgxp.h | 8 +++--- 3 files changed, 54 insertions(+), 25 deletions(-) diff --git a/src/core/cpu_core.cpp b/src/core/cpu_core.cpp index d8edd706b..4417d9d5b 100644 --- a/src/core/cpu_core.cpp +++ b/src/core/cpu_core.cpp @@ -827,7 +827,7 @@ restart_instruction: g_state.regs.lo = Truncate32(result); if constexpr (pgxp_mode >= PGXPMode::CPU) - PGXP::CPU_MULT(inst.bits, g_state.regs.hi, g_state.regs.lo, lhs, rhs); + PGXP::CPU_MULT(inst.bits, lhs, rhs); } break; @@ -838,7 +838,7 @@ restart_instruction: const u64 result = ZeroExtend64(lhs) * ZeroExtend64(rhs); if constexpr (pgxp_mode >= PGXPMode::CPU) - PGXP::CPU_MULTU(inst.bits, g_state.regs.hi, g_state.regs.lo, lhs, rhs); + PGXP::CPU_MULTU(inst.bits, lhs, rhs); g_state.regs.hi = Truncate32(result >> 32); g_state.regs.lo = Truncate32(result); @@ -869,7 +869,7 @@ restart_instruction: } if constexpr (pgxp_mode >= PGXPMode::CPU) - PGXP::CPU_DIV(inst.bits, g_state.regs.hi, g_state.regs.lo, num, denom); + PGXP::CPU_DIV(inst.bits, num, denom); } break; @@ -891,7 +891,7 @@ restart_instruction: } if constexpr (pgxp_mode >= PGXPMode::CPU) - PGXP::CPU_DIVU(inst.bits, g_state.regs.hi, g_state.regs.lo, num, denom); + PGXP::CPU_DIVU(inst.bits, num, denom); } break; diff --git a/src/core/pgxp.cpp b/src/core/pgxp.cpp index 1045c66f2..ea6a0347b 100644 --- a/src/core/pgxp.cpp +++ b/src/core/pgxp.cpp @@ -183,28 +183,28 @@ void MakeValid(PGXP_value* pV, u32 psxV) } } -void Validate(PGXP_value* pV, u32 psxV) +void ALWAYS_INLINE_RELEASE Validate(PGXP_value* pV, u32 psxV) { // assume pV is not NULL pV->flags &= (pV->value == psxV) ? ALL : INV_VALID_ALL; } -void MaskValidate(PGXP_value* pV, u32 psxV, u32 mask, u32 validMask) +void ALWAYS_INLINE_RELEASE MaskValidate(PGXP_value* pV, u32 psxV, u32 mask, u32 validMask) { // assume pV is not NULL pV->flags &= ((pV->value & mask) == (psxV & mask)) ? ALL : (ALL ^ (validMask)); } -double f16Sign(double in) +double ALWAYS_INLINE_RELEASE f16Sign(double in) { u32 s = (u32)(in * (double)((u32)1 << 16)); return ((double)*((s32*)&s)) / (double)((s32)1 << 16); } -double f16Unsign(double in) +double ALWAYS_INLINE_RELEASE f16Unsign(double in) { return (in >= 0) ? in : ((double)in + (double)USHRT_MAX + 1); } -double f16Overflow(double in) +double ALWAYS_INLINE_RELEASE f16Overflow(double in) { double out = 0; s64 v = ((s64)in) >> 16; @@ -1310,7 +1310,7 @@ void CPU_SLTU(u32 instr, u32 rdVal, u32 rsVal, u32 rtVal) // Register mult/div //////////////////////////////////// -void CPU_MULT(u32 instr, u32 hiVal, u32 loVal, u32 rsVal, u32 rtVal) +void CPU_MULT(u32 instr, u32 rsVal, u32 rtVal) { // Hi/Lo = Rs * Rt (signed) Validate(&CPU_reg[rs(instr)], rsVal); @@ -1352,11 +1352,13 @@ void CPU_MULT(u32 instr, u32 hiVal, u32 loVal, u32 rsVal, u32 rtVal) CPU_Hi.x = (float)f16Sign(hx); CPU_Hi.y = (float)f16Sign(hy); - CPU_Lo.value = loVal; - CPU_Hi.value = hiVal; + // compute PSX value + const u64 result = static_cast(static_cast(SignExtend64(rsVal)) * static_cast(SignExtend64(rtVal))); + CPU_Hi.value = Truncate32(result >> 32); + CPU_Lo.value = Truncate32(result); } -void CPU_MULTU(u32 instr, u32 hiVal, u32 loVal, u32 rsVal, u32 rtVal) +void CPU_MULTU(u32 instr, u32 rsVal, u32 rtVal) { // Hi/Lo = Rs * Rt (unsigned) Validate(&CPU_reg[rs(instr)], rsVal); @@ -1398,11 +1400,13 @@ void CPU_MULTU(u32 instr, u32 hiVal, u32 loVal, u32 rsVal, u32 rtVal) CPU_Hi.x = (float)f16Sign(hx); CPU_Hi.y = (float)f16Sign(hy); - CPU_Lo.value = loVal; - CPU_Hi.value = hiVal; + // compute PSX value + const u64 result = ZeroExtend64(rsVal) * ZeroExtend64(rtVal); + CPU_Hi.value = Truncate32(result >> 32); + CPU_Lo.value = Truncate32(result); } -void CPU_DIV(u32 instr, u32 hiVal, u32 loVal, u32 rsVal, u32 rtVal) +void CPU_DIV(u32 instr, u32 rsVal, u32 rtVal) { // Lo = Rs / Rt (signed) // Hi = Rs % Rt (signed) @@ -1431,11 +1435,27 @@ void CPU_DIV(u32 instr, u32 hiVal, u32 loVal, u32 rsVal, u32 rtVal) CPU_Hi.y = (float)f16Sign(f16Overflow(hi)); CPU_Hi.x = (float)f16Sign(hi); - CPU_Lo.value = loVal; - CPU_Hi.value = hiVal; + // compute PSX value + if (static_cast(rtVal) == 0) + { + // divide by zero + CPU_Lo.value = (static_cast(rsVal) >= 0) ? UINT32_C(0xFFFFFFFF) : UINT32_C(1); + CPU_Hi.value = static_cast(static_cast(rsVal)); + } + else if (rsVal == UINT32_C(0x80000000) && static_cast(rtVal) == -1) + { + // unrepresentable + CPU_Lo.value = UINT32_C(0x80000000); + CPU_Hi.value = 0; + } + else + { + CPU_Lo.value = static_cast(static_cast(rsVal) / static_cast(rtVal)); + CPU_Hi.value = static_cast(static_cast(rsVal) % static_cast(rtVal)); + } } -void CPU_DIVU(u32 instr, u32 hiVal, u32 loVal, u32 rsVal, u32 rtVal) +void CPU_DIVU(u32 instr, u32 rsVal, u32 rtVal) { // Lo = Rs / Rt (unsigned) // Hi = Rs % Rt (unsigned) @@ -1464,8 +1484,17 @@ void CPU_DIVU(u32 instr, u32 hiVal, u32 loVal, u32 rsVal, u32 rtVal) CPU_Hi.y = (float)f16Sign(f16Overflow(hi)); CPU_Hi.x = (float)f16Sign(hi); - CPU_Lo.value = loVal; - CPU_Hi.value = hiVal; + if (rtVal == 0) + { + // divide by zero + CPU_Lo.value = UINT32_C(0xFFFFFFFF); + CPU_Hi.value = rsVal; + } + else + { + CPU_Lo.value = rsVal / rtVal; + CPU_Hi.value = rsVal % rtVal; + } } //////////////////////////////////// diff --git a/src/core/pgxp.h b/src/core/pgxp.h index 038485c5c..0a497fe56 100644 --- a/src/core/pgxp.h +++ b/src/core/pgxp.h @@ -76,10 +76,10 @@ void CPU_SLT(u32 instr, u32 rdVal, u32 rsVal, u32 rtVal); void CPU_SLTU(u32 instr, u32 rdVal, u32 rsVal, u32 rtVal); // Register mult/div -void CPU_MULT(u32 instr, u32 hiVal, u32 loVal, u32 rsVal, u32 rtVal); -void CPU_MULTU(u32 instr, u32 hiVal, u32 loVal, u32 rsVal, u32 rtVal); -void CPU_DIV(u32 instr, u32 hiVal, u32 loVal, u32 rsVal, u32 rtVal); -void CPU_DIVU(u32 instr, u32 hiVal, u32 loVal, u32 rsVal, u32 rtVal); +void CPU_MULT(u32 instr, u32 rsVal, u32 rtVal); +void CPU_MULTU(u32 instr, u32 rsVal, u32 rtVal); +void CPU_DIV(u32 instr, u32 rsVal, u32 rtVal); +void CPU_DIVU(u32 instr, u32 rsVal, u32 rtVal); // Shift operations (sa) void CPU_SLL(u32 instr, u32 rdVal, u32 rtVal);