Browse Source

Use u128 on Clock Cycles calculation.

Fernando Sahmkow 7 years ago
parent
commit
ecccfe0337

+ 23 - 1
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};
 }
 

+ 3 - 20
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

+ 1 - 1
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;

+ 4 - 4
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

+ 1 - 1
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