diff options
| author | JosJuice <josjuice@gmail.com> | 2021-01-20 14:18:05 +0100 |
|---|---|---|
| committer | JosJuice <josjuice@gmail.com> | 2021-04-25 15:56:19 +0200 |
| commit | f96ee475e4ce22ec1e18cd7ae1e8ff9fd7d0893a (patch) | |
| tree | 0c7ff70746bea41a51a552cc6e2c88ad55ab4a21 /Source/Core/Common/ArmFPURoundMode.cpp | |
| parent | aa3a96f048a889cc77445a320397e377baff2ba4 (diff) | |
Implement ArmFPURoundMode.cpp
Fixes https://bugs.dolphin-emu.org/issues/12388. Might also fix
other games that have problems with float/paired instructions
in JitArm64, but I haven't tested any.
Diffstat (limited to 'Source/Core/Common/ArmFPURoundMode.cpp')
| -rw-r--r-- | Source/Core/Common/ArmFPURoundMode.cpp | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/Source/Core/Common/ArmFPURoundMode.cpp b/Source/Core/Common/ArmFPURoundMode.cpp new file mode 100644 index 0000000000..323e456ae7 --- /dev/null +++ b/Source/Core/Common/ArmFPURoundMode.cpp @@ -0,0 +1,78 @@ +// Copyright 2021 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "Common/CommonTypes.h" +#include "Common/FPURoundMode.h" + +#ifdef _MSC_VER +#include <intrin.h> +#endif + +static u64 GetFPCR() +{ +#ifdef _MSC_VER + return _ReadStatusReg(ARM64_FPCR); +#else + u64 fpcr; + __asm__ __volatile__("mrs %0, fpcr" : "=r"(fpcr)); + return fpcr; +#endif +} + +static void SetFPCR(u64 fpcr) +{ +#ifdef _MSC_VER + _WriteStatusReg(ARM64_FPCR, fpcr); +#else + __asm__ __volatile__("msr fpcr, %0" : : "ri"(fpcr)); +#endif +} + +namespace FPURoundMode +{ +static const u64 default_fpcr = GetFPCR(); +static u64 saved_fpcr = default_fpcr; + +void SetRoundMode(int mode) +{ + // We don't need to do anything here since SetSIMDMode is always called after calling this +} + +void SetPrecisionMode(PrecisionMode mode) +{ +} + +void SetSIMDMode(int rounding_mode, bool non_ieee_mode) +{ + // Flush-To-Zero (non-IEEE mode: denormal outputs are set to +/- 0) + constexpr u32 FZ = 1 << 24; + + // lookup table for FPSCR.RN-to-FPCR.RMode translation + constexpr u32 rounding_mode_table[] = { + (0 << 22), // nearest + (3 << 22), // zero + (1 << 22), // +inf + (2 << 22), // -inf + }; + + const u64 base = default_fpcr & ~(0b111 << 22); + SetFPCR(base | rounding_mode_table[rounding_mode] | (non_ieee_mode ? FZ : 0)); +} + +void SaveSIMDState() +{ + saved_fpcr = GetFPCR(); +} + +void LoadSIMDState() +{ + SetFPCR(saved_fpcr); +} + +void LoadDefaultSIMDState() +{ + SetFPCR(default_fpcr); +} + +} // namespace FPURoundMode |
