From 5b9c13b23fe77c1e185236449fb9cde0306e87e8 Mon Sep 17 00:00:00 2001 From: Wunkolo Date: Tue, 24 Mar 2026 10:24:38 -0700 Subject: [PATCH] [a64] Implement raw clock with `CNTVCT_EL0` Implements a raw clock by directly accessing the `CNTVCT_EL0` and `CNTFRQ_EL0` registers by using `mrs` intrinsics. Should allow for a raw-clock to work on all ARM platforms without having to make a per-platform implementation for any further a64 platforms like MacOS or Linux or Android and such. --- src/xenia/base/clock.cc | 5 +++-- src/xenia/base/clock.h | 2 +- src/xenia/base/clock_arm64.cc | 37 +++++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 src/xenia/base/clock_arm64.cc diff --git a/src/xenia/base/clock.cc b/src/xenia/base/clock.cc index 7d2a168e9..527c5eb6b 100644 --- a/src/xenia/base/clock.cc +++ b/src/xenia/base/clock.cc @@ -26,8 +26,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 { diff --git a/src/xenia/base/clock.h b/src/xenia/base/clock.h index f843aa868..28e7a40a3 100644 --- a/src/xenia/base/clock.h +++ b/src/xenia/base/clock.h @@ -16,7 +16,7 @@ #include "xenia/base/cvar.h" #include "xenia/base/platform.h" -#if XE_ARCH_AMD64 +#if XE_ARCH_AMD64 || XE_ARCH_ARM64 #define XE_CLOCK_RAW_AVAILABLE 1 #endif diff --git a/src/xenia/base/clock_arm64.cc b/src/xenia/base/clock_arm64.cc new file mode 100644 index 000000000..2021b1534 --- /dev/null +++ b/src/xenia/base/clock_arm64.cc @@ -0,0 +1,37 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2026 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 + +// Wrap all these different cpu compiler intrinsics. +// So no inline assembler here and the compiler will remove the clutter. +#if XE_COMPILER_MSVC +#include +constexpr uint32_t CNTFRQ_EL0 = ARM64_SYSREG(3, 3, 14, 0, 0); +constexpr uint32_t CNTVCT_EL0 = ARM64_SYSREG(3, 3, 14, 0, 2); +#define xe_cpu_mrs(reg) _ReadStatusReg(reg) +#elif XE_COMPILER_CLANG || XE_COMPILER_GNUC +#include +#define xe_cpu_mrs(reg) __arm_rsr64(#reg) +#else +#error "No cpu instruction wrappers for current compiler implemented." +#endif + +namespace xe { +XE_NOINLINE +uint64_t Clock::host_tick_frequency_raw() { return xe_cpu_mrs(CNTFRQ_EL0); } +XE_NOINLINE +uint64_t Clock::host_tick_count_raw() { return xe_cpu_mrs(CNTVCT_EL0); } + +} // namespace xe + +#endif