Fixed-Point alternative implementation for rdtsc replacement

Both slightly faster, and more accurate than the previous implementation

Thanks haxar!
This commit is contained in:
Luke Usher 2018-06-05 10:54:54 +01:00
parent d700120994
commit 97222b6de0
2 changed files with 35 additions and 29 deletions

View File

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

View File

@ -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.
DbgPrintf("host tick count : %lu\n", CxbxRdTsc(false));
ret = CxbxRdTsc(true);
DbgPrintf("emulated tick count : %lu\n", ret);
// 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;
RETURN(ret);
}