summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/common/uint128.cpp24
-rw-r--r--src/common/uint128.h23
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp2
-rw-r--r--src/core/core_timing_util.cpp8
-rw-r--r--src/core/core_timing_util.h2
5 files changed, 32 insertions, 27 deletions
diff --git a/src/common/uint128.cpp b/src/common/uint128.cpp
index aea7f03e2..8548ba808 100644
--- a/src/common/uint128.cpp
+++ b/src/common/uint128.cpp
@@ -1,7 +1,25 @@
+#ifdef _MSC_VER
+#include <intrin.h>
+
+#pragma intrinsic(_umul128)
+#endif
+#include "common/uint128.h"
namespace Common {
+u128 Multiply64Into128(u64 a, u64 b) {
+#ifdef _MSC_VER
+ u128 result;
+ result[0] = _umul128(a, b, &result[1]);
+#else
+ unsigned __int128 tmp = a;
+ tmp *= b;
+ u128 result;
+ std::memcpy(&result, &tmp, sizeof(u128));
+#endif
+ return result;
+}
-std::pair<u64, u64> udiv128(u128 dividend, u64 divisor) {
+std::pair<u64, u64> Divide128On64(u128 dividend, u64 divisor) {
u64 remainder = dividend[0] % divisor;
u64 accum = dividend[0] / divisor;
if (dividend[1] == 0)
@@ -12,6 +30,10 @@ std::pair<u64, u64> udiv128(u128 dividend, u64 divisor) {
u64 second_segment = (first_segment % divisor) << 32;
accum += (second_segment / divisor);
remainder += second_segment % divisor;
+ if (remainder >= divisor) {
+ accum++;
+ remainder -= divisor;
+ }
return {accum, remainder};
}
diff --git a/src/common/uint128.h b/src/common/uint128.h
index fda313bcc..45e384c33 100644
--- a/src/common/uint128.h
+++ b/src/common/uint128.h
@@ -1,30 +1,13 @@
#include <array>
#include <cstdint>
-#include <utility>
#include <cstring>
+#include <utility>
#include "common/common_types.h"
namespace Common {
-#ifdef _MSC_VER
-#include <intrin.h>
-
-#pragma intrinsic(_umul128)
-#endif
-
-inline u128 umul128(u64 a, u64 b) {
-#ifdef _MSC_VER
-u128 result;
-result[0] = _umul128(a, b, &result[1]);
-#else
-unsigned __int128 tmp = a;
-tmp *= b;
-u128 result;
-std::memcpy(&result, &tmp, sizeof(u128));
-#endif
-return result;
-}
+u128 Multiply64Into128(u64 a, u64 b);
-std::pair<u64, u64> udiv128(u128 dividend, u64 divisor);
+std::pair<u64, u64> Divide128On64(u128 dividend, u64 divisor);
} // namespace Common
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index d36538257..25f76259b 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -120,7 +120,7 @@ public:
return std::max(parent.core_timing.GetDowncount(), 0);
}
u64 GetCNTPCT() override {
- return CpuCyclesToClockCycles(parent.core_timing.GetTicks());
+ return Timing::CpuCyclesToClockCycles(parent.core_timing.GetTicks());
}
ARM_Dynarmic& parent;
diff --git a/src/core/core_timing_util.cpp b/src/core/core_timing_util.cpp
index 8fc92560a..aab4aa697 100644
--- a/src/core/core_timing_util.cpp
+++ b/src/core/core_timing_util.cpp
@@ -7,6 +7,7 @@
#include <cinttypes>
#include <limits>
#include "common/logging/log.h"
+#include "common/uint128.h"
namespace Core::Timing {
@@ -61,10 +62,9 @@ s64 nsToCycles(u64 ns) {
}
u64 CpuCyclesToClockCycles(u64 ticks) {
- u64 result = ticks;
- result *= CNTFREQ;
- result /= BASE_CLOCK_RATE;
- return static_cast<u64>(result);
+ u128 temporal = Common::Multiply64Into128(ticks, CNTFREQ);
+ std::pair<u64, u64> result = Common::Divide128On64(temporal, BASE_CLOCK_RATE);
+ return result.first;
}
} // namespace Core::Timing
diff --git a/src/core/core_timing_util.h b/src/core/core_timing_util.h
index 545d3a260..679aa3123 100644
--- a/src/core/core_timing_util.h
+++ b/src/core/core_timing_util.h
@@ -11,7 +11,7 @@ namespace Core::Timing {
// The below clock rate is based on Switch's clockspeed being widely known as 1.020GHz
// The exact value used is of course unverified.
constexpr u64 BASE_CLOCK_RATE = 1019215872; // Switch clock speed is 1020MHz un/docked
-constexpr u64 CNTFREQ = 19200000; // Value from fusee.
+constexpr u64 CNTFREQ = 19200000; // Value from fusee.
inline s64 msToCycles(int ms) {
// since ms is int there is no way to overflow