diff --git a/Utilities/asm.h b/Utilities/asm.h index ff0080e14f..a8daa32694 100644 --- a/Utilities/asm.h +++ b/Utilities/asm.h @@ -174,6 +174,32 @@ namespace utils return (x * y) >> 64; } + constexpr s64 div128(s64 high, s64 low, s64 divisor, s64* remainder = nullptr) + { + const __int128_t x = (__uint128_t{u64(high)} << 64) | u64(low); + const __int128_t r = x / divisor; + + if (remainder) + { + *remainder = x % divisor; + } + + return r; + } + + constexpr u64 udiv128(u64 high, u64 low, u64 divisor, u64* remainder = nullptr) + { + const __uint128_t x = (__uint128_t{high} << 64) | low; + const __uint128_t r = x / divisor; + + if (remainder) + { + *remainder = x % divisor; + } + + return r; + } + #elif defined(_MSC_VER) inline u8 rol8(u8 x, u8 n) { @@ -224,5 +250,31 @@ namespace utils { return __mulh(x, y); } + + inline s64 div128(s64 high, s64 low, s64 divisor, s64* remainder = nullptr) + { + s64 rem; + s64 r = _div128(high, low, divisor, &rem); + + if (remainder) + { + *remainder = rem; + } + + return r; + } + + inline u64 udiv128(u64 high, u64 low, u64 divisor, u64* remainder = nullptr) + { + u64 rem; + u64 r = _udiv128(high, low, divisor, &rem); + + if (remainder) + { + *remainder = rem; + } + + return r; + } #endif } // namespace utils diff --git a/rpcs3/Emu/Cell/lv2/sys_time.cpp b/rpcs3/Emu/Cell/lv2/sys_time.cpp index 4df32edc2d..dbf0c4c4c6 100644 --- a/rpcs3/Emu/Cell/lv2/sys_time.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_time.cpp @@ -3,6 +3,7 @@ #include "Emu/System.h" #include "Emu/Cell/ErrorCodes.h" +#include "Utilities/asm.h" #ifdef _WIN32 @@ -196,8 +197,12 @@ s32 sys_time_get_current_time(vm::ptr sec, vm::ptr nsec) LARGE_INTEGER count; verify(HERE), QueryPerformanceCounter(&count); - // get time difference in nanoseconds - const u64 diff = (count.QuadPart - s_time_aux_info.start_time) * 1000000000ull / s_time_aux_info.perf_freq; + const u64 diff_base = count.QuadPart - s_time_aux_info.start_time; + + // Get time difference in nanoseconds (using 128 bit accumulator) + const u64 diff_sl = diff_base * 1000000000ull; + const u64 diff_sh = utils::umulh64(diff_base, 1000000000ull); + const u64 diff = utils::udiv128(diff_sh, diff_sl, s_time_aux_info.perf_freq); // get time since Epoch in nanoseconds const u64 time = s_time_aux_info.start_ftime * 100u + (diff * g_cfg.core.clocks_scale / 100u); @@ -237,7 +242,7 @@ s32 sys_time_get_current_time(vm::ptr sec, vm::ptr nsec) { // Correct value if borrow encountered tv_sec -= 1; - tv_nsec = 1'000'000'000ull - (stv_nsec - tv_nsec); + tv_nsec = 1'000'000'000ull - (stv_nsec - tv_nsec); } else {