Thread: Better/minor accuracy for sysclock delay.

Certain negative values shouldn't cause a delay, could help if a game has
a bug.
This commit is contained in:
Unknown W. Brackets 2016-05-30 20:06:14 -07:00
parent baac12b327
commit 197f3393df
2 changed files with 27 additions and 18 deletions

View File

@ -734,8 +734,8 @@ const HLEFunction ThreadManForUser[] =
{0X71BC9871, &WrapI_II<sceKernelChangeThreadPriority>, "sceKernelChangeThreadPriority", 'i', "ii" },
{0X446D8DE6, &WrapI_CUUIUU<sceKernelCreateThread>, "sceKernelCreateThread", 'i', "sxxixx", HLE_NOT_IN_INTERRUPT },
{0X9FA03CD3, &WrapI_I<sceKernelDeleteThread>, "sceKernelDeleteThread", 'i', "i" },
{0XBD123D9E, &WrapI_U<sceKernelDelaySysClockThread>, "sceKernelDelaySysClockThread", 'i', "x", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED },
{0X1181E963, &WrapI_U<sceKernelDelaySysClockThreadCB>, "sceKernelDelaySysClockThreadCB", 'i', "x", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED },
{0XBD123D9E, &WrapI_U<sceKernelDelaySysClockThread>, "sceKernelDelaySysClockThread", 'i', "P", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED },
{0X1181E963, &WrapI_U<sceKernelDelaySysClockThreadCB>, "sceKernelDelaySysClockThreadCB", 'i', "P", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED },
{0XCEADEB47, &WrapI_U<sceKernelDelayThread>, "sceKernelDelayThread", 'i', "x", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED },
{0X68DA9E36, &WrapI_U<sceKernelDelayThreadCB>, "sceKernelDelayThreadCB", 'i', "x", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED },
{0XAA73C935, &WrapV_I<sceKernelExitThread>, "sceKernelExitThread", 'v', "i" },

View File

@ -2413,6 +2413,17 @@ static s64 __KernelDelayThreadUs(u64 usec) {
if (usec < 200) {
return 210;
}
if (usec > 0x8000000000000000ULL) {
// Wrap around (behavior seen on firmware) and potentially wake up soon.
usec -= 0x8000000000000000ULL;
}
if (usec > 0x0010000000000000ULL) {
// This will probably overflow when we convert to cycles.
// Note: converting millenia to hundreds of years. Should be safe, basically perma-delay.
usec >>= 12;
}
// It never wakes up right away. It usually takes at least 15 extra us, but let's be nicer.
return usec + 10;
}
@ -2439,40 +2450,38 @@ int sceKernelDelayThread(u32 usec) {
return hleLogSuccessI(SCEKERNEL, 0, "delaying %lld usecs", delayUs);
}
int sceKernelDelaySysClockThreadCB(u32 sysclockAddr)
{
int sceKernelDelaySysClockThreadCB(u32 sysclockAddr) {
auto sysclock = PSPPointer<SceKernelSysClock>::Create(sysclockAddr);
if (!sysclock.IsValid()) {
ERROR_LOG(SCEKERNEL, "sceKernelDelaySysClockThreadCB(%08x) - bad pointer", sysclockAddr);
return -1;
// Note: crashes on real firmware.
return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad pointer");
}
// TODO: Which unit?
// This is just a u64 of usecs. All bits are respected, but overflow can happen for very large values.
u64 usec = sysclock->lo | ((u64)sysclock->hi << 32);
DEBUG_LOG(SCEKERNEL, "sceKernelDelaySysClockThreadCB(%08x (%llu))", sysclockAddr, usec);
SceUID curThread = __KernelGetCurThread();
__KernelScheduleWakeup(curThread, __KernelDelayThreadUs(usec));
s64 delayUs = __KernelDelayThreadUs(usec);
__KernelScheduleWakeup(curThread, delayUs);
__KernelWaitCurThread(WAITTYPE_DELAY, curThread, 0, 0, true, "thread delayed");
return 0;
return hleLogSuccessI(SCEKERNEL, 0, "delaying %lld usecs", delayUs);
}
int sceKernelDelaySysClockThread(u32 sysclockAddr)
{
int sceKernelDelaySysClockThread(u32 sysclockAddr) {
auto sysclock = PSPPointer<SceKernelSysClock>::Create(sysclockAddr);
if (!sysclock.IsValid()) {
ERROR_LOG(SCEKERNEL, "sceKernelDelaySysClockThread(%08x) - bad pointer", sysclockAddr);
return -1;
// Note: crashes on real firmware.
return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad pointer");
}
// TODO: Which unit?
// This is just a u64 of usecs. All bits are respected, but overflow can happen for very large values.
u64 usec = sysclock->lo | ((u64)sysclock->hi << 32);
DEBUG_LOG(SCEKERNEL, "sceKernelDelaySysClockThread(%08x (%llu))", sysclockAddr, usec);
SceUID curThread = __KernelGetCurThread();
__KernelScheduleWakeup(curThread, __KernelDelayThreadUs(usec));
s64 delayUs = __KernelDelayThreadUs(usec);
__KernelScheduleWakeup(curThread, delayUs);
__KernelWaitCurThread(WAITTYPE_DELAY, curThread, 0, 0, false, "thread delayed");
return 0;
return hleLogSuccessI(SCEKERNEL, 0, "delaying %lld usecs", delayUs);
}
u32 __KernelGetThreadPrio(SceUID id)