diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h index af4bc6dd3d..d3a4487c4c 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h @@ -94,6 +94,13 @@ inline double ForceDouble(double d) return d; } +inline double Force25Bit(double d) +{ + u64 di = *(u64*)&d; + di = (di & 0xFFFFFFFFF8000000ULL) + (di & 0x8000000); + return *(double*)&di; +} + // these functions allow globally modify operations behaviour // also, these may be used to set flags like FR, FI, OX, UX diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp index d3df8716f5..f0ef426e5f 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp @@ -297,7 +297,8 @@ void Interpreter::fmulx(UGeckoInstruction _inst) } void Interpreter::fmulsx(UGeckoInstruction _inst) { - double d_value = NI_mul(rPS0(_inst.FA), rPS0(_inst.FC)); + double c_value = Force25Bit(rPS0(_inst.FC)); + double d_value = NI_mul(rPS0(_inst.FA), c_value); rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(d_value); //FPSCR.FI = d_value != rPS0(_inst.FD); FPSCR.FI = 0; @@ -320,7 +321,8 @@ void Interpreter::fmaddx(UGeckoInstruction _inst) void Interpreter::fmaddsx(UGeckoInstruction _inst) { - double d_value = NI_madd( rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB) ); + double c_value = Force25Bit(rPS0(_inst.FC)); + double d_value = NI_madd(rPS0(_inst.FA), c_value, rPS0(_inst.FB)); rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(d_value); FPSCR.FI = d_value != rPS0(_inst.FD); FPSCR.FR = 0; diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Paired.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Paired.cpp index bf47c351dc..0888e79042 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Paired.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Paired.cpp @@ -264,8 +264,10 @@ void Interpreter::ps_add(UGeckoInstruction _inst) void Interpreter::ps_mul(UGeckoInstruction _inst) { - rPS0(_inst.FD) = ForceSingle(NI_mul(rPS0(_inst.FA), rPS0(_inst.FC))); - rPS1(_inst.FD) = ForceSingle(NI_mul(rPS1(_inst.FA), rPS1(_inst.FC))); + double c0 = Force25Bit(rPS0(_inst.FC)); + double c1 = Force25Bit(rPS1(_inst.FC)); + rPS0(_inst.FD) = ForceSingle(NI_mul(rPS0(_inst.FA), c0)); + rPS1(_inst.FD) = ForceSingle(NI_mul(rPS1(_inst.FA), c1)); UpdateFPRF(rPS0(_inst.FD)); if (_inst.Rc) @@ -275,8 +277,10 @@ void Interpreter::ps_mul(UGeckoInstruction _inst) void Interpreter::ps_msub(UGeckoInstruction _inst) { - rPS0(_inst.FD) = ForceSingle(NI_msub(rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB))); - rPS1(_inst.FD) = ForceSingle(NI_msub(rPS1(_inst.FA), rPS1(_inst.FC), rPS1(_inst.FB))); + double c0 = Force25Bit(rPS0(_inst.FC)); + double c1 = Force25Bit(rPS1(_inst.FC)); + rPS0(_inst.FD) = ForceSingle(NI_msub(rPS0(_inst.FA), c0, rPS0(_inst.FB))); + rPS1(_inst.FD) = ForceSingle(NI_msub(rPS1(_inst.FA), c1, rPS1(_inst.FB))); UpdateFPRF(rPS0(_inst.FD)); if (_inst.Rc) @@ -285,8 +289,10 @@ void Interpreter::ps_msub(UGeckoInstruction _inst) void Interpreter::ps_madd(UGeckoInstruction _inst) { - rPS0(_inst.FD) = ForceSingle(NI_madd(rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB))); - rPS1(_inst.FD) = ForceSingle(NI_madd(rPS1(_inst.FA), rPS1(_inst.FC), rPS1(_inst.FB))); + double c0 = Force25Bit(rPS0(_inst.FC)); + double c1 = Force25Bit(rPS1(_inst.FC)); + rPS0(_inst.FD) = ForceSingle(NI_madd(rPS0(_inst.FA), c0, rPS0(_inst.FB))); + rPS1(_inst.FD) = ForceSingle(NI_madd(rPS1(_inst.FA), c1, rPS1(_inst.FB))); UpdateFPRF(rPS0(_inst.FD)); if (_inst.Rc) @@ -295,8 +301,10 @@ void Interpreter::ps_madd(UGeckoInstruction _inst) void Interpreter::ps_nmsub(UGeckoInstruction _inst) { - rPS0(_inst.FD) = ForceSingle( -NI_msub( rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB) ) ); - rPS1(_inst.FD) = ForceSingle( -NI_msub( rPS1(_inst.FA), rPS1(_inst.FC), rPS1(_inst.FB) ) ); + double c0 = Force25Bit(rPS0(_inst.FC)); + double c1 = Force25Bit(rPS1(_inst.FC)); + rPS0(_inst.FD) = ForceSingle(-NI_msub(rPS0(_inst.FA), c0, rPS0(_inst.FB))); + rPS1(_inst.FD) = ForceSingle(-NI_msub(rPS1(_inst.FA), c1, rPS1(_inst.FB))); UpdateFPRF(rPS0(_inst.FD)); if (_inst.Rc) @@ -305,8 +313,10 @@ void Interpreter::ps_nmsub(UGeckoInstruction _inst) void Interpreter::ps_nmadd(UGeckoInstruction _inst) { - rPS0(_inst.FD) = ForceSingle( -NI_madd( rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB) ) ); - rPS1(_inst.FD) = ForceSingle( -NI_madd( rPS1(_inst.FA), rPS1(_inst.FC), rPS1(_inst.FB) ) ); + double c0 = Force25Bit(rPS0(_inst.FC)); + double c1 = Force25Bit(rPS1(_inst.FC)); + rPS0(_inst.FD) = ForceSingle(-NI_madd(rPS0(_inst.FA), c0, rPS0(_inst.FB))); + rPS1(_inst.FD) = ForceSingle(-NI_madd(rPS1(_inst.FA), c1, rPS1(_inst.FB))); UpdateFPRF(rPS0(_inst.FD)); if (_inst.Rc) @@ -339,8 +349,9 @@ void Interpreter::ps_sum1(UGeckoInstruction _inst) void Interpreter::ps_muls0(UGeckoInstruction _inst) { - double p0 = ForceSingle(NI_mul(rPS0(_inst.FA), rPS0(_inst.FC))); - double p1 = ForceSingle(NI_mul(rPS1(_inst.FA), rPS0(_inst.FC))); + double c0 = Force25Bit(rPS1(_inst.FC)); + double p0 = ForceSingle(NI_mul(rPS0(_inst.FA), c0)); + double p1 = ForceSingle(NI_mul(rPS1(_inst.FA), c0)); rPS0(_inst.FD) = p0; rPS1(_inst.FD) = p1; UpdateFPRF(rPS0(_inst.FD)); @@ -351,8 +362,9 @@ void Interpreter::ps_muls0(UGeckoInstruction _inst) void Interpreter::ps_muls1(UGeckoInstruction _inst) { - double p0 = ForceSingle(NI_mul(rPS0(_inst.FA), rPS1(_inst.FC))); - double p1 = ForceSingle(NI_mul(rPS1(_inst.FA), rPS1(_inst.FC))); + double c1 = Force25Bit(rPS1(_inst.FC)); + double p0 = ForceSingle(NI_mul(rPS0(_inst.FA), c1)); + double p1 = ForceSingle(NI_mul(rPS1(_inst.FA), c1)); rPS0(_inst.FD) = p0; rPS1(_inst.FD) = p1; UpdateFPRF(rPS0(_inst.FD)); @@ -363,8 +375,10 @@ void Interpreter::ps_muls1(UGeckoInstruction _inst) void Interpreter::ps_madds0(UGeckoInstruction _inst) { - double p0 = ForceSingle( NI_madd( rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB)) ); - double p1 = ForceSingle( NI_madd( rPS1(_inst.FA), rPS0(_inst.FC), rPS1(_inst.FB)) ); + double c0 = Force25Bit(rPS0(_inst.FC)); + double c1 = Force25Bit(rPS1(_inst.FC)); + double p0 = ForceSingle(NI_madd(rPS0(_inst.FA), c0, rPS0(_inst.FB))); + double p1 = ForceSingle(NI_madd(rPS1(_inst.FA), c1, rPS1(_inst.FB))); rPS0(_inst.FD) = p0; rPS1(_inst.FD) = p1; UpdateFPRF(rPS0(_inst.FD)); @@ -375,8 +389,10 @@ void Interpreter::ps_madds0(UGeckoInstruction _inst) void Interpreter::ps_madds1(UGeckoInstruction _inst) { - double p0 = ForceSingle( NI_madd( rPS0(_inst.FA), rPS1(_inst.FC), rPS0(_inst.FB)) ); - double p1 = ForceSingle( NI_madd( rPS1(_inst.FA), rPS1(_inst.FC), rPS1(_inst.FB)) ); + double c0 = Force25Bit(rPS0(_inst.FC)); + double c1 = Force25Bit(rPS1(_inst.FC)); + double p0 = ForceSingle(NI_madd(rPS0(_inst.FA), c0, rPS0(_inst.FB))); + double p1 = ForceSingle(NI_madd(rPS1(_inst.FA), c1, rPS1(_inst.FB))); rPS0(_inst.FD) = p0; rPS1(_inst.FD) = p1; UpdateFPRF(rPS0(_inst.FD));