From 09282023105fc65f224378b0ced125d1bfe5ed09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 28 Sep 2026 17:41:41 -0600 Subject: [PATCH] scePower: CPU clock can't exceed the PLL, float frequency to the bit scePowerSetCpuClockFrequency refuses a CPU clock above the PLL's, and scePowerGetCpuClockFrequencyFloat computes pll * n / 511 in single precision like the firmware, instead of converting whole Hz, which was off in the last digit. power/freq now passes. Co-Authored-By: Claude Opus 5.5 (1M context) --- Core/HLE/scePower.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Core/HLE/scePower.cpp b/Core/HLE/scePower.cpp index 07c5d12e52..43ca06633c 100644 --- a/Core/HLE/scePower.cpp +++ b/Core/HLE/scePower.cpp @@ -511,6 +511,10 @@ static u32 scePowerSetCpuClockFrequency(u32 cpufreq) { if (cpufreq == 0 || cpufreq > 333) { return hleLogWarning(Log::sceMisc, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid frequency"); } + // The CPU can't run faster than the PLL it's divided from. + if ((u64)cpufreq * 1000000 > (u64)pllFreq) { + return hleLogWarning(Log::sceMisc, SCE_KERNEL_ERROR_INVALID_VALUE, "above the pll frequency"); + } if (GetLockedCPUSpeedMhz() > 0) { return hleLogDebug(Log::sceMisc, 0, "locked by user config at %i", GetLockedCPUSpeedMhz()); } @@ -557,7 +561,13 @@ static u32 scePowerGetBusClockFrequencyInt() { } static float scePowerGetCpuClockFrequencyFloat() { - float cpuFreq = CoreTiming::GetClockFrequencyHz() / 1000000.0f; + // The CPU runs at a multiple of pll/511, and the firmware works the value out in single + // precision, as pll * n / 511, rather than from whole Hz - which is off in the last digit + // (power/freq). + const double step = (double)pllFreq / 511.0; + const float steps = (float)std::round(CoreTiming::GetClockFrequencyHz() / step); + const float pllMhz = (float)(pllFreq / 1000000.0); + float cpuFreq = (pllMhz * steps) / 511.0f; DEBUG_LOG(Log::sceMisc, "%f=scePowerGetCpuClockFrequencyFloat()", (float)cpuFreq); return cpuFreq; }