Fix system time wraparound

Implement utils::udiv128, utils::div128
This commit is contained in:
Nekotekina 2019-08-30 19:47:31 +03:00
parent 7f99de36c1
commit 81a110f346
2 changed files with 60 additions and 3 deletions

View File

@ -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

View File

@ -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<s64> sec, vm::ptr<s64> 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<s64> sec, vm::ptr<s64> 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
{