From 4e9f54a4005786a2ecacd8e14a2de54271669636 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 1 Sep 2014 15:33:18 -0700 Subject: [PATCH 1/9] Require 250us lead time to start a vtimer. Matches tests, improves the threads/vtimers/delete test. --- Core/HLE/sceKernelVTimer.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Core/HLE/sceKernelVTimer.cpp b/Core/HLE/sceKernelVTimer.cpp index 11244a0180..6152f71d97 100644 --- a/Core/HLE/sceKernelVTimer.cpp +++ b/Core/HLE/sceKernelVTimer.cpp @@ -121,8 +121,8 @@ void __rescheduleVTimer(SceUID id, u32 delay) { if (error) return; - if (delay < 100) - delay = 100; + if (delay < 250) + delay = 250; __KernelScheduleVTimer(vt, vt->nvt.schedule + delay); } @@ -372,11 +372,16 @@ void __startVTimer(VTimer *vt) { vt->nvt.active = 1; vt->nvt.base = CoreTiming::GetGlobalTimeUs(); + u64 delay = vt->nvt.schedule; + if (delay < 250) + delay = 250; if (vt->nvt.handlerAddr != 0) - __KernelScheduleVTimer(vt, vt->nvt.schedule); + __KernelScheduleVTimer(vt, delay); } u32 sceKernelStartVTimer(SceUID uid) { + hleEatCycles(12200); + if (uid == runningVTimer) { WARN_LOG(SCEKERNEL, "sceKernelStartVTimer(%08x): invalid vtimer", uid); return SCE_KERNEL_ERROR_ILLEGAL_VTID; From 2cad35ad595f52a7700d65c93fc1592be4d73c26 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 1 Sep 2014 15:57:37 -0700 Subject: [PATCH 2/9] Put a 250us minimum on all vtimer scheduling. --- Core/HLE/sceKernelVTimer.cpp | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/Core/HLE/sceKernelVTimer.cpp b/Core/HLE/sceKernelVTimer.cpp index 6152f71d97..08c2cebc12 100644 --- a/Core/HLE/sceKernelVTimer.cpp +++ b/Core/HLE/sceKernelVTimer.cpp @@ -99,15 +99,14 @@ void __KernelScheduleVTimer(VTimer *vt, u64 schedule) { // The "real" base is base + current. But when setting the time, base is important. // The schedule is relative to those. u64 cyclesIntoFuture; - // It seems like the minimum is approximately 200us? - if (schedule < __getVTimerCurrentTime(vt)) + if (schedule < 250) { + schedule = 250; + } + u64 goalUs = vt->nvt.base + schedule - vt->nvt.current; + if (goalUs < CoreTiming::GetGlobalTimeUs()) { cyclesIntoFuture = usToCycles(200); - else { - u64 goalUs = vt->nvt.base + schedule - vt->nvt.current; - if (goalUs < CoreTiming::GetGlobalTimeUs()) - cyclesIntoFuture = usToCycles(200); - else - cyclesIntoFuture = usToCycles(goalUs - CoreTiming::GetGlobalTimeUs()); + } else { + cyclesIntoFuture = usToCycles(goalUs - CoreTiming::GetGlobalTimeUs()); } CoreTiming::ScheduleEvent(cyclesIntoFuture, vtimerTimer, vt->GetUID()); @@ -121,9 +120,6 @@ void __rescheduleVTimer(SceUID id, u32 delay) { if (error) return; - if (delay < 250) - delay = 250; - __KernelScheduleVTimer(vt, vt->nvt.schedule + delay); } @@ -372,11 +368,8 @@ void __startVTimer(VTimer *vt) { vt->nvt.active = 1; vt->nvt.base = CoreTiming::GetGlobalTimeUs(); - u64 delay = vt->nvt.schedule; - if (delay < 250) - delay = 250; if (vt->nvt.handlerAddr != 0) - __KernelScheduleVTimer(vt, delay); + __KernelScheduleVTimer(vt, vt->nvt.schedule); } u32 sceKernelStartVTimer(SceUID uid) { @@ -432,6 +425,7 @@ u32 sceKernelStopVTimer(SceUID uid) { } u32 sceKernelSetVTimerHandler(SceUID uid, u32 scheduleAddr, u32 handlerFuncAddr, u32 commonAddr) { + hleEatCycles(900); if (uid == runningVTimer) { WARN_LOG(SCEKERNEL, "sceKernelSetVTimerHandler(%08x, %08x, %08x, %08x): invalid vtimer", uid, scheduleAddr, handlerFuncAddr, commonAddr); return SCE_KERNEL_ERROR_ILLEGAL_VTID; @@ -446,6 +440,7 @@ u32 sceKernelSetVTimerHandler(SceUID uid, u32 scheduleAddr, u32 handlerFuncAddr, } DEBUG_LOG(SCEKERNEL, "sceKernelSetVTimerHandler(%08x, %08x, %08x, %08x)", uid, scheduleAddr, handlerFuncAddr, commonAddr); + hleEatCycles(2000); u64 schedule = Memory::Read_U64(scheduleAddr); vt->nvt.handlerAddr = handlerFuncAddr; @@ -460,6 +455,7 @@ u32 sceKernelSetVTimerHandler(SceUID uid, u32 scheduleAddr, u32 handlerFuncAddr, } u32 sceKernelSetVTimerHandlerWide(SceUID uid, u64 schedule, u32 handlerFuncAddr, u32 commonAddr) { + hleEatCycles(900); if (uid == runningVTimer) { WARN_LOG(SCEKERNEL, "sceKernelSetVTimerHandlerWide(%08x, %llu, %08x, %08x): invalid vtimer", uid, schedule, handlerFuncAddr, commonAddr); return SCE_KERNEL_ERROR_ILLEGAL_VTID; From f78712ec3aad91c4664e9d8709b1ab4282052a68 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 1 Sep 2014 16:56:26 -0700 Subject: [PATCH 3/9] Simplify alarm timing. This is from when it seemed like sceKernelSetAlarm() was by cycles. Corrects handling of large timer / sysclock params. --- Core/HLE/sceKernelAlarm.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Core/HLE/sceKernelAlarm.cpp b/Core/HLE/sceKernelAlarm.cpp index 6b1891686e..6bd1a89ee9 100644 --- a/Core/HLE/sceKernelAlarm.cpp +++ b/Core/HLE/sceKernelAlarm.cpp @@ -57,7 +57,7 @@ struct Alarm : public KernelObject NativeAlarm alm; }; -void __KernelScheduleAlarm(Alarm *alarm, u64 ticks); +void __KernelScheduleAlarm(Alarm *alarm, u64 micro); class AlarmIntrHandler : public IntrHandler { @@ -96,7 +96,7 @@ public: DEBUG_LOG(SCEKERNEL, "Rescheduling alarm %08x for +%dms", alarmID, result); u32 error; Alarm *alarm = kernelObjects.Get(alarmID, error); - __KernelScheduleAlarm(alarm, (u64) usToCycles(result)); + __KernelScheduleAlarm(alarm, result); } else { @@ -150,13 +150,13 @@ KernelObject *__KernelAlarmObject() return new Alarm; } -void __KernelScheduleAlarm(Alarm *alarm, u64 ticks) +void __KernelScheduleAlarm(Alarm *alarm, u64 micro) { - alarm->alm.schedule = CoreTiming::GetGlobalTimeUs() + ticks / (u64) CoreTiming::GetClockFrequencyMHz(); - CoreTiming::ScheduleEvent((int) ticks, alarmTimer, alarm->GetUID()); + alarm->alm.schedule = CoreTiming::GetGlobalTimeUs() + micro; + CoreTiming::ScheduleEvent(usToCycles(micro), alarmTimer, alarm->GetUID()); } -SceUID __KernelSetAlarm(u64 ticks, u32 handlerPtr, u32 commonPtr) +SceUID __KernelSetAlarm(u64 micro, u32 handlerPtr, u32 commonPtr) { if (!Memory::IsValidAddress(handlerPtr)) return SCE_KERNEL_ERROR_ILLEGAL_ADDR; @@ -168,14 +168,14 @@ SceUID __KernelSetAlarm(u64 ticks, u32 handlerPtr, u32 commonPtr) alarm->alm.handlerPtr = handlerPtr; alarm->alm.commonPtr = commonPtr; - __KernelScheduleAlarm(alarm, ticks); + __KernelScheduleAlarm(alarm, micro); return uid; } SceUID sceKernelSetAlarm(SceUInt micro, u32 handlerPtr, u32 commonPtr) { DEBUG_LOG(SCEKERNEL, "sceKernelSetAlarm(%d, %08x, %08x)", micro, handlerPtr, commonPtr); - return __KernelSetAlarm(usToCycles((u64) micro), handlerPtr, commonPtr); + return __KernelSetAlarm((u64) micro, handlerPtr, commonPtr); } SceUID sceKernelSetSysClockAlarm(u32 microPtr, u32 handlerPtr, u32 commonPtr) @@ -188,7 +188,7 @@ SceUID sceKernelSetSysClockAlarm(u32 microPtr, u32 handlerPtr, u32 commonPtr) return -1; DEBUG_LOG(SCEKERNEL, "sceKernelSetSysClockAlarm(%lld, %08x, %08x)", micro, handlerPtr, commonPtr); - return __KernelSetAlarm(usToCycles(micro), handlerPtr, commonPtr); + return __KernelSetAlarm(micro, handlerPtr, commonPtr); } int sceKernelCancelAlarm(SceUID uid) From a42a2864a66b0b7805cfdd99f53641bcc299fbd2 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 1 Sep 2014 20:02:56 -0700 Subject: [PATCH 4/9] Protect against vtimers scheduled in past. --- Core/HLE/sceKernelVTimer.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Core/HLE/sceKernelVTimer.cpp b/Core/HLE/sceKernelVTimer.cpp index 08c2cebc12..2ed7ac3a08 100644 --- a/Core/HLE/sceKernelVTimer.cpp +++ b/Core/HLE/sceKernelVTimer.cpp @@ -102,9 +102,10 @@ void __KernelScheduleVTimer(VTimer *vt, u64 schedule) { if (schedule < 250) { schedule = 250; } - u64 goalUs = vt->nvt.base + schedule - vt->nvt.current; - if (goalUs < CoreTiming::GetGlobalTimeUs()) { - cyclesIntoFuture = usToCycles(200); + s64 goalUs = (u64)vt->nvt.base + schedule - (u64)vt->nvt.current; + s64 minGoalUs = CoreTiming::GetGlobalTimeUs() + 250; + if (goalUs < minGoalUs) { + cyclesIntoFuture = usToCycles(250); } else { cyclesIntoFuture = usToCycles(goalUs - CoreTiming::GetGlobalTimeUs()); } From 6599430c044e926360ff92ef03b114ecc5257cf2 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 1 Sep 2014 11:05:50 -0700 Subject: [PATCH 5/9] Improve some timing in msgpipes. Probably not super important, but makes tests happier. Also, when unscheduling an event, return the current time left, including already spent time since last Advance. --- Core/CoreTiming.cpp | 8 ++++---- Core/HLE/sceKernelMsgPipe.cpp | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/Core/CoreTiming.cpp b/Core/CoreTiming.cpp index ba5b50232d..df50415dea 100644 --- a/Core/CoreTiming.cpp +++ b/Core/CoreTiming.cpp @@ -326,7 +326,7 @@ s64 UnscheduleEvent(int event_type, u64 userdata) { if (first->type == event_type && first->userdata == userdata) { - result = first->time - globalTimer; + result = first->time - GetTicks(); Event *next = first->next; FreeEvent(first); @@ -345,7 +345,7 @@ s64 UnscheduleEvent(int event_type, u64 userdata) { if (ptr->type == event_type && ptr->userdata == userdata) { - result = ptr->time - globalTimer; + result = ptr->time - GetTicks(); prev->next = ptr->next; FreeEvent(ptr); @@ -371,7 +371,7 @@ s64 UnscheduleThreadsafeEvent(int event_type, u64 userdata) { if (tsFirst->type == event_type && tsFirst->userdata == userdata) { - result = tsFirst->time - globalTimer; + result = tsFirst->time - GetTicks(); Event *next = tsFirst->next; FreeTsEvent(tsFirst); @@ -394,7 +394,7 @@ s64 UnscheduleThreadsafeEvent(int event_type, u64 userdata) { if (ptr->type == event_type && ptr->userdata == userdata) { - result = ptr->time - globalTimer; + result = ptr->time - GetTicks(); prev->next = ptr->next; if (ptr == tsLast) diff --git a/Core/HLE/sceKernelMsgPipe.cpp b/Core/HLE/sceKernelMsgPipe.cpp index ef4ecb3e28..98052c08f7 100644 --- a/Core/HLE/sceKernelMsgPipe.cpp +++ b/Core/HLE/sceKernelMsgPipe.cpp @@ -729,6 +729,8 @@ int sceKernelCreateMsgPipe(const char *name, int partition, u32 attr, u32 size, int sceKernelDeleteMsgPipe(SceUID uid) { + hleEatCycles(900); + u32 error; MsgPipe *m = kernelObjects.Get(uid, error); if (!m) @@ -737,6 +739,10 @@ int sceKernelDeleteMsgPipe(SceUID uid) return error; } + hleEatCycles(3100); + if (!m->sendWaitingThreads.empty() || !m->receiveWaitingThreads.empty()) + hleEatCycles(4000); + for (size_t i = 0; i < m->sendWaitingThreads.size(); i++) m->sendWaitingThreads[i].Cancel(uid, SCE_KERNEL_ERROR_WAIT_DELETE); for (size_t i = 0; i < m->receiveWaitingThreads.size(); i++) @@ -785,6 +791,8 @@ int __KernelValidateSendMsgPipe(SceUID uid, u32 sendBufAddr, u32 sendSize, int w int __KernelSendMsgPipe(MsgPipe *m, u32 sendBufAddr, u32 sendSize, int waitMode, u32 resultAddr, u32 timeoutPtr, bool cbEnabled, bool poll) { + hleEatCycles(2400); + bool needsResched = false; bool needsWait = false; @@ -962,6 +970,8 @@ int sceKernelTryReceiveMsgPipe(SceUID uid, u32 receiveBufAddr, u32 receiveSize, int sceKernelCancelMsgPipe(SceUID uid, u32 numSendThreadsAddr, u32 numReceiveThreadsAddr) { + hleEatCycles(900); + u32 error; MsgPipe *m = kernelObjects.Get(uid, error); if (!m) @@ -970,6 +980,10 @@ int sceKernelCancelMsgPipe(SceUID uid, u32 numSendThreadsAddr, u32 numReceiveThr return error; } + hleEatCycles(1100); + if (!m->sendWaitingThreads.empty() || !m->receiveWaitingThreads.empty()) + hleEatCycles(4000); + if (Memory::IsValidAddress(numSendThreadsAddr)) Memory::Write_U32((u32) m->sendWaitingThreads.size(), numSendThreadsAddr); if (Memory::IsValidAddress(numReceiveThreadsAddr)) From c5b15cc9fcf337c2e8e60d789b666ff0b0fcff67 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 1 Sep 2014 14:52:46 -0700 Subject: [PATCH 6/9] Adjust semaphore timing slightly. This matches tests a bit better. --- Core/HLE/sceKernelSemaphore.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Core/HLE/sceKernelSemaphore.cpp b/Core/HLE/sceKernelSemaphore.cpp index ae2f728d6c..347b55582b 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -359,9 +359,9 @@ void __KernelSetSemaTimeout(Semaphore *s, u32 timeoutPtr) // This happens to be how the hardware seems to time things. if (micro <= 3) - micro = 25; + micro = 24; else if (micro <= 249) - micro = 250; + micro = 245; // This should call __KernelSemaTimeout() later, unless we cancel it. CoreTiming::ScheduleEvent(usToCycles(micro), semaWaitTimer, __KernelGetCurThread()); @@ -369,11 +369,18 @@ void __KernelSetSemaTimeout(Semaphore *s, u32 timeoutPtr) int __KernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr, bool processCallbacks) { + hleEatCycles(900); + + if (wantedCount <= 0) + return SCE_KERNEL_ERROR_ILLEGAL_COUNT; + + hleEatCycles(500); + u32 error; Semaphore *s = kernelObjects.Get(id, error); if (s) { - if (wantedCount > s->ns.maxCount || wantedCount <= 0) + if (wantedCount > s->ns.maxCount) return SCE_KERNEL_ERROR_ILLEGAL_COUNT; // If there are any callbacks, we always wait, and wake after the callbacks. From 84231c018896188075cab8bad333afdd8dfbde4a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 1 Sep 2014 21:11:41 -0700 Subject: [PATCH 7/9] Eat some cycles when canceling/deleting fpls. Improves tests measuing timeouts remaining after delete. --- Core/HLE/sceKernelMemory.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp index bee423bf13..7d848ceb35 100644 --- a/Core/HLE/sceKernelMemory.cpp +++ b/Core/HLE/sceKernelMemory.cpp @@ -653,6 +653,7 @@ int sceKernelCreateFpl(const char *name, u32 mpid, u32 attr, u32 blockSize, u32 int sceKernelDeleteFpl(SceUID uid) { + hleEatCycles(600); u32 error; FPL *fpl = kernelObjects.Get(uid, error); if (fpl) @@ -833,6 +834,8 @@ retry: int sceKernelCancelFpl(SceUID uid, u32 numWaitThreadsPtr) { + hleEatCycles(600); + u32 error; FPL *fpl = kernelObjects.Get(uid, error); if (fpl) From 292380021742d17e3bd732a4f0d15d97dd9b9a63 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 1 Sep 2014 21:12:13 -0700 Subject: [PATCH 8/9] Eat some cycles when starting a thread. Seems to improve a test a bit, based on tests. --- Core/HLE/sceKernelThread.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index a2fc29fe56..2463778101 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -2274,6 +2274,7 @@ int sceKernelStartThread(SceUID threadToStartID, int argSize, u32 argBlockPtr) } INFO_LOG(SCEKERNEL, "sceKernelStartThread(thread=%i, argSize=%i, argPtr=%08x)", threadToStartID, argSize, argBlockPtr); + hleEatCycles(3400); return __KernelStartThread(threadToStartID, argSize, argBlockPtr); } From d637de8b4ce02cb51e5caa49a6e3896264f92057 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 1 Sep 2014 21:12:56 -0700 Subject: [PATCH 9/9] Eat some cycles when signaling semaphores. Seems to match tests. --- Core/HLE/sceKernelSemaphore.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Core/HLE/sceKernelSemaphore.cpp b/Core/HLE/sceKernelSemaphore.cpp index 347b55582b..236db2d20d 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -320,6 +320,7 @@ retry: if (wokeThreads) hleReSchedule("semaphore signaled"); + hleEatCycles(900); return 0; } else