Interpreter: Fix rounding edge case in frsp

Fixes the Dolphin bug mentioned in
https://github.com/dolphin-emu/hwtests/issues/45.

Because this doesn't fix any observed behavior in games (no, 1080°
Avalanche isn't affected), I haven't implemented this in the JITs,
so as to not cause unnecessary performance degradations.
This commit is contained in:
JosJuice 2022-08-06 18:54:19 +02:00
parent 7b2b559743
commit c5d9514cd9

View File

@ -52,6 +52,25 @@ inline void SetFPException(UReg_FPSCR* fpscr, u32 mask)
inline float ForceSingle(const UReg_FPSCR& fpscr, double value)
{
if (fpscr.NI)
{
// Emulate a rounding quirk. If the conversion result before rounding is a subnormal single,
// it's always flushed to zero, even if rounding would have caused it to become normal.
constexpr u64 smallest_normal_single = 0x3810000000000000;
const u64 value_without_sign =
Common::BitCast<u64>(value) & (Common::DOUBLE_EXP | Common::DOUBLE_FRAC);
if (value_without_sign < smallest_normal_single)
{
const u64 flushed_double = Common::BitCast<u64>(value) & Common::DOUBLE_SIGN;
const u32 flushed_single = static_cast<u32>(flushed_double >> 32);
return Common::BitCast<float>(flushed_single);
}
}
// Emulate standard conversion to single precision.
float x = static_cast<float>(value);
if (!cpu_info.bFlushToZero && fpscr.NI)
{