summaryrefslogtreecommitdiff
path: root/Source/Core/Common/ArmFPURoundMode.cpp
diff options
context:
space:
mode:
authorJosJuice <josjuice@gmail.com>2021-01-20 14:18:05 +0100
committerJosJuice <josjuice@gmail.com>2021-04-25 15:56:19 +0200
commitf96ee475e4ce22ec1e18cd7ae1e8ff9fd7d0893a (patch)
tree0c7ff70746bea41a51a552cc6e2c88ad55ab4a21 /Source/Core/Common/ArmFPURoundMode.cpp
parentaa3a96f048a889cc77445a320397e377baff2ba4 (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.cpp78
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