Merge pull request #11971 from unknownbrackets/power

Correct cpu/pll/bus hz update and rescheduling
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2019-04-16 09:41:43 +02:00
commit dcd2ff03b0
4 files changed
+159 -92

No files matched your search

+15 -18
View File
@@ -92,43 +92,40 @@ static std::mutex externalEventLock;
std::vector<MHzChangeCallback> mhzChangeCallbacks;
void FireMhzChange() {
for (auto it = mhzChangeCallbacks.begin(), end = mhzChangeCallbacks.end(); it != end; ++it) {
MHzChangeCallback cb = *it;
for (MHzChangeCallback cb : mhzChangeCallbacks) {
cb();
}
}
void SetClockFrequencyMHz(int cpuMhz)
{
void SetClockFrequencyHz(int cpuHz) {
// When the mhz changes, we keep track of what "time" it was before hand.
// This way, time always moves forward, even if mhz is changed.
lastGlobalTimeUs = GetGlobalTimeUs();
lastGlobalTimeTicks = GetTicks();
CPU_HZ = cpuMhz * 1000000;
CPU_HZ = cpuHz;
// TODO: Rescale times of scheduled events?
FireMhzChange();
}
int GetClockFrequencyMHz()
{
return CPU_HZ / 1000000;
int GetClockFrequencyHz() {
return CPU_HZ;
}
u64 GetGlobalTimeUsScaled()
{
s64 ticksSinceLast = GetTicks() - lastGlobalTimeTicks;
int freq = GetClockFrequencyMHz();
s64 usSinceLast = ticksSinceLast / freq;
return lastGlobalTimeUs + usSinceLast;
u64 GetGlobalTimeUsScaled() {
return GetGlobalTimeUs();
}
u64 GetGlobalTimeUs()
{
u64 GetGlobalTimeUs() {
s64 ticksSinceLast = GetTicks() - lastGlobalTimeTicks;
int freq = GetClockFrequencyMHz();
s64 usSinceLast = ticksSinceLast / freq;
int freq = GetClockFrequencyHz();
s64 usSinceLast = ticksSinceLast * 1000000 / freq;
if (ticksSinceLast > UINT_MAX) {
// Adjust the calculated value to avoid overflow errors.
lastGlobalTimeUs += usSinceLast;
lastGlobalTimeTicks = GetTicks();
}
return lastGlobalTimeUs + usSinceLast;
}
+3 -3
View File
@@ -67,7 +67,7 @@ inline s64 usToCycles(u64 us) {
}
inline s64 cyclesToUs(s64 cycles) {
return cycles / (CPU_HZ / 1000000);
return (cycles * CPU_HZ) / 1000000;
}
namespace CoreTiming
@@ -121,8 +121,8 @@ namespace CoreTiming
void DoState(PointerWrap &p);
void SetClockFrequencyMHz(int cpuMhz);
int GetClockFrequencyMHz();
void SetClockFrequencyHz(int cpuHz);
int GetClockFrequencyHz();
extern int slicelength;
}; // end of namespace
+2 -2
View File
@@ -1069,10 +1069,10 @@ static u32 sceDisplayGetVcount() {
}
static u32 __DisplayGetCurrentHcount() {
const static int ticksPerVblank333 = 333 * 1000000 / 60 / hCountPerVblank;
const int ticksIntoFrame = CoreTiming::GetTicks() - frameStartTicks;
const int ticksPerVblank = CoreTiming::GetClockFrequencyHz() / 60 / hCountPerVblank;
// Can't seem to produce a 0 on real hardware, offsetting by 1 makes things look right.
return 1 + (ticksIntoFrame / (CoreTiming::GetClockFrequencyMHz() * ticksPerVblank333 / 333));
return 1 + (ticksIntoFrame / ticksPerVblank);
}
static u32 __DisplayGetAccumulatedHcount() {
+139 -69
View File
@@ -57,10 +57,57 @@ static int powerCbSlots[numberOfCBPowerSlots];
static std::vector<VolatileWaitingThread> volatileWaitingThreads;
// Should this belong here, or in CoreTiming?
static int RealpllFreq = 222;
static int RealbusFreq = 111;
static int pllFreq = 222;
static int busFreq = 111;
static int RealpllFreq = 222000000;
static int RealbusFreq = 111000000;
static int pllFreq = 222000000;
static int busFreq = 111000000;
// The CPU mhz can only be a multiple of the PLL divided by 511.
int PowerCpuMhzToHz(int desired, int pllHz) {
double maxfreq = desired * 1000000.0;
double step = (double)pllHz / 511.0;
// These values seem to be locked.
if (pllHz >= 333000000 && desired == 333) {
return 333000000;
} else if (pllHz >= 222000000 && desired == 222) {
return 222000000;
}
double freq = 0;
while (freq + step < maxfreq) {
freq += step;
}
// We match the PSP's HLE funcs better when we have the same float error, it seems.
return (float)(freq / 1000000.0f) * 1000000;
}
int PowerPllMhzToHz(int mhz) {
// These seem to be the only steps it has.
if (mhz <= 190)
return 190285721;
if (mhz <= 222)
return 222000000;
if (mhz <= 266)
return 266399994;
if (mhz <= 333)
return 333000000;
return mhz * 1000000;
}
int PowerBusMhzToHz(int mhz) {
// These seem to be the only steps it has.
if (mhz <= 95)
return 95142860;
if (mhz <= 111)
return 111000000;
if (mhz <= 133)
return 133199997;
if (mhz <= 166)
return 166500000;
return mhz * 1000000;
}
void __PowerInit() {
memset(powerCbSlots, 0, sizeof(powerCbSlots));
@@ -68,15 +115,15 @@ void __PowerInit() {
volatileWaitingThreads.clear();
if (g_Config.iLockedCPUSpeed > 0) {
CoreTiming::SetClockFrequencyMHz(g_Config.iLockedCPUSpeed);
pllFreq = g_Config.iLockedCPUSpeed;
busFreq = g_Config.iLockedCPUSpeed / 2;
pllFreq = PowerPllMhzToHz(g_Config.iLockedCPUSpeed);
busFreq = PowerBusMhzToHz(pllFreq / 2000000);
CoreTiming::SetClockFrequencyHz(PowerCpuMhzToHz(g_Config.iLockedCPUSpeed, pllFreq));
} else {
pllFreq = 222;
busFreq = 111;
pllFreq = PowerPllMhzToHz(222);
busFreq = PowerBusMhzToHz(111);
}
RealpllFreq = 222;
RealbusFreq = 111;
RealpllFreq = PowerPllMhzToHz(222);
RealbusFreq = PowerBusMhzToHz(111);
}
void __PowerDoState(PointerWrap &p) {
@@ -87,17 +134,20 @@ void __PowerDoState(PointerWrap &p) {
if (s >= 2) {
p.Do(RealpllFreq);
p.Do(RealbusFreq);
}
else {
RealpllFreq = 222;
RealbusFreq = 111;
if (RealpllFreq < 1000000)
RealpllFreq = PowerPllMhzToHz(RealpllFreq);
if (RealbusFreq < 1000000)
RealbusFreq = PowerBusMhzToHz(RealbusFreq);
} else {
RealpllFreq = PowerPllMhzToHz(222);
RealbusFreq = PowerBusMhzToHz(111);
}
if (g_Config.iLockedCPUSpeed > 0) {
CoreTiming::SetClockFrequencyMHz(g_Config.iLockedCPUSpeed);
pllFreq = g_Config.iLockedCPUSpeed;
busFreq = g_Config.iLockedCPUSpeed / 2;
}
else {
pllFreq = PowerPllMhzToHz(g_Config.iLockedCPUSpeed);
busFreq = PowerBusMhzToHz(pllFreq / 2000000);
CoreTiming::SetClockFrequencyHz(PowerCpuMhzToHz(g_Config.iLockedCPUSpeed, pllFreq));
} else {
pllFreq = RealpllFreq;
busFreq = RealbusFreq;
}
@@ -372,104 +422,124 @@ static int sceKernelVolatileMemLock(int type, u32 paddr, u32 psize) {
static u32 scePowerSetClockFrequency(u32 pllfreq, u32 cpufreq, u32 busfreq) {
// 190 might (probably) be a typo for 19, but it's what the actual PSP validates against.
if (pllfreq < 19 || pllfreq < cpufreq || pllfreq > 333) {
return hleLogWarning(SCEMISC, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid pll frequency");
}
if (cpufreq == 0 || cpufreq > 333) {
WARN_LOG(HLE,"scePowerSetClockFrequency(%i,%i,%i): invalid frequency", pllfreq, cpufreq, busfreq);
return SCE_KERNEL_ERROR_INVALID_VALUE;
return hleLogWarning(SCEMISC, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid cpu frequency");
}
if (busfreq == 0 || busfreq > 166) {
return hleLogWarning(SCEMISC, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid bus frequency");
}
// TODO: More restrictions.
if (g_Config.iLockedCPUSpeed > 0) {
INFO_LOG(HLE, "scePowerSetClockFrequency(%i,%i,%i): locked by user config at %i, %i, %i", pllfreq, cpufreq, busfreq, g_Config.iLockedCPUSpeed, g_Config.iLockedCPUSpeed, busFreq);
}
else {
} else {
INFO_LOG(HLE, "scePowerSetClockFrequency(%i,%i,%i)", pllfreq, cpufreq, busfreq);
}
if (RealpllFreq != pllfreq || RealbusFreq != busfreq) {
RealpllFreq = pllfreq;
RealbusFreq = busfreq;
// Only reschedules when the stepped PLL frequency changes.
// It seems like the busfreq parameter has no effect (but can cause errors.)
if (RealpllFreq != PowerPllMhzToHz(pllfreq)) {
int oldPll = RealpllFreq / 1000000;
RealpllFreq = PowerPllMhzToHz(pllfreq);
RealbusFreq = PowerBusMhzToHz(RealpllFreq / 2000000);
if (g_Config.iLockedCPUSpeed <= 0) {
pllFreq = pllfreq;
busFreq = busfreq;
CoreTiming::SetClockFrequencyMHz(cpufreq);
pllFreq = RealpllFreq;
busFreq = RealbusFreq;
CoreTiming::SetClockFrequencyHz(PowerCpuMhzToHz(cpufreq, pllFreq));
}
return hleDelayResult(0, "scepower set clockFrequency", 150000);
// The delay depends on the source and destination frequency, most are 150ms.
int newPll = RealpllFreq / 1000000;
int usec = 150000;
if ((newPll == 190 && oldPll == 222) || (newPll == 222 && oldPll == 190))
usec = 15700;
else if ((newPll == 266 && oldPll == 333) || (newPll == 333 && oldPll == 266))
usec = 16600;
return hleDelayResult(0, "scepower set clockFrequency", usec);
}
if (g_Config.iLockedCPUSpeed <= 0)
CoreTiming::SetClockFrequencyMHz(cpufreq);
CoreTiming::SetClockFrequencyHz(PowerCpuMhzToHz(cpufreq, pllFreq));
return 0;
}
static u32 scePowerSetCpuClockFrequency(u32 cpufreq) {
if(g_Config.iLockedCPUSpeed > 0) {
DEBUG_LOG(HLE,"scePowerSetCpuClockFrequency(%i): locked by user config at %i", cpufreq, g_Config.iLockedCPUSpeed);
if (cpufreq == 0 || cpufreq > 333) {
return hleLogWarning(SCEMISC, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid frequency");
}
else {
if (cpufreq == 0 || cpufreq > 333) {
WARN_LOG(HLE,"scePowerSetCpuClockFrequency(%i): invalid frequency", cpufreq);
return SCE_KERNEL_ERROR_INVALID_VALUE;
}
CoreTiming::SetClockFrequencyMHz(cpufreq);
INFO_LOG(HLE,"scePowerSetCpuClockFrequency(%i)", cpufreq);
if (g_Config.iLockedCPUSpeed > 0) {
return hleLogDebug(SCEMISC, 0, "locked by user config at %i", g_Config.iLockedCPUSpeed);
}
return 0;
CoreTiming::SetClockFrequencyHz(PowerCpuMhzToHz(cpufreq, pllFreq));
return hleLogSuccessI(SCEMISC, 0);
}
static u32 scePowerSetBusClockFrequency(u32 busfreq) {
if(g_Config.iLockedCPUSpeed > 0) {
DEBUG_LOG(HLE,"scePowerSetBusClockFrequency(%i): locked by user config at %i", busfreq, busFreq);
if (busfreq == 0 || busfreq > 111) {
return hleLogWarning(SCEMISC, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid frequency");
}
else {
if (busfreq == 0 || busfreq > 111) {
WARN_LOG(HLE,"scePowerSetBusClockFrequency(%i): invalid frequency", busfreq);
return SCE_KERNEL_ERROR_INVALID_VALUE;
}
// TODO: It seems related to other frequencies, though.
busFreq = busfreq;
INFO_LOG_REPORT_ONCE(SetBusClockFrequency,HLE,"scePowerSetBusClockFrequency(%i)", busfreq);
if (g_Config.iLockedCPUSpeed > 0) {
return hleLogDebug(SCEMISC, 0, "locked by user config at %i", g_Config.iLockedCPUSpeed / 2);
}
return 0;
// The value passed is validated, but then doesn't seem to matter for the result.
// However, this sets a different hz than scePowerSetClockFrequency would have.
if (pllFreq <= 190)
busFreq = 94956673;
else if (pllFreq <= 222)
busFreq = 111000000;
else if (pllFreq <= 266)
busFreq = 132939331;
else if (pllFreq <= 333)
busFreq = 165848343;
else
busFreq = pllFreq / 2;
return hleLogSuccessI(SCEMISC, 0);
}
static u32 scePowerGetCpuClockFrequencyInt() {
int cpuFreq = CoreTiming::GetClockFrequencyMHz();
DEBUG_LOG(HLE,"%i=scePowerGetCpuClockFrequencyInt()", cpuFreq);
return cpuFreq;
int cpuFreq = CoreTiming::GetClockFrequencyHz() / 1000000;
return hleLogSuccessI(SCEMISC, cpuFreq);
}
static u32 scePowerGetPllClockFrequencyInt() {
INFO_LOG(HLE,"%i=scePowerGetPllClockFrequencyInt()", pllFreq);
return pllFreq;
return hleLogSuccessInfoI(SCEMISC, pllFreq / 1000000);
}
static u32 scePowerGetBusClockFrequencyInt() {
INFO_LOG(HLE,"%i=scePowerGetBusClockFrequencyInt()", busFreq);
return busFreq;
return hleLogSuccessInfoI(SCEMISC, busFreq / 1000000);
}
static float scePowerGetCpuClockFrequencyFloat() {
int cpuFreq = CoreTiming::GetClockFrequencyMHz();
DEBUG_LOG(HLE, "%f=scePowerGetCpuClockFrequencyFloat()", (float)cpuFreq);
return (float) cpuFreq;
float cpuFreq = CoreTiming::GetClockFrequencyHz() / 1000000.0f;
DEBUG_LOG(SCEMISC, "%f=scePowerGetCpuClockFrequencyFloat()", (float)cpuFreq);
return cpuFreq;
}
static float scePowerGetPllClockFrequencyFloat() {
INFO_LOG(HLE, "%f=scePowerGetPllClockFrequencyFloat()", (float)pllFreq);
return (float) pllFreq;
INFO_LOG(SCEMISC, "%f=scePowerGetPllClockFrequencyFloat()", (float)pllFreq / 1000000.0f);
return (float) pllFreq / 1000000.0f;
}
static float scePowerGetBusClockFrequencyFloat() {
INFO_LOG(HLE, "%f=scePowerGetBusClockFrequencyFloat()", (float)busFreq);
return (float) busFreq;
INFO_LOG(SCEMISC, "%f=scePowerGetBusClockFrequencyFloat()", (float)busFreq / 1000000.0f);
return (float) busFreq / 1000000.0f;
}
static int scePowerTick() {
DEBUG_LOG(HLE, "scePowerTick()");
DEBUG_LOG(SCEMISC, "scePowerTick()");
// Don't think we need to do anything.
return 0;
}
static u32 IsPSPNonFat() {
DEBUG_LOG(HLE, "%d=scePower_a85880d0_IsPSPNonFat()", g_Config.iPSPModel);
DEBUG_LOG(SCEMISC, "%d=scePower_a85880d0_IsPSPNonFat()", g_Config.iPSPModel);
return g_Config.iPSPModel;
}