diff --git a/src/xenia/base/clock.cc b/src/xenia/base/clock.cc index 058eae43a..dd9972ad6 100644 --- a/src/xenia/base/clock.cc +++ b/src/xenia/base/clock.cc @@ -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 { diff --git a/src/xenia/base/clock.h b/src/xenia/base/clock.h index 67a3ebb67..1b57d8b52 100644 --- a/src/xenia/base/clock.h +++ b/src/xenia/base/clock.h @@ -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); diff --git a/src/xenia/base/clock_a64.cc b/src/xenia/base/clock_a64.cc new file mode 100644 index 000000000..6ca3569fe --- /dev/null +++ b/src/xenia/base/clock_a64.cc @@ -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 +#include +#else +#include +#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