From 97222b6de03b2f7654639a88400e8c98e7198140 Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Tue, 5 Jun 2018 10:54:54 +0100 Subject: [PATCH] Fixed-Point alternative implementation for rdtsc replacement Both slightly faster, and more accurate than the previous implementation Thanks haxar! --- src/CxbxKrnl/EmuDSound.cpp | 3 +- src/CxbxKrnl/EmuKrnlKe.cpp | 61 +++++++++++++++++++++----------------- 2 files changed, 35 insertions(+), 29 deletions(-) diff --git a/src/CxbxKrnl/EmuDSound.cpp b/src/CxbxKrnl/EmuDSound.cpp index 3ddaf99c0..7ccd46b97 100755 --- a/src/CxbxKrnl/EmuDSound.cpp +++ b/src/CxbxKrnl/EmuDSound.cpp @@ -70,7 +70,6 @@ namespace xboxkrnl { // TODO: Move these to LLE APUDevice once we have one! #define APU_TIMER_FREQUENCY 48000 -extern LARGE_INTEGER NativePerformanceFrequency; LARGE_INTEGER APUInitialPerformanceCounter; double NativeToXboxAPU_FactorForPerformanceFrequency = 0; @@ -78,7 +77,7 @@ void ResetApuTimer() { // Measure current host performance counter and frequency QueryPerformanceCounter(&APUInitialPerformanceCounter); - NativeToXboxAPU_FactorForPerformanceFrequency = (double)APU_TIMER_FREQUENCY / NativePerformanceFrequency.QuadPart; + NativeToXboxAPU_FactorForPerformanceFrequency = (double)APU_TIMER_FREQUENCY / APUInitialPerformanceCounter.QuadPart; } uint32_t GetAPUTime() diff --git a/src/CxbxKrnl/EmuKrnlKe.cpp b/src/CxbxKrnl/EmuKrnlKe.cpp index b769f440c..b285da7cf 100644 --- a/src/CxbxKrnl/EmuKrnlKe.cpp +++ b/src/CxbxKrnl/EmuKrnlKe.cpp @@ -240,25 +240,40 @@ void InitDpcAndTimerThread() // Xbox Performance Counter Frequency = 733333333 (CPU Clock) #define XBOX_PERFORMANCE_FREQUENCY 733333333 - -LARGE_INTEGER NativePerformanceCounter = { 0 }; -LARGE_INTEGER NativePerformanceFrequency = { 0 }; -double NativeToXbox_FactorForPerformanceFrequency; +uint64_t NativeToXbox_FactorForPerformanceFrequency; void ConnectKeInterruptTimeToThunkTable(); // forward +uint64_t CxbxRdTsc(bool xbox) { + LARGE_INTEGER tsc; + + QueryPerformanceCounter(&tsc); + + if (xbox && NativeToXbox_FactorForPerformanceFrequency) { + LARGE_INTEGER scaledTsc; + scaledTsc.QuadPart = 1000000000; + scaledTsc.QuadPart *= tsc.QuadPart; + scaledTsc.QuadPart /= NativeToXbox_FactorForPerformanceFrequency; + return (uint64_t)scaledTsc.QuadPart; + } + + return (uint64_t)tsc.QuadPart; +} + +uint64_t CxbxCalibrateTsc() +{ + LARGE_INTEGER pf; + QueryPerformanceFrequency(&pf); + return pf.QuadPart; +} + void CxbxInitPerformanceCounters() { - BootTickCount = GetTickCount64(); - - // Measure current host performance counter and frequency - QueryPerformanceCounter(&NativePerformanceCounter); - QueryPerformanceFrequency(&NativePerformanceFrequency); - // TODO : If anything like speed-stepping influences this, prevent or fix it here - - // Calculate the host-to-xbox performance frequency factor, - // used the return Xbox-like results in KeQueryPerformanceCounter: - NativeToXbox_FactorForPerformanceFrequency = (double)XBOX_PERFORMANCE_FREQUENCY / NativePerformanceFrequency.QuadPart; + LARGE_INTEGER t; + t.QuadPart = 1000000000; + t.QuadPart *= CxbxCalibrateTsc(); + t.QuadPart /= XBOX_PERFORMANCE_FREQUENCY; + NativeToXbox_FactorForPerformanceFrequency = t.QuadPart; ConnectKeInterruptTimeToThunkTable(); @@ -1102,20 +1117,12 @@ XBSYSAPI EXPORTNUM(126) xboxkrnl::ULONGLONG NTAPI xboxkrnl::KeQueryPerformanceCo LOG_FUNC(); ULONGLONG ret; - ::LARGE_INTEGER PerformanceCounter; + //no matter rdtsc is patched or not, we should always return a scaled performance counter here. - - // Dxbx note : Xbox actually uses the RDTSC machine code instruction for this, - // and we we're bound to a single core, so we could do that too, but on Windows - // rdtsc is not a very stable counter, so instead, we'll use the native PeformanceCounter : - QueryPerformanceCounter(&PerformanceCounter); - - // Re-base the performance counter to increase accuracy of the following conversion : - PerformanceCounter.QuadPart -= NativePerformanceCounter.QuadPart; - // We appy a conversion factor here, to fake Xbox1-like increment-speed behaviour : - PerformanceCounter.QuadPart = (ULONGLONG)(NativeToXbox_FactorForPerformanceFrequency * PerformanceCounter.QuadPart); - - ret = PerformanceCounter.QuadPart; + DbgPrintf("host tick count : %lu\n", CxbxRdTsc(false)); + ret = CxbxRdTsc(true); + DbgPrintf("emulated tick count : %lu\n", ret); + RETURN(ret); }