diff options
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_64.cpp | 6 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_64.h | 1 | ||||
| -rw-r--r-- | src/core/arm/nce/patcher.cpp | 3 | ||||
| -rw-r--r-- | src/core/core.cpp | 25 | ||||
| -rw-r--r-- | src/core/core_timing.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/service/psc/time/common.h | 11 |
6 files changed, 36 insertions, 12 deletions
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index a2c0124f33..e65e38dd9e 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -180,7 +180,7 @@ u64 DynarmicCallbacks64::GetCNTPCT() { const char* value = std::getenv("EDEN_NX2_CNTPCT_PAUSE"); return value == nullptr || value[0] != '0'; }(); - if (pause_spins && ticks - m_last_cntpct < 32) { + if (pause_spins && ticks - m_last_cntpct < m_spin_ticks) { #if defined(_M_X64) || defined(__x86_64__) _mm_pause(); _mm_pause(); @@ -269,7 +269,9 @@ void ArmDynarmic64::MakeJit(Common::PageTable* page_table, std::size_t address_s config.tpidr_el0 = &m_cb->m_tpidr_el0; config.dczid_el0 = 4; config.ctr_el0 = 0x8444c004; - config.cntfrq_el0 = Hardware::CNTFREQ; + // 31.25 MHz for Switch 2 titles (Common::WallClock::SetGuestCNTFRQ, set at boot). + config.cntfrq_el0 = static_cast<u32>(Common::g_wall_clock.GetGuestCNTFRQ()); + m_cb->m_spin_ticks = config.cntfrq_el0 / 600'000; // Unpredictable instructions config.define_unpredictable_behaviour = true; diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h index acd1fe773f..66b07474c1 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.h +++ b/src/core/arm/dynarmic/arm_dynarmic_64.h @@ -66,6 +66,7 @@ public: u64 m_tpidrro_el0{}; u64 m_tpidr_el0{}; u64 m_last_cntpct{}; ///< The previous counter read (GetCNTPCT spin detection) + u64 m_spin_ticks{32}; ///< Reads closer than this (~1.7 us) count as a polling loop Kernel::KProcess* m_process{}; const bool m_debugger_enabled{}; const bool m_check_memory_access{}; diff --git a/src/core/arm/nce/patcher.cpp b/src/core/arm/nce/patcher.cpp index f21d7cacdc..72c3497f03 100644 --- a/src/core/arm/nce/patcher.cpp +++ b/src/core/arm/nce/patcher.cpp @@ -627,7 +627,7 @@ void Patcher::WriteMsrHandler(ModuleDestLabel module_dest, oaknut::XReg src_reg, } void Patcher::WriteCntfrqHandler(ModuleDestLabel module_dest, oaknut::XReg dest_reg, oaknut::VectorCodeGenerator& cg) { - cg.MOV(dest_reg, Common::WallClock::CNTFRQ); + cg.MOV(dest_reg, Common::g_wall_clock.GetGuestCNTFRQ()); // Jump back to the instruction after the emulated MRS. if (&cg == &c_pre) @@ -642,6 +642,7 @@ void Patcher::WriteCntpctHandler(ModuleDestLabel module_dest, oaknut::XReg dest_ #else static Common::WallClock clock(true, 1); #endif + clock.SetGuestCNTFRQ(Common::g_wall_clock.GetGuestCNTFRQ()); const auto factor = clock.GetGuestCNTFRQFactor(); const auto raw_factor = std::bit_cast<std::array<u64, 2>>(factor); diff --git a/src/core/core.cpp b/src/core/core.cpp index f3d224b1ce..3728ccf8f7 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -2,11 +2,13 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include <array> +#include <cstdlib> #include <atomic> #include <memory> #include <utility> #include "game_settings.h" +#include "common/cpu_features.h" #include "audio_core/audio_core.h" #include "common/fs/fs.h" #include "common/logging.h" @@ -313,16 +315,33 @@ struct System::Impl { fs_controller.InitTempStorage(); } + const bool switch2_program = + virtual_filesystem != nullptr && + IsSwitch2Program(GetGameFileFromPath(virtual_filesystem, filepath)); + // Switch 2 titles size their heap from the total memory and need the 12 GiB layout. Set it // as a per-game value, so RestoreGlobalState brings back the configured layout afterwards. - if (virtual_filesystem != nullptr && - Settings::values.memory_layout_mode.GetValue() != Settings::MemoryLayout::Memory_12Gb && - IsSwitch2Program(GetGameFileFromPath(virtual_filesystem, filepath))) { + if (switch2_program && + Settings::values.memory_layout_mode.GetValue() != Settings::MemoryLayout::Memory_12Gb) { LOG_INFO(Core, "Switch 2 program: using the 12 GiB memory layout"); Settings::values.memory_layout_mode.SetGlobal(false); Settings::values.memory_layout_mode.SetValue(Settings::MemoryLayout::Memory_12Gb); } + // The Switch 2 counter runs at 31.25 MHz and its SDK converts ticks with that constant + // (nn::os::GetSystemTickFrequency, TickManager::ConvertToTimeSpan/ConvertToTick). At 19.2 MHz + // every tick-based time in the game was off by 1.63x: elapsed times read short and a frame + // deadline in ticks waited ~27 ms. EDEN_NX2_CNTFRQ=<Hz> overrides it (A/B tests). + static const u64 forced_cntfrq = [] { + const char* value = std::getenv("EDEN_NX2_CNTFRQ"); + return value != nullptr ? std::strtoull(value, nullptr, 10) : 0ULL; + }(); + const u64 cntfrq = forced_cntfrq != 0 ? forced_cntfrq + : switch2_program ? Common::WallClock::Switch2CNTFRQ + : Common::WallClock::CNTFRQ; + Common::g_wall_clock.SetGuestCNTFRQ(cntfrq); + LOG_INFO(Core, "Guest counter frequency: {} Hz", cntfrq); + InitializeKernel(system); if (params.applet_type == Service::AM::AppletType::Application) { diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index b85bd30a58..dfc3f6f2a6 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -224,7 +224,7 @@ void CoreTiming::ResetTicks() { } u64 CoreTiming::GetClockTicks() const { - u64 fres = is_multicore ? Common::g_wall_clock.GetCNTPCT() : Common::WallClock::CPUTickToCNTPCT(cpu_ticks); + u64 fres = is_multicore ? Common::g_wall_clock.GetCNTPCT() : Common::g_wall_clock.CPUTickToGuestCNTPCT(cpu_ticks); if (const u32 target = CpuClockTargetMhz(Settings::values.cpu_clock.GetValue()); target != CPU_CLOCK_BASE_MHZ) { fres = fres * target / CPU_CLOCK_BASE_MHZ; diff --git a/src/core/hle/service/psc/time/common.h b/src/core/hle/service/psc/time/common.h index 2183fa72b8..6f7d2cb88b 100644 --- a/src/core/hle/service/psc/time/common.h +++ b/src/core/hle/service/psc/time/common.h @@ -134,12 +134,13 @@ struct OperationEvent : public Common::IntrusiveListBaseNode<OperationEvent> { Kernel::KEvent* m_event{}; }; -constexpr inline std::chrono::nanoseconds ConvertToTimeSpan(s64 ticks) { +inline std::chrono::nanoseconds ConvertToTimeSpan(s64 ticks) { constexpr auto one_second_ns{ std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()}; - constexpr s64 max{Common::WallClock::CNTFRQ * - ((std::numeric_limits<s64>::max)() / one_second_ns)}; + // The guest counter's frequency: 31.25 MHz for Switch 2 titles. + const s64 frequency{static_cast<s64>(Common::g_wall_clock.GetGuestCNTFRQ())}; + const s64 max{frequency * ((std::numeric_limits<s64>::max)() / one_second_ns)}; if (ticks > max) { return std::chrono::nanoseconds((std::numeric_limits<s64>::max)()); @@ -147,8 +148,8 @@ constexpr inline std::chrono::nanoseconds ConvertToTimeSpan(s64 ticks) { return std::chrono::nanoseconds((std::numeric_limits<s64>::min)()); } - auto a{ticks / Common::WallClock::CNTFRQ * one_second_ns}; - auto b{((ticks % Common::WallClock::CNTFRQ) * one_second_ns) / Common::WallClock::CNTFRQ}; + auto a{ticks / frequency * one_second_ns}; + auto b{((ticks % frequency) * one_second_ns) / frequency}; return std::chrono::nanoseconds(a + b); } |
