[a64] Implement raw clock source

Uses `CNTFRQ` and `CNTVCT` system-registers as a raw clock source.

On my ThinkPad x13s, the raw clock source returns a tick-frequency of
19,200,000 while the platform clock source(QueryPerformanceFrequency)
returns 10,000,000. Almost double the accuracy over the platform-clock!
This commit is contained in:
Wunkolo 2024-05-27 11:31:24 -07:00
parent 63f31d5741
commit 3b1a696dd6
3 changed files with 55 additions and 2 deletions

View File

@ -21,8 +21,9 @@ DEFINE_bool(clock_no_scaling, false,
"Guest system time is directly pulled from host.",
"CPU");
DEFINE_bool(clock_source_raw, false,
"Use the RDTSC instruction as the time source. "
"Host CPU must support invariant TSC.",
"On x64, Use the RDTSC instruction as the time source. Requires "
"invariant TSC. "
"On a64, Use the CNTVCT_EL0 register as the time source",
"CPU");
namespace xe {

View File

@ -18,6 +18,8 @@
#if XE_ARCH_AMD64
#define XE_CLOCK_RAW_AVAILABLE 1
#elif XE_ARCH_ARM64
#define XE_CLOCK_RAW_AVAILABLE 1
#endif
DECLARE_bool(clock_no_scaling);

View File

@ -0,0 +1,50 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2024 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/base/clock.h"
#include "xenia/base/platform.h"
#if XE_ARCH_ARM64 && XE_CLOCK_RAW_AVAILABLE
#include "xenia/base/logging.h"
#ifdef _MSC_VER
#include <arm64_neon.h>
#include <intrin.h>
#else
#include <arm_neon.h>
#endif
// Wrap all these different cpu compiler intrinsics.
#if XE_COMPILER_MSVC
constexpr int32_t CNTFRQ_EL0 = ARM64_SYSREG(3, 3, 14, 0, 0);
constexpr int32_t CNTVCT_EL0 = ARM64_SYSREG(3, 3, 14, 0, 2);
#define xe_cpu_mrs(reg) _ReadStatusReg(reg)
#elif XE_COMPILER_CLANG || XE_COMPILER_GNUC
constexpr int32_t CNTFRQ_EL0 = 0b11'011'1110'0000'000;
constexpr int32_t CNTVCT_EL0 = 0b11'011'1110'0000'010;
uint64_t xe_cpu_mrs(uint32_t reg) {
uint64_t result;
__asm__ volatile("mrs \t%0," #reg : "=r"(result));
return result;
}
#else
#error \
"No cpu instruction wrappers xe_cpu_mrs(CNTVCT_EL0); for current compiler implemented."
#endif
namespace xe {
uint64_t Clock::host_tick_frequency_raw() { return xe_cpu_mrs(CNTFRQ_EL0); }
uint64_t Clock::host_tick_count_raw() { return xe_cpu_mrs(CNTVCT_EL0); }
} // namespace xe
#endif