diff --git a/Core/HLE/FunctionWrappers.h b/Core/HLE/FunctionWrappers.h index a0561526f7..bc7f1ed1b2 100644 --- a/Core/HLE/FunctionWrappers.h +++ b/Core/HLE/FunctionWrappers.h @@ -83,6 +83,11 @@ template void WrapI_U() { RETURN(retval); } +template void WrapI_UI() { + int retval = func(PARAM(0), PARAM(1)); + RETURN(retval); +} + template void WrapU_IUI() { u32 retval = func(PARAM(0), PARAM(1), PARAM(2)); RETURN(retval); @@ -103,6 +108,8 @@ template void WrapU_I() { RETURN(retval); } + + template void WrapI_I() { int retval = func(PARAM(0)); RETURN(retval); @@ -128,6 +135,11 @@ template void WrapV_UC() { func(PARAM(0), Memory::GetCharPointer(PARAM(1))); } +template void WrapI_UC() { + int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1))); + RETURN(retval); +} + template void WrapU_UIIIIII() { u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6)); RETURN(retval); @@ -220,6 +232,12 @@ template void WrapI_CUUU() { RETURN(retval); } +template void WrapI_CUUIUU() { + int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), + PARAM(3), PARAM(4), PARAM(5)); + RETURN(retval); +} + template void WrapU_CU() { u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1)); RETURN((u32) retval); @@ -262,6 +280,11 @@ template void WrapV_UIU() { func(PARAM(0), PARAM(1), PARAM(2)); } +template void WrapI_UIU() { + int retval = func(PARAM(0), PARAM(1), PARAM(2)); + RETURN(retval); +} + template void WrapV_IUUUU() { func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); } @@ -278,16 +301,33 @@ template void WrapV_CUIU() { func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3)); } +template void WrapI_CUIU() { + int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3)); + RETURN(retval); +} + template void WrapV_UCUIU() { func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3), PARAM(4)); } +template void WrapI_UCUIU() { + int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), + PARAM(3), PARAM(4)); + RETURN(retval); +} + template void WrapV_CUIIU() { func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); } +template void WrapI_CUIIU() { + int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), + PARAM(3), PARAM(4)); + RETURN(retval); +} + template void WrapU_UUUU() { u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); RETURN(retval); diff --git a/Core/HLE/HLE.cpp b/Core/HLE/HLE.cpp index 5313b5a1f2..0c2e9ad829 100644 --- a/Core/HLE/HLE.cpp +++ b/Core/HLE/HLE.cpp @@ -25,10 +25,27 @@ #include "sceIo.h" #include "sceAudio.h" #include "sceKernelMemory.h" +#include "sceKernelThread.h" #include "../MIPS/MIPSCodeUtils.h" +enum +{ + // Do nothing after the syscall. + HLE_AFTER_NOTHING = 0x00, + // Reschedule immediately after the syscall. + HLE_AFTER_RESCHED = 0x01, + // Call current thread's callbacks after the syscall. + HLE_AFTER_CURRENT_CALLBACKS = 0x02, + // Check all threads' callbacks after the syscall. + HLE_AFTER_ALL_CALLBACKS = 0x04, + // Reschedule and process current thread's callbacks after the syscall. + HLE_AFTER_RESCHED_CALLBACKS = 0x08, +}; + static std::vector moduleDB; static std::vector unresolvedSyscalls; +static int hleAfterSyscall = HLE_AFTER_NOTHING; +static const char *hleAfterSyscallReschedReason = NULL; void HLEInit() { @@ -177,6 +194,47 @@ const char *GetFuncName(int moduleIndex, int func) return "[unknown]"; } +void hleCheckAllCallbacks() +{ + hleAfterSyscall |= HLE_AFTER_ALL_CALLBACKS; +} + +void hleCheckCurrentCallbacks() +{ + hleAfterSyscall |= HLE_AFTER_CURRENT_CALLBACKS; +} + +void hleReSchedule(const char *reason) +{ + _dbg_assert_msg_(HLE, reason != 0, "hleReSchedule: Expecting a valid reason."); + + hleAfterSyscall |= HLE_AFTER_RESCHED; + hleAfterSyscallReschedReason = reason; +} + +void hleReSchedule(bool callbacks, const char *reason) +{ + hleReSchedule(reason); + hleAfterSyscall |= HLE_AFTER_RESCHED_CALLBACKS; +} + +inline void hleFinishSyscall() +{ + if ((hleAfterSyscall & HLE_AFTER_CURRENT_CALLBACKS) != 0) + __KernelForceCallbacks(); + + // Rescheduling will also do HLE_AFTER_ALL_CALLBACKS. + if ((hleAfterSyscall & HLE_AFTER_RESCHED_CALLBACKS) != 0) + __KernelReSchedule(true, hleAfterSyscallReschedReason); + else if ((hleAfterSyscall & HLE_AFTER_RESCHED) != 0) + __KernelReSchedule(hleAfterSyscallReschedReason); + else if ((hleAfterSyscall & HLE_AFTER_ALL_CALLBACKS) != 0) + __KernelCheckCallbacks(); + + hleAfterSyscall = HLE_AFTER_NOTHING; + hleAfterSyscallReschedReason = NULL; +} + void CallSyscall(u32 op) { u32 callno = (op >> 6) & 0xFFFFF; //20 bits @@ -192,6 +250,9 @@ void CallSyscall(u32 op) if (func) { func(); + + if (hleAfterSyscall != HLE_AFTER_NOTHING) + hleFinishSyscall(); } else { diff --git a/Core/HLE/HLE.h b/Core/HLE/HLE.h index 9305057b61..83633b134f 100644 --- a/Core/HLE/HLE.h +++ b/Core/HLE/HLE.h @@ -73,6 +73,14 @@ int GetModuleIndex(const char *modulename); void RegisterModule(const char *name, int numFunctions, const HLEFunction *funcTable); +// Run the current thread's callbacks after the syscall finishes. +void hleCheckCurrentCallbacks(); +// Check and potentially run all thread's callbacks after the syscall finishes. +void hleCheckAllCallbacks(); +// Reschedule after the syscall finishes. +void hleReSchedule(const char *reason); +// Reschedule and go into a callback processing state after the syscall finishes. +void hleReSchedule(bool callbacks, const char *reason); void HLEInit(); void HLEShutdown(); diff --git a/Core/HLE/__sceAudio.cpp b/Core/HLE/__sceAudio.cpp index 380f0ba778..c163efdfc4 100644 --- a/Core/HLE/__sceAudio.cpp +++ b/Core/HLE/__sceAudio.cpp @@ -46,8 +46,8 @@ const int audioIntervalUs = (int)(1000000ULL * hwBlockSize / hwSampleRate); const int audioHostIntervalUs = (int)(1000000ULL * hostAttemptBlockSize / hwSampleRate); // High and low watermarks, basically. -const int chanQueueMaxSizeFactor = 2; -const int chanQueueMinSizeFactor = 1; +const int chanQueueMaxSizeFactor = 4; +const int chanQueueMinSizeFactor = 2; FixedSizeQueue outAudioQueue; diff --git a/Core/HLE/sceAudio.cpp b/Core/HLE/sceAudio.cpp index 35f76a04e1..be2cc3652f 100644 --- a/Core/HLE/sceAudio.cpp +++ b/Core/HLE/sceAudio.cpp @@ -6,7 +6,7 @@ // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License 2.0 for more details. // A copy of the GPL 2.0 should have been included with the program. @@ -36,74 +36,48 @@ AudioChannel chans[8]; // Not sure about the range of volume, I often see 0x800 so that might be either // max or 50%? -void sceAudioOutputBlocking(u32 chan, u32 vol, u32 samplePtr) -{ - if (samplePtr == 0) - { +u32 sceAudioOutputBlocking(u32 chan, u32 vol, u32 samplePtr) { + if (samplePtr == 0) { ERROR_LOG(HLE, "sceAudioOutputBlocking - Sample pointer null"); - RETURN(0); + return 0; } - if (chan < 0 || chan >= MAX_CHANNEL) - { + if (chan < 0 || chan >= MAX_CHANNEL) { ERROR_LOG(HLE,"sceAudioOutputBlocking() - BAD CHANNEL"); - RETURN(SCE_ERROR_AUDIO_INVALID_CHANNEL); - } - else if (!chans[chan].reserved) - { + return SCE_ERROR_AUDIO_INVALID_CHANNEL; + } else if (!chans[chan].reserved) { ERROR_LOG(HLE,"sceAudioOutputBlocking() - channel not reserved"); - RETURN(SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED); - } - else - { + return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED; + } else { DEBUG_LOG(HLE, "sceAudioOutputBlocking(%d, %d, %08x )",chan,vol,samplePtr); chans[chan].leftVolume = vol; chans[chan].rightVolume = vol; chans[chan].sampleAddress = samplePtr; - RETURN(0); - int retval = __AudioEnqueue(chans[chan], chan, true); - if (retval != 0) { - // There was an error and didn't block (block always returns 0 here). Fine to RETURN. - RETURN(retval); - } + return __AudioEnqueue(chans[chan], chan, true); } } -void sceAudioOutputPannedBlocking(u32 chan, u32 volume1, u32 volume2, u32 samplePtr) -{ - if (samplePtr == 0) - { - ERROR_LOG(HLE, "sceAudioOutputPannedBlocking - Sample pointer null"); - RETURN(0); - } - else if (chan < 0 || chan >= MAX_CHANNEL) - { +u32 sceAudioOutputPannedBlocking(u32 chan, u32 volume1, u32 volume2, u32 samplePtr) { + if (samplePtr == 0) { + ERROR_LOG(HLE, "sceAudioOutputPannedBlocking - Sample pointer null"); + return 0; + } else if (chan < 0 || chan >= MAX_CHANNEL) { ERROR_LOG(HLE,"sceAudioOutputPannedBlocking() - BAD CHANNEL"); - RETURN(SCE_ERROR_AUDIO_INVALID_CHANNEL); - } - else if (!chans[chan].reserved) - { + return SCE_ERROR_AUDIO_INVALID_CHANNEL; + } else if (!chans[chan].reserved) { ERROR_LOG(HLE,"sceAudioOutputPannedBlocking() - CHANNEL NOT RESERVED"); - RETURN(SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED); - } - else - { - DEBUG_LOG(HLE, "sceAudioOutputPannedBlocking(%d,%d,%d, %08x )", chan, volume1, volume2, samplePtr); + return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED; + } else { + DEBUG_LOG(HLE, "sceAudioOutputPannedBlocking(%d,%d,%d, %08x )", chan, volume1, volume2, samplePtr); chans[chan].leftVolume = volume1; chans[chan].rightVolume = volume2; chans[chan].sampleAddress = samplePtr; - RETURN(0); - int retval = __AudioEnqueue(chans[chan], chan, true); - if (retval != 0) { - // There was an error and didn't block (block always returns 0 here). Fine to RETURN. - RETURN(retval); - } + return __AudioEnqueue(chans[chan], chan, true); } } u32 sceAudioOutput(u32 chan, u32 vol, u32 samplePtr) { - if (chan < 0 || chan >= MAX_CHANNEL) - { + if (chan < 0 || chan >= MAX_CHANNEL) { ERROR_LOG(HLE,"sceAudioOutput() - BAD CHANNEL"); return SCE_ERROR_AUDIO_INVALID_CHANNEL; } @@ -175,7 +149,7 @@ int sceAudioGetChannelRestLength(u32 chan) static int GetFreeChannel() { for (int i = 0; i < MAX_CHANNEL; i++) - { + { if (!chans[i].reserved) { return i; @@ -240,64 +214,64 @@ u32 sceAudioChRelease(u32 chan) u32 sceAudioSetChannelDataLen(u32 chan, u32 len) { - if (chan < 0 || chan >= MAX_CHANNEL) - { - ERROR_LOG(HLE,"sceAudioSetChannelDataLen(%i, %i) - BAD CHANNEL", chan, len); - return SCE_ERROR_AUDIO_INVALID_CHANNEL; - } - else if (!chans[chan].reserved) - { - ERROR_LOG(HLE,"sceAudioSetChannelDataLen(%i, %i) - channel not reserved", chan, len); - return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED; - } - else - { - DEBUG_LOG(HLE, "sceAudioSetChannelDataLen(%i, %i)", chan, len); + if (chan < 0 || chan >= MAX_CHANNEL) + { + ERROR_LOG(HLE,"sceAudioSetChannelDataLen(%i, %i) - BAD CHANNEL", chan, len); + return SCE_ERROR_AUDIO_INVALID_CHANNEL; + } + else if (!chans[chan].reserved) + { + ERROR_LOG(HLE,"sceAudioSetChannelDataLen(%i, %i) - channel not reserved", chan, len); + return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED; + } + else + { + DEBUG_LOG(HLE, "sceAudioSetChannelDataLen(%i, %i)", chan, len); //chans[chan].dataLen = len; chans[chan].sampleCount = len; - return 0; - } + return 0; + } } u32 sceAudioChangeChannelConfig(u32 chan, u32 format) { - if (chan < 0 || chan >= MAX_CHANNEL) - { - ERROR_LOG(HLE,"sceAudioChangeChannelConfig(%i, %i) - invalid channel number", chan, format); - return SCE_ERROR_AUDIO_INVALID_CHANNEL; - } - else if (!chans[chan].reserved) - { - ERROR_LOG(HLE,"sceAudioChangeChannelConfig(%i, %i) - channel not reserved", chan, format); - return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED; - } - else - { - DEBUG_LOG(HLE, "sceAudioChangeChannelConfig(%i, %i)", chan, format); - chans[chan].format = format; - return 0; - } + if (chan < 0 || chan >= MAX_CHANNEL) + { + ERROR_LOG(HLE,"sceAudioChangeChannelConfig(%i, %i) - invalid channel number", chan, format); + return SCE_ERROR_AUDIO_INVALID_CHANNEL; + } + else if (!chans[chan].reserved) + { + ERROR_LOG(HLE,"sceAudioChangeChannelConfig(%i, %i) - channel not reserved", chan, format); + return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED; + } + else + { + DEBUG_LOG(HLE, "sceAudioChangeChannelConfig(%i, %i)", chan, format); + chans[chan].format = format; + return 0; + } } u32 sceAudioChangeChannelVolume(u32 chan, u32 lvolume, u32 rvolume) { - if (chan < 0 || chan >= MAX_CHANNEL) - { - ERROR_LOG(HLE,"sceAudioChangeChannelVolume(%i, %i, %i) - invalid channel number", chan, lvolume, rvolume); - return SCE_ERROR_AUDIO_INVALID_CHANNEL; - } - else if (!chans[chan].reserved) - { - ERROR_LOG(HLE,"sceAudioChangeChannelVolume(%i, %i, %i) - channel not reserved", chan, lvolume, rvolume); - return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED; - } - else - { - DEBUG_LOG(HLE, "sceAudioChangeChannelVolume(%i, %i, %i)", chan, lvolume, rvolume); - chans[chan].leftVolume = lvolume; - chans[chan].rightVolume = rvolume; - return 0; - } + if (chan < 0 || chan >= MAX_CHANNEL) + { + ERROR_LOG(HLE,"sceAudioChangeChannelVolume(%i, %i, %i) - invalid channel number", chan, lvolume, rvolume); + return SCE_ERROR_AUDIO_INVALID_CHANNEL; + } + else if (!chans[chan].reserved) + { + ERROR_LOG(HLE,"sceAudioChangeChannelVolume(%i, %i, %i) - channel not reserved", chan, lvolume, rvolume); + return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED; + } + else + { + DEBUG_LOG(HLE, "sceAudioChangeChannelVolume(%i, %i, %i)", chan, lvolume, rvolume); + chans[chan].leftVolume = lvolume; + chans[chan].rightVolume = rvolume; + return 0; + } } u32 sceAudioInit() @@ -321,16 +295,13 @@ u32 sceAudioOutput2Reserve(u32 sampleCount) return 0; } -void sceAudioOutput2OutputBlocking(u32 vol, u32 dataPtr) +u32 sceAudioOutput2OutputBlocking(u32 vol, u32 dataPtr) { DEBUG_LOG(HLE,"FAKE sceAudioOutput2OutputBlocking(%i, %08x)", vol, dataPtr); chans[0].leftVolume = vol; chans[0].rightVolume = vol; chans[0].sampleAddress = dataPtr; - RETURN(0); - u32 retval = __AudioEnqueue(chans[0], 0, true); - if (retval < 0) - RETURN(retval); + return __AudioEnqueue(chans[0], 0, true); } u32 sceAudioOutput2ChangeLength(u32 sampleCount) @@ -342,7 +313,7 @@ u32 sceAudioOutput2ChangeLength(u32 sampleCount) u32 sceAudioOutput2GetRestSample() { - WARN_LOG(HLE,"UNTESTED sceAudioOutput2GetRestSample()"); + WARN_LOG(HLE,"UNTESTED sceAudioOutput2GetRestSample()"); return chans[0].sampleQueue.size() * 2; } @@ -368,30 +339,30 @@ const HLEFunction sceAudio[] = { // Newer simplified single channel audio output. Presumably for games that use Atrac3 // directly from Sas instead of playing it on a separate audio channel. - {0x01562ba3, WrapU_U, "sceAudioOutput2Reserve"}, - {0x2d53f36e, WrapV_UU, "sceAudioOutput2OutputBlocking"}, - {0x63f2889c, WrapU_U, "sceAudioOutput2ChangeLength"}, - {0x647cef33, WrapU_V, "sceAudioOutput2GetRestSample"}, - {0x43196845, WrapU_V, "sceAudioOutput2Release"}, + {0x01562ba3, WrapU_U, "sceAudioOutput2Reserve"}, + {0x2d53f36e, WrapU_UU, "sceAudioOutput2OutputBlocking"}, + {0x63f2889c, WrapU_U, "sceAudioOutput2ChangeLength"}, + {0x647cef33, WrapU_V, "sceAudioOutput2GetRestSample"}, + {0x43196845, WrapU_V, "sceAudioOutput2Release"}, {0x80F1F7E0, WrapU_V, "sceAudioInit"}, {0x210567F7, WrapU_V, "sceAudioEnd"}, - {0xA2BEAA6C, WrapU_U, "sceAudioSetFrequency"}, + {0xA2BEAA6C, WrapU_U, "sceAudioSetFrequency"}, {0x927AC32B, 0, "sceAudioSetVolumeOffset"}, // The oldest and standard audio interface. Supports 8 channels, most games use 1-2. - {0x8c1009b2, WrapU_UUU, "sceAudioOutput"}, - {0x136CAF51, WrapV_UUU, "sceAudioOutputBlocking"}, - {0xE2D56B2D, WrapU_UUUU, "sceAudioOutputPanned"}, - {0x13F592BC, WrapV_UUUU, "sceAudioOutputPannedBlocking"}, //(u32, u32, u32, void *)Output sound, blocking - {0x5EC81C55, WrapU_UUU, "sceAudioChReserve"}, //(u32, u32 samplecount, u32) Initialize channel and allocate buffer long, long samplecount, long);//init buffer? returns handle, minus if error - {0x6FC46853, WrapU_U, "sceAudioChRelease"}, //(long handle)Terminate channel and deallocate buffer //free buffer? - {0xE9D97901, WrapI_U, "sceAudioGetChannelRestLen"}, - {0xB011922F, WrapI_U, "sceAudioGetChannelRestLength"}, // Is there a difference between this and sceAudioGetChannelRestLen? + {0x8c1009b2, WrapU_UUU, "sceAudioOutput"}, + {0x136CAF51, WrapU_UUU, "sceAudioOutputBlocking"}, + {0xE2D56B2D, WrapU_UUUU, "sceAudioOutputPanned"}, + {0x13F592BC, WrapU_UUUU, "sceAudioOutputPannedBlocking"}, //(u32, u32, u32, void *)Output sound, blocking + {0x5EC81C55, WrapU_UUU, "sceAudioChReserve"}, //(u32, u32 samplecount, u32) Initialize channel and allocate buffer long, long samplecount, long);//init buffer? returns handle, minus if error + {0x6FC46853, WrapU_U, "sceAudioChRelease"}, //(long handle)Terminate channel and deallocate buffer //free buffer? + {0xE9D97901, WrapI_U, "sceAudioGetChannelRestLen"}, + {0xB011922F, WrapI_U, "sceAudioGetChannelRestLength"}, // Is there a difference between this and sceAudioGetChannelRestLen? {0xCB2E439E, WrapU_UU, "sceAudioSetChannelDataLen"}, //(u32, u32) - {0x95FD0C2D, WrapU_UU, "sceAudioChangeChannelConfig"}, - {0xB7E1D8E7, WrapU_UUU, "sceAudioChangeChannelVolume"}, + {0x95FD0C2D, WrapU_UU, "sceAudioChangeChannelConfig"}, + {0xB7E1D8E7, WrapU_UUU, "sceAudioChangeChannelVolume"}, // I guess these are like the others but do sample rate conversion? {0x38553111, 0, "sceAudioSRCChReserve"}, @@ -405,9 +376,9 @@ const HLEFunction sceAudio[] = // Microphone interface {0x7de61688, 0, "sceAudioInputInit"}, {0xE926D3FB, 0, "sceAudioInputInitEx"}, - {0x6d4bec68, 0, "sceAudioInput"}, - {0x086e5895, 0, "sceAudioInputBlocking"}, - {0xa708c6a6, 0, "sceAudioGetInputLength"}, + {0x6d4bec68, 0, "sceAudioInput"}, + {0x086e5895, 0, "sceAudioInputBlocking"}, + {0xa708c6a6, 0, "sceAudioGetInputLength"}, {0xA633048E, 0, "sceAudioPollInputEnd"}, {0x87b2e651, 0, "sceAudioWaitInputEnd"}, }; @@ -416,5 +387,5 @@ const HLEFunction sceAudio[] = void Register_sceAudio() { - RegisterModule("sceAudio", ARRAY_SIZE(sceAudio), sceAudio); + RegisterModule("sceAudio", ARRAY_SIZE(sceAudio), sceAudio); } diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index f8a0609c6b..c1938e3f86 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -337,21 +337,18 @@ void sceDisplayWaitVblankCB() { DEBUG_LOG(HLE,"sceDisplayWaitVblankCB()"); __KernelWaitCurThread(WAITTYPE_VBLANK, 0, 0, 0, true); - __KernelCheckCallbacks(); } void sceDisplayWaitVblankStartCB() { DEBUG_LOG(HLE,"sceDisplayWaitVblankStartCB()"); __KernelWaitCurThread(WAITTYPE_VBLANK, 0, 0, 0, true); - __KernelCheckCallbacks(); } void sceDisplayWaitVblankStartMultiCB() { DEBUG_LOG(HLE,"sceDisplayWaitVblankStartMultiCB()"); __KernelWaitCurThread(WAITTYPE_VBLANK, 0, 0, 0, true); - __KernelCheckCallbacks(); } void sceDisplayGetVcount() diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index 3544c9a171..c86a6d6d70 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -332,30 +332,30 @@ const HLEFunction ThreadManForUser[] = {0xCD203292,&WrapU_V, "sceKernelCancelEventFlag"}, {0xA66B0120,&WrapU_IU, "sceKernelReferEventFlagStatus"}, - {0x8FFDF9A2,&WrapV_IIU, "sceKernelCancelSema"}, - {0xD6DA4BA1,&WrapV_CUIIU, "sceKernelCreateSema"}, - {0x28b6489c,&WrapV_I, "sceKernelDeleteSema"}, - {0x58b1f937,&WrapV_II, "sceKernelPollSema"}, - {0xBC6FEBC5,&WrapV_IU, "sceKernelReferSemaStatus"}, - {0x3F53E640,&WrapV_II, "sceKernelSignalSema"}, - {0x4E3A1105,&WrapV_IIU, "sceKernelWaitSema"}, - {0x6d212bac,&WrapV_IIU, "sceKernelWaitSemaCB"}, + {0x8FFDF9A2,&WrapI_IIU, "sceKernelCancelSema"}, + {0xD6DA4BA1,&WrapI_CUIIU, "sceKernelCreateSema"}, + {0x28b6489c,&WrapI_I, "sceKernelDeleteSema"}, + {0x58b1f937,&WrapI_II, "sceKernelPollSema"}, + {0xBC6FEBC5,&WrapI_IU, "sceKernelReferSemaStatus"}, + {0x3F53E640,&WrapI_II, "sceKernelSignalSema"}, + {0x4E3A1105,&WrapI_IIU, "sceKernelWaitSema"}, + {0x6d212bac,&WrapI_IIU, "sceKernelWaitSemaCB"}, - {0x60107536,&WrapV_U, "sceKernelDeleteLwMutex"}, - {0x19CFF145,&WrapV_UCUIU, "sceKernelCreateLwMutex"}, - {0xf8170fbe,&WrapV_I, "sceKernelDeleteMutex"}, - {0xB011B11F,&WrapV_IIU, "sceKernelLockMutex"}, - {0x5bf4dd27,&WrapV_IIU, "sceKernelLockMutexCB"}, - {0x6b30100f,&WrapV_II, "sceKernelUnlockMutex"}, - {0xb7d098c6,&WrapV_CUIU, "sceKernelCreateMutex"}, - {0x0DDCD2C9,&WrapV_II, "sceKernelTryLockMutex"}, + {0x60107536,&WrapI_U, "sceKernelDeleteLwMutex"}, + {0x19CFF145,&WrapI_UCUIU, "sceKernelCreateLwMutex"}, + {0xf8170fbe,&WrapI_I, "sceKernelDeleteMutex"}, + {0xB011B11F,&WrapI_IIU, "sceKernelLockMutex"}, + {0x5bf4dd27,&WrapI_IIU, "sceKernelLockMutexCB"}, + {0x6b30100f,&WrapI_II, "sceKernelUnlockMutex"}, + {0xb7d098c6,&WrapI_CUIU, "sceKernelCreateMutex"}, + {0x0DDCD2C9,&WrapI_II, "sceKernelTryLockMutex"}, // NOTE: LockLwMutex and UnlockLwMutex are in Kernel_Library, see sceKernelInterrupt.cpp. {0xFCCFAD26,sceKernelCancelWakeupThread,"sceKernelCancelWakeupThread"}, {0xea748e31,sceKernelChangeCurrentThreadAttr,"sceKernelChangeCurrentThreadAttr"}, {0x71bc9871,sceKernelChangeThreadPriority,"sceKernelChangeThreadPriority"}, - {0x446D8DE6,sceKernelCreateThread,"sceKernelCreateThread"}, - {0x9fa03cd3,sceKernelDeleteThread,"sceKernelDeleteThread"}, + {0x446D8DE6,WrapI_CUUIUU,"sceKernelCreateThread"}, + {0x9fa03cd3,WrapI_I,"sceKernelDeleteThread"}, {0xBD123D9E,0,"sceKernelDelaySysClockThread"}, {0x1181E963,0,"sceKernelDelaySysClockThreadCB"}, {0xceadeb47,sceKernelDelayThread,"sceKernelDelayThread"}, @@ -375,10 +375,10 @@ const HLEFunction ThreadManForUser[] = {0x912354a7,sceKernelRotateThreadReadyQueue,"sceKernelRotateThreadReadyQueue"}, {0x9ACE131E,sceKernelSleepThread,"sceKernelSleepThread"}, {0x82826f70,sceKernelSleepThreadCB,"sceKernelSleepThreadCB"}, - {0xF475845D,&WrapV_IUU,"sceKernelStartThread"}, + {0xF475845D,&WrapI_IUU,"sceKernelStartThread"}, {0x9944f31f,sceKernelSuspendThread,"sceKernelSuspendThread"}, - {0x616403ba,WrapV_U,"sceKernelTerminateThread"}, - {0x383f7bcc,sceKernelTerminateDeleteThread,"sceKernelTerminateDeleteThread"}, + {0x616403ba,WrapI_U,"sceKernelTerminateThread"}, + {0x383f7bcc,WrapI_I,"sceKernelTerminateDeleteThread"}, {0x840E8133,sceKernelWaitThreadEndCB,"sceKernelWaitThreadEndCB"}, {0xd13bde95,sceKernelCheckThreadStack,"sceKernelCheckThreadStack"}, diff --git a/Core/HLE/sceKernelEventFlag.cpp b/Core/HLE/sceKernelEventFlag.cpp index bd8478ecdc..e2ae736575 100644 --- a/Core/HLE/sceKernelEventFlag.cpp +++ b/Core/HLE/sceKernelEventFlag.cpp @@ -232,7 +232,6 @@ void sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeout = Memory::Read_U32(timeoutPtr); __KernelWaitCurThread(WAITTYPE_EVENTFLAG, id, 0, 0, true); // sets RETURN - __KernelCheckCallbacks(); } } else diff --git a/Core/HLE/sceKernelInterrupt.cpp b/Core/HLE/sceKernelInterrupt.cpp index e23207bff2..bf298e4d40 100644 --- a/Core/HLE/sceKernelInterrupt.cpp +++ b/Core/HLE/sceKernelInterrupt.cpp @@ -439,11 +439,11 @@ const HLEFunction Kernel_Library[] = {0x47a0b729,sceKernelIsCpuIntrSuspended, "sceKernelIsCpuIntrSuspended"}, //flags {0xb55249d2,sceKernelIsCpuIntrEnable, "sceKernelIsCpuIntrEnable"}, {0xa089eca4,sceKernelMemset, "sceKernelMemset"}, - {0xDC692EE3,&WrapV_UI, "sceKernelTryLockLwMutex"}, - {0x37431849,&WrapV_UI, "sceKernelTryLockLwMutex_600"}, - {0xbea46419,&WrapV_UIU, "sceKernelLockLwMutex"}, - {0x1FC64E09,&WrapV_UIU, "sceKernelLockLwMutexCB"}, - {0x15b6446b,&WrapV_UI, "sceKernelUnlockLwMutex"}, + {0xDC692EE3,&WrapI_UI, "sceKernelTryLockLwMutex"}, + {0x37431849,&WrapI_UI, "sceKernelTryLockLwMutex_600"}, + {0xbea46419,&WrapI_UIU, "sceKernelLockLwMutex"}, + {0x1FC64E09,&WrapI_UIU, "sceKernelLockLwMutexCB"}, + {0x15b6446b,&WrapI_UI, "sceKernelUnlockLwMutex"}, {0x293b45b8,sceKernelGetThreadId, "sceKernelGetThreadId"}, {0x1839852A,&WrapU_UUU,"sce_paf_private_memcpy"}, }; diff --git a/Core/HLE/sceKernelMutex.cpp b/Core/HLE/sceKernelMutex.cpp index 23232590ae..337d41e427 100644 --- a/Core/HLE/sceKernelMutex.cpp +++ b/Core/HLE/sceKernelMutex.cpp @@ -161,26 +161,39 @@ void __KernelMutexEraseLock(Mutex *mutex) mutex->nm.lockThread = -1; } -void sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optionsPtr) +std::vector::iterator __KernelMutexFindPriority(std::vector &waiting) +{ + _dbg_assert_msg_(HLE, !waiting.empty(), "__KernelMutexFindPriority: Trying to find best of no threads."); + + std::vector::iterator iter, end, best = waiting.end(); + u32 best_prio = 0xFFFFFFFF; + for (iter = waiting.begin(), end = waiting.end(); iter != end; ++iter) + { + u32 iter_prio = __KernelGetThreadPrio(*iter); + if (iter_prio < best_prio) + { + best = iter; + best_prio = iter_prio; + } + } + + _dbg_assert_msg_(HLE, best != waiting.end(), "__KernelMutexFindPriority: Returning invalid best thread."); + return best; +} + +int sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optionsPtr) { if (!mutexInitComplete) __KernelMutexInit(); - u32 error = 0; if (!name) - error = SCE_KERNEL_ERROR_ERROR; - else if (initialCount < 0) - error = SCE_KERNEL_ERROR_ILLEGAL_COUNT; - else if ((attr & PSP_MUTEX_ATTR_ALLOW_RECURSIVE) == 0 && initialCount > 1) - error = SCE_KERNEL_ERROR_ILLEGAL_COUNT; + return SCE_KERNEL_ERROR_ERROR; + if (initialCount < 0) + return SCE_KERNEL_ERROR_ILLEGAL_COUNT; + if ((attr & PSP_MUTEX_ATTR_ALLOW_RECURSIVE) == 0 && initialCount > 1) + return SCE_KERNEL_ERROR_ILLEGAL_COUNT; - if (error) - { - RETURN(error); - return; - } - - DEBUG_LOG(HLE,"sceKernelCreateMutex(%s, %08x, %d, %08x)", name, attr, initialCount, optionsPtr); + DEBUG_LOG(HLE, "sceKernelCreateMutex(%s, %08x, %d, %08x)", name, attr, initialCount, optionsPtr); Mutex *mutex = new Mutex(); SceUID id = kernelObjects.Create(mutex); @@ -198,12 +211,39 @@ void sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 opti __KernelMutexAcquireLock(mutex, initialCount); if (optionsPtr != 0) - WARN_LOG(HLE,"sceKernelCreateMutex(%s) unsupported options parameter.", name); + WARN_LOG(HLE, "sceKernelCreateMutex(%s) unsupported options parameter.", name); - RETURN(id); + return id; } -void sceKernelDeleteMutex(SceUID id) +bool __KernelUnlockMutexForThread(Mutex *mutex, SceUID threadID, u32 &error, int result) +{ + SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_MUTEX, error); + u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); + + // The waitID may be different after a timeout. + if (waitID != mutex->GetUID()) + return false; + + // If result is an error code, we're just letting it go. + if (result == 0) + { + int wVal = (int)__KernelGetWaitValue(threadID, error); + __KernelMutexAcquireLock(mutex, wVal, threadID); + } + + if (timeoutPtr != 0 && mutexWaitTimer != 0) + { + // Remove any event for this thread. + u64 cyclesLeft = CoreTiming::UnscheduleEvent(mutexWaitTimer, threadID); + Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); + } + + __KernelResumeThreadFromWait(threadID, result); + return true; +} + +int sceKernelDeleteMutex(SceUID id) { DEBUG_LOG(HLE,"sceKernelDeleteMutex(%i)", id); u32 error; @@ -213,35 +253,19 @@ void sceKernelDeleteMutex(SceUID id) bool wokeThreads = false; std::vector::iterator iter, end; for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter) - { - SceUID threadID = *iter; - SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_MUTEX, error); - // The waitID may be different after a timeout. - if (waitID != id) - continue; + wokeThreads |= __KernelUnlockMutexForThread(mutex, *iter, error, SCE_KERNEL_ERROR_WAIT_DELETE); - u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); - if (timeoutPtr != 0 && mutexWaitTimer != 0) - { - // Remove any event for this thread. - u64 cyclesLeft = CoreTiming::UnscheduleEvent(mutexWaitTimer, threadID); - Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); - } - - __KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_DELETE); - wokeThreads = true; - } if (mutex->nm.lockThread != -1) __KernelMutexEraseLock(mutex); mutex->waitingThreads.clear(); - RETURN(kernelObjects.Destroy(id)); - if (wokeThreads) - __KernelReSchedule("mutex deleted"); + hleReSchedule("mutex deleted"); + + return kernelObjects.Destroy(id); } else - RETURN(error); + return error; } bool __KernelLockMutex(Mutex *mutex, int count, u32 &error) @@ -289,37 +313,17 @@ bool __KernelUnlockMutex(Mutex *mutex, u32 &error) { __KernelMutexEraseLock(mutex); - // TODO: PSP_MUTEX_ATTR_PRIORITY bool wokeThreads = false; - std::vector::iterator iter, end; -retry: - for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter) + std::vector::iterator iter; + while (!wokeThreads && !mutex->waitingThreads.empty()) { - SceUID threadID = *iter; - SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_MUTEX, error); - // The waitID may be different after a timeout. - if (waitID != mutex->GetUID()) - { - mutex->waitingThreads.erase(iter); - goto retry; - } + if ((mutex->nm.attr & PSP_MUTEX_ATTR_PRIORITY) != 0) + iter = __KernelMutexFindPriority(mutex->waitingThreads); + else + iter = mutex->waitingThreads.begin(); - int wVal = (int)__KernelGetWaitValue(threadID, error); - u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); - - __KernelMutexAcquireLock(mutex, wVal, threadID); - - if (timeoutPtr != 0 && mutexWaitTimer != 0) - { - // Remove any event for this thread. - u64 cyclesLeft = CoreTiming::UnscheduleEvent(mutexWaitTimer, threadID); - Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); - } - - __KernelResumeThreadFromWait(threadID, 0); - wokeThreads = true; + wokeThreads |= __KernelUnlockMutexForThread(mutex, *iter, error, 0); mutex->waitingThreads.erase(iter); - break; } if (!wokeThreads) @@ -345,10 +349,10 @@ void __KernelMutexThreadEnd(SceUID threadID) u32 error; // If it was waiting on the mutex, it should finish now. - SceUID mutexID = __KernelGetWaitID(threadID, WAITTYPE_MUTEX, error); - if (mutexID) + SceUID waitingMutexID = __KernelGetWaitID(threadID, WAITTYPE_MUTEX, error); + if (waitingMutexID) { - Mutex *mutex = kernelObjects.Get(mutexID, error); + Mutex *mutex = kernelObjects.Get(waitingMutexID, error); if (mutex) mutex->waitingThreads.erase(std::remove(mutex->waitingThreads.begin(), mutex->waitingThreads.end(), threadID), mutex->waitingThreads.end()); } @@ -387,122 +391,109 @@ void __KernelWaitMutex(Mutex *mutex, u32 timeoutPtr) } // int sceKernelLockMutex(SceUID id, int count, int *timeout) -// void because it changes threads. -void sceKernelLockMutex(SceUID id, int count, u32 timeoutPtr) +int sceKernelLockMutex(SceUID id, int count, u32 timeoutPtr) { - DEBUG_LOG(HLE,"sceKernelLockMutex(%i, %i, %08x)", id, count, timeoutPtr); + DEBUG_LOG(HLE, "sceKernelLockMutex(%i, %i, %08x)", id, count, timeoutPtr); u32 error; Mutex *mutex = kernelObjects.Get(id, error); if (__KernelLockMutex(mutex, count, error)) - { - RETURN(0); - } + return 0; else if (error) - RETURN(error); + return error; else { mutex->waitingThreads.push_back(__KernelGetCurThread()); __KernelWaitMutex(mutex, timeoutPtr); __KernelWaitCurThread(WAITTYPE_MUTEX, id, count, timeoutPtr, false); + + // Return value will be overwritten by wait. + return 0; } } // int sceKernelLockMutexCB(SceUID id, int count, int *timeout) -// void because it changes threads. -void sceKernelLockMutexCB(SceUID id, int count, u32 timeoutPtr) +int sceKernelLockMutexCB(SceUID id, int count, u32 timeoutPtr) { - DEBUG_LOG(HLE,"sceKernelLockMutexCB(%i, %i, %08x)", id, count, timeoutPtr); + DEBUG_LOG(HLE, "sceKernelLockMutexCB(%i, %i, %08x)", id, count, timeoutPtr); u32 error; Mutex *mutex = kernelObjects.Get(id, error); if (__KernelLockMutex(mutex, count, error)) { - RETURN(0); + hleCheckCurrentCallbacks(); + return 0; } else if (error) - RETURN(error); + return error; else { mutex->waitingThreads.push_back(__KernelGetCurThread()); __KernelWaitMutex(mutex, timeoutPtr); __KernelWaitCurThread(WAITTYPE_MUTEX, id, count, timeoutPtr, true); - __KernelCheckCallbacks(); + + // Return value will be overwritten by wait. + return 0; } } // int sceKernelTryLockMutex(SceUID id, int count) -// void because it changes threads. -void sceKernelTryLockMutex(SceUID id, int count) +int sceKernelTryLockMutex(SceUID id, int count) { - DEBUG_LOG(HLE,"sceKernelTryLockMutex(%i, %i)", id, count); + DEBUG_LOG(HLE, "sceKernelTryLockMutex(%i, %i)", id, count); u32 error; Mutex *mutex = kernelObjects.Get(id, error); if (__KernelLockMutex(mutex, count, error)) - RETURN(0); + return 0; else if (error) - RETURN(error); + return error; else - RETURN(PSP_MUTEX_ERROR_TRYLOCK_FAILED); + return PSP_MUTEX_ERROR_TRYLOCK_FAILED; } // int sceKernelUnlockMutex(SceUID id, int count) -// void because it changes threads. -void sceKernelUnlockMutex(SceUID id, int count) +int sceKernelUnlockMutex(SceUID id, int count) { - DEBUG_LOG(HLE,"sceKernelUnlockMutex(%i, %i)", id, count); + DEBUG_LOG(HLE, "sceKernelUnlockMutex(%i, %i)", id, count); u32 error; Mutex *mutex = kernelObjects.Get(id, error); - if (!error) - { - if (count <= 0) - error = SCE_KERNEL_ERROR_ILLEGAL_COUNT; - else if ((mutex->nm.attr & PSP_MUTEX_ATTR_ALLOW_RECURSIVE) == 0 && count > 1) - error = SCE_KERNEL_ERROR_ILLEGAL_COUNT; - else if (mutex->nm.lockLevel == 0 || mutex->nm.lockThread != __KernelGetCurThread()) - error = PSP_MUTEX_ERROR_NOT_LOCKED; - else if (mutex->nm.lockLevel < count) - error = PSP_MUTEX_ERROR_UNLOCK_UNDERFLOW; - } - if (error) - { - RETURN(error); - return; - } + return error; + if (count <= 0) + return SCE_KERNEL_ERROR_ILLEGAL_COUNT; + if ((mutex->nm.attr & PSP_MUTEX_ATTR_ALLOW_RECURSIVE) == 0 && count > 1) + return SCE_KERNEL_ERROR_ILLEGAL_COUNT; + if (mutex->nm.lockLevel == 0 || mutex->nm.lockThread != __KernelGetCurThread()) + return PSP_MUTEX_ERROR_NOT_LOCKED; + if (mutex->nm.lockLevel < count) + return PSP_MUTEX_ERROR_UNLOCK_UNDERFLOW; mutex->nm.lockLevel -= count; - RETURN(0); if (mutex->nm.lockLevel == 0) { if (__KernelUnlockMutex(mutex, error)) - __KernelReSchedule("mutex unlocked"); + hleReSchedule("mutex unlocked"); } + + return 0; } -void sceKernelCreateLwMutex(u32 workareaPtr, const char *name, u32 attr, int initialCount, u32 optionsPtr) +int sceKernelCreateLwMutex(u32 workareaPtr, const char *name, u32 attr, int initialCount, u32 optionsPtr) { if (!mutexInitComplete) __KernelMutexInit(); - DEBUG_LOG(HLE,"sceKernelCreateLwMutex(%08x, %s, %08x, %d, %08x)", workareaPtr, name, attr, initialCount, optionsPtr); + DEBUG_LOG(HLE, "sceKernelCreateLwMutex(%08x, %s, %08x, %d, %08x)", workareaPtr, name, attr, initialCount, optionsPtr); - u32 error = 0; if (!name) - error = SCE_KERNEL_ERROR_ERROR; + return SCE_KERNEL_ERROR_ERROR; else if (initialCount < 0) - error = SCE_KERNEL_ERROR_ILLEGAL_COUNT; + return SCE_KERNEL_ERROR_ILLEGAL_COUNT; else if ((attr & PSP_MUTEX_ATTR_ALLOW_RECURSIVE) == 0 && initialCount > 1) - error = SCE_KERNEL_ERROR_ILLEGAL_COUNT; - - if (error) - { - RETURN(error); - return; - } + return SCE_KERNEL_ERROR_ILLEGAL_COUNT; LwMutex *mutex = new LwMutex(); SceUID id = kernelObjects.Create(mutex); @@ -525,20 +516,44 @@ void sceKernelCreateLwMutex(u32 workareaPtr, const char *name, u32 attr, int ini Memory::WriteStruct(workareaPtr, &workarea); if (optionsPtr != 0) - WARN_LOG(HLE,"sceKernelCreateLwMutex(%s) unsupported options parameter.", name); + WARN_LOG(HLE, "sceKernelCreateLwMutex(%s) unsupported options parameter.", name); - RETURN(0); + return 0; } -void sceKernelDeleteLwMutex(u32 workareaPtr) +bool __KernelUnlockLwMutexForThread(LwMutex *mutex, NativeLwMutexWorkarea &workarea, SceUID threadID, u32 &error, int result) { - DEBUG_LOG(HLE,"sceKernelDeleteLwMutex(%08x)", workareaPtr); + SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_LWMUTEX, error); + u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); + + // The waitID may be different after a timeout. + if (waitID != mutex->GetUID()) + return false; + + // If result is an error code, we're just letting it go. + if (result == 0) + { + workarea.lockLevel = (int) __KernelGetWaitValue(threadID, error); + workarea.lockThread = threadID; + } + + if (timeoutPtr != 0 && lwMutexWaitTimer != 0) + { + // Remove any event for this thread. + u64 cyclesLeft = CoreTiming::UnscheduleEvent(lwMutexWaitTimer, threadID); + Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); + } + + __KernelResumeThreadFromWait(threadID, result); + return true; +} + +int sceKernelDeleteLwMutex(u32 workareaPtr) +{ + DEBUG_LOG(HLE, "sceKernelDeleteLwMutex(%08x)", workareaPtr); if (!workareaPtr || !Memory::IsValidAddress(workareaPtr)) - { - RETURN(SCE_KERNEL_ERROR_ILLEGAL_ADDR); - return; - } + return SCE_KERNEL_ERROR_ILLEGAL_ADDR; NativeLwMutexWorkarea workarea; Memory::ReadStruct(workareaPtr, &workarea); @@ -550,35 +565,19 @@ void sceKernelDeleteLwMutex(u32 workareaPtr) bool wokeThreads = false; std::vector::iterator iter, end; for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter) - { - SceUID threadID = *iter; - SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_LWMUTEX, error); - // The waitID may be different after a timeout. - if (waitID != mutex->GetUID()) - continue; - - u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); - if (timeoutPtr != 0 && lwMutexWaitTimer != 0) - { - // Remove any event for this thread. - u64 cyclesLeft = CoreTiming::UnscheduleEvent(lwMutexWaitTimer, threadID); - Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); - } - - __KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_DELETE); - wokeThreads = true; - } + wokeThreads |= __KernelUnlockLwMutexForThread(mutex, workarea, *iter, error, SCE_KERNEL_ERROR_WAIT_DELETE); mutex->waitingThreads.clear(); - RETURN(kernelObjects.Destroy(workarea.uid)); workarea.clear(); Memory::WriteStruct(workareaPtr, &workarea); if (wokeThreads) - __KernelReSchedule("lwmutex deleted"); + hleReSchedule("lwmutex deleted"); + + return kernelObjects.Destroy(mutex->GetUID()); } else - RETURN(error); + return error; } bool __KernelLockLwMutex(NativeLwMutexWorkarea &workarea, int count, u32 &error) @@ -641,38 +640,17 @@ bool __KernelUnlockLwMutex(NativeLwMutexWorkarea &workarea, u32 &error) return false; } - // TODO: PSP_MUTEX_ATTR_PRIORITY bool wokeThreads = false; - std::vector::iterator iter, end; -retry: - for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter) + std::vector::iterator iter; + while (!wokeThreads && !mutex->waitingThreads.empty()) { - SceUID threadID = *iter; - SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_LWMUTEX, error); - // The waitID may be different after a timeout. - if (waitID != mutex->GetUID()) - { - mutex->waitingThreads.erase(iter); - goto retry; - } + if ((mutex->nm.attr & PSP_MUTEX_ATTR_PRIORITY) != 0) + iter = __KernelMutexFindPriority(mutex->waitingThreads); + else + iter = mutex->waitingThreads.begin(); - int wVal = (int)__KernelGetWaitValue(threadID, error); - u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); - - workarea.lockLevel = wVal; - workarea.lockThread = threadID; - - if (timeoutPtr != 0 && lwMutexWaitTimer != 0) - { - // Remove any event for this thread. - u64 cyclesLeft = CoreTiming::UnscheduleEvent(lwMutexWaitTimer, threadID); - Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); - } - - __KernelResumeThreadFromWait(threadID, 0); - wokeThreads = true; + wokeThreads |= __KernelUnlockLwMutexForThread(mutex, workarea, *iter, error, 0); mutex->waitingThreads.erase(iter); - break; } if (!wokeThreads) @@ -710,9 +688,9 @@ void __KernelWaitLwMutex(LwMutex *mutex, u32 timeoutPtr) CoreTiming::ScheduleEvent(usToCycles(micro), lwMutexWaitTimer, __KernelGetCurThread()); } -void sceKernelTryLockLwMutex(u32 workareaPtr, int count) +int sceKernelTryLockLwMutex(u32 workareaPtr, int count) { - DEBUG_LOG(HLE,"sceKernelTryLockLwMutex(%08x, %i)", workareaPtr, count); + DEBUG_LOG(HLE, "sceKernelTryLockLwMutex(%08x, %i)", workareaPtr, count); NativeLwMutexWorkarea workarea; Memory::ReadStruct(workareaPtr, &workarea); @@ -721,17 +699,18 @@ void sceKernelTryLockLwMutex(u32 workareaPtr, int count) if (__KernelLockLwMutex(workarea, count, error)) { Memory::WriteStruct(workareaPtr, &workarea); - RETURN(0); + return 0; } + // Unlike sceKernelTryLockLwMutex_600, this always returns the same error. else if (error) - RETURN(PSP_MUTEX_ERROR_TRYLOCK_FAILED); + return PSP_MUTEX_ERROR_TRYLOCK_FAILED; else - RETURN(PSP_MUTEX_ERROR_TRYLOCK_FAILED); + return PSP_MUTEX_ERROR_TRYLOCK_FAILED; } -void sceKernelTryLockLwMutex_600(u32 workareaPtr, int count) +int sceKernelTryLockLwMutex_600(u32 workareaPtr, int count) { - DEBUG_LOG(HLE,"sceKernelTryLockLwMutex_600(%08x, %i)", workareaPtr, count); + DEBUG_LOG(HLE, "sceKernelTryLockLwMutex_600(%08x, %i)", workareaPtr, count); NativeLwMutexWorkarea workarea; Memory::ReadStruct(workareaPtr, &workarea); @@ -740,17 +719,17 @@ void sceKernelTryLockLwMutex_600(u32 workareaPtr, int count) if (__KernelLockLwMutex(workarea, count, error)) { Memory::WriteStruct(workareaPtr, &workarea); - RETURN(0); + return 0; } else if (error) - RETURN(error); + return error; else - RETURN(PSP_LWMUTEX_ERROR_TRYLOCK_FAILED); + return PSP_LWMUTEX_ERROR_TRYLOCK_FAILED; } -void sceKernelLockLwMutex(u32 workareaPtr, int count, u32 timeoutPtr) +int sceKernelLockLwMutex(u32 workareaPtr, int count, u32 timeoutPtr) { - DEBUG_LOG(HLE,"sceKernelLockLwMutex(%08x, %i, %08x)", workareaPtr, count, timeoutPtr); + DEBUG_LOG(HLE, "sceKernelLockLwMutex(%08x, %i, %08x)", workareaPtr, count, timeoutPtr); NativeLwMutexWorkarea workarea; Memory::ReadStruct(workareaPtr, &workarea); @@ -759,10 +738,10 @@ void sceKernelLockLwMutex(u32 workareaPtr, int count, u32 timeoutPtr) if (__KernelLockLwMutex(workarea, count, error)) { Memory::WriteStruct(workareaPtr, &workarea); - RETURN(0); + return 0; } else if (error) - RETURN(error); + return error; else { LwMutex *mutex = kernelObjects.Get(workarea.uid, error); @@ -771,15 +750,18 @@ void sceKernelLockLwMutex(u32 workareaPtr, int count, u32 timeoutPtr) mutex->waitingThreads.push_back(__KernelGetCurThread()); __KernelWaitLwMutex(mutex, timeoutPtr); __KernelWaitCurThread(WAITTYPE_LWMUTEX, workarea.uid, count, timeoutPtr, false); + + // Return value will be overwritten by wait. + return 0; } else - RETURN(error); + return error; } } -void sceKernelLockLwMutexCB(u32 workareaPtr, int count, u32 timeoutPtr) +int sceKernelLockLwMutexCB(u32 workareaPtr, int count, u32 timeoutPtr) { - DEBUG_LOG(HLE,"sceKernelLockLwMutexCB(%08x, %i, %08x)", workareaPtr, count, timeoutPtr); + DEBUG_LOG(HLE, "sceKernelLockLwMutexCB(%08x, %i, %08x)", workareaPtr, count, timeoutPtr); NativeLwMutexWorkarea workarea; Memory::ReadStruct(workareaPtr, &workarea); @@ -788,10 +770,11 @@ void sceKernelLockLwMutexCB(u32 workareaPtr, int count, u32 timeoutPtr) if (__KernelLockLwMutex(workarea, count, error)) { Memory::WriteStruct(workareaPtr, &workarea); - RETURN(0); + hleCheckCurrentCallbacks(); + return 0; } else if (error) - RETURN(error); + return error; else { LwMutex *mutex = kernelObjects.Get(workarea.uid, error); @@ -800,48 +783,44 @@ void sceKernelLockLwMutexCB(u32 workareaPtr, int count, u32 timeoutPtr) mutex->waitingThreads.push_back(__KernelGetCurThread()); __KernelWaitLwMutex(mutex, timeoutPtr); __KernelWaitCurThread(WAITTYPE_LWMUTEX, workarea.uid, count, timeoutPtr, true); - __KernelCheckCallbacks(); + + // Return value will be overwritten by wait. + return 0; } else - RETURN(error); + return error; } } -void sceKernelUnlockLwMutex(u32 workareaPtr, int count) +int sceKernelUnlockLwMutex(u32 workareaPtr, int count) { - DEBUG_LOG(HLE,"sceKernelUnlockLwMutex(%08x, %i)", workareaPtr, count); + DEBUG_LOG(HLE, "sceKernelUnlockLwMutex(%08x, %i)", workareaPtr, count); NativeLwMutexWorkarea workarea; Memory::ReadStruct(workareaPtr, &workarea); - u32 error = 0; if (workarea.uid == -1) - error = PSP_LWMUTEX_ERROR_NO_SUCH_LWMUTEX; + return PSP_LWMUTEX_ERROR_NO_SUCH_LWMUTEX; else if (count <= 0) - error = SCE_KERNEL_ERROR_ILLEGAL_COUNT; + return SCE_KERNEL_ERROR_ILLEGAL_COUNT; else if ((workarea.attr & PSP_MUTEX_ATTR_ALLOW_RECURSIVE) == 0 && count > 1) - error = SCE_KERNEL_ERROR_ILLEGAL_COUNT; + return SCE_KERNEL_ERROR_ILLEGAL_COUNT; else if (workarea.lockLevel == 0 || workarea.lockThread != __KernelGetCurThread()) - error = PSP_LWMUTEX_ERROR_NOT_LOCKED; + return PSP_LWMUTEX_ERROR_NOT_LOCKED; else if (workarea.lockLevel < count) - error = PSP_LWMUTEX_ERROR_UNLOCK_UNDERFLOW; - - if (error) - { - RETURN(error); - return; - } + return PSP_LWMUTEX_ERROR_UNLOCK_UNDERFLOW; workarea.lockLevel -= count; - RETURN(0); if (workarea.lockLevel == 0) { + u32 error; if (__KernelUnlockLwMutex(workarea, error)) - __KernelReSchedule("lwmutex unlocked"); + hleReSchedule("lwmutex unlocked"); Memory::WriteStruct(workareaPtr, &workarea); } else Memory::WriteStruct(workareaPtr, &workarea); + return 0; } \ No newline at end of file diff --git a/Core/HLE/sceKernelMutex.h b/Core/HLE/sceKernelMutex.h index bb89691fb7..8d7c09e9f2 100644 --- a/Core/HLE/sceKernelMutex.h +++ b/Core/HLE/sceKernelMutex.h @@ -17,20 +17,20 @@ #pragma once -void sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optionsPtr); -void sceKernelDeleteMutex(SceUID id); -void sceKernelLockMutex(SceUID id, int count, u32 timeoutPtr); -void sceKernelLockMutexCB(SceUID id, int count, u32 timeoutPtr); -void sceKernelTryLockMutex(SceUID id, int count); -void sceKernelUnlockMutex(SceUID id, int count); +int sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optionsPtr); +int sceKernelDeleteMutex(SceUID id); +int sceKernelLockMutex(SceUID id, int count, u32 timeoutPtr); +int sceKernelLockMutexCB(SceUID id, int count, u32 timeoutPtr); +int sceKernelTryLockMutex(SceUID id, int count); +int sceKernelUnlockMutex(SceUID id, int count); -void sceKernelCreateLwMutex(u32 workareaPtr, const char *name, u32 attr, int initialCount, u32 optionsPtr); -void sceKernelDeleteLwMutex(u32 workareaPtr); -void sceKernelTryLockLwMutex(u32 workareaPtr, int count); -void sceKernelTryLockLwMutex_600(u32 workareaPtr, int count); -void sceKernelLockLwMutex(u32 workareaPtr, int count, u32 timeoutPtr); -void sceKernelLockLwMutexCB(u32 workareaPtr, int count, u32 timeoutPtr); -void sceKernelUnlockLwMutex(u32 workareaPtr, int count); +int sceKernelCreateLwMutex(u32 workareaPtr, const char *name, u32 attr, int initialCount, u32 optionsPtr); +int sceKernelDeleteLwMutex(u32 workareaPtr); +int sceKernelTryLockLwMutex(u32 workareaPtr, int count); +int sceKernelTryLockLwMutex_600(u32 workareaPtr, int count); +int sceKernelLockLwMutex(u32 workareaPtr, int count, u32 timeoutPtr); +int sceKernelLockLwMutexCB(u32 workareaPtr, int count, u32 timeoutPtr); +int sceKernelUnlockLwMutex(u32 workareaPtr, int count); void __KernelMutexTimeout(u64 userdata, int cyclesLate); void __KernelLwMutexTimeout(u64 userdata, int cyclesLate); diff --git a/Core/HLE/sceKernelSemaphore.cpp b/Core/HLE/sceKernelSemaphore.cpp index b53e7d092f..c4b103f007 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -70,59 +70,87 @@ void __KernelSemaInit() semaInitComplete = true; } +// Returns whether the thread should be removed. +bool __KernelUnlockSemaForThread(Semaphore *s, SceUID threadID, u32 &error, int result, bool &wokeThreads) +{ + SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_SEMA, error); + u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); + + // The waitID may be different after a timeout. + if (waitID != s->GetUID()) + return true; + + // If result is an error code, we're just letting it go. + if (result == 0) + { + int wVal = (int) __KernelGetWaitValue(threadID, error); + if (wVal > s->ns.currentCount) + return false; + + s->ns.currentCount -= wVal; + s->ns.numWaitThreads--; + } + + if (timeoutPtr != 0 && semaWaitTimer != 0) + { + // Remove any event for this thread. + u64 cyclesLeft = CoreTiming::UnscheduleEvent(semaWaitTimer, threadID); + Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); + } + + __KernelResumeThreadFromWait(threadID, result); + wokeThreads = true; + return true; +} + // Resume all waiting threads (for delete / cancel.) // Returns true if it woke any threads. bool __KernelClearSemaThreads(Semaphore *s, int reason) { + u32 error; bool wokeThreads = false; - - // TODO: PSP_SEMA_ATTR_PRIORITY - std::vector::iterator iter; - for (iter = s->waitingThreads.begin(); iter != s->waitingThreads.end(); ++iter) - { - u32 error; - SceUID threadID = *iter; - SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_SEMA, error); - // The waitID may be different after a timeout. - if (waitID != s->GetUID()) - continue; - - u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); - if (timeoutPtr != 0 && semaWaitTimer != 0) - { - // Remove any event for this thread. - u64 cyclesLeft = CoreTiming::UnscheduleEvent(semaWaitTimer, threadID); - Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); - } - - __KernelResumeThreadFromWait(threadID, reason); - wokeThreads = true; - } + std::vector::iterator iter, end; + for (iter = s->waitingThreads.begin(), end = s->waitingThreads.end(); iter != end; ++iter) + __KernelUnlockSemaForThread(s, *iter, error, reason, wokeThreads); s->waitingThreads.clear(); return wokeThreads; } -// int sceKernelCancelSema(SceUID id, int newCount, int *numWaitThreads); -// void because it changes threads. -void sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr) +std::vector::iterator __KernelSemaFindPriority(std::vector &waiting, std::vector::iterator begin) { - DEBUG_LOG(HLE,"sceKernelCancelSema(%i)", id); + _dbg_assert_msg_(HLE, !waiting.empty(), "__KernelSemaFindPriority: Trying to find best of no threads."); + + std::vector::iterator iter, end, best = waiting.end(); + u32 best_prio = 0xFFFFFFFF; + for (iter = begin, end = waiting.end(); iter != end; ++iter) + { + u32 iter_prio = __KernelGetThreadPrio(*iter); + if (iter_prio < best_prio) + { + best = iter; + best_prio = iter_prio; + } + } + + _dbg_assert_msg_(HLE, best != waiting.end(), "__KernelSemaFindPriority: Returning invalid best thread."); + return best; +} + +// int sceKernelCancelSema(SceUID id, int newCount, int *numWaitThreads); +int sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr) +{ + DEBUG_LOG(HLE, "sceKernelCancelSema(%i)", id); u32 error; Semaphore *s = kernelObjects.Get(id, error); if (s) { if (newCount > s->ns.maxCount) - { - RETURN(SCE_KERNEL_ERROR_ILLEGAL_COUNT); - return; - } + return SCE_KERNEL_ERROR_ILLEGAL_COUNT; if (numWaitThreadsPtr) - { Memory::Write_U32(s->ns.numWaitThreads, numWaitThreadsPtr); - } if (newCount < 0) s->ns.currentCount = s->ns.initCount; @@ -130,31 +158,26 @@ void sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr) s->ns.currentCount = newCount; s->ns.numWaitThreads = 0; - // We need to set the return value BEFORE rescheduling threads. - RETURN(0); - if (__KernelClearSemaThreads(s, SCE_KERNEL_ERROR_WAIT_CANCEL)) - __KernelReSchedule("semaphore canceled"); + hleReSchedule("semaphore canceled"); + + return 0; } else { ERROR_LOG(HLE, "sceKernelCancelSema : Trying to cancel invalid semaphore %i", id); - RETURN(error); + return error; } } //SceUID sceKernelCreateSema(const char *name, SceUInt attr, int initVal, int maxVal, SceKernelSemaOptParam *option); -// void because it changes threads. -void sceKernelCreateSema(const char* name, u32 attr, int initVal, int maxVal, u32 optionPtr) +int sceKernelCreateSema(const char* name, u32 attr, int initVal, int maxVal, u32 optionPtr) { if (!semaInitComplete) __KernelSemaInit(); if (!name) - { - RETURN(SCE_KERNEL_ERROR_ERROR); - return; - } + return SCE_KERNEL_ERROR_ERROR; Semaphore *s = new Semaphore; SceUID id = kernelObjects.Create(s); @@ -168,121 +191,94 @@ void sceKernelCreateSema(const char* name, u32 attr, int initVal, int maxVal, u3 s->ns.maxCount = maxVal; s->ns.numWaitThreads = 0; - DEBUG_LOG(HLE,"%i=sceKernelCreateSema(%s, %08x, %i, %i, %08x)", id, s->ns.name, s->ns.attr, s->ns.initCount, s->ns.maxCount, optionPtr); + DEBUG_LOG(HLE, "%i=sceKernelCreateSema(%s, %08x, %i, %i, %08x)", id, s->ns.name, s->ns.attr, s->ns.initCount, s->ns.maxCount, optionPtr); if (optionPtr != 0) - WARN_LOG(HLE,"sceKernelCreateSema(%s) unsupported options parameter.", name); + WARN_LOG(HLE, "sceKernelCreateSema(%s) unsupported options parameter.", name); - RETURN(id); + return id; } //int sceKernelDeleteSema(SceUID semaid); -// void because it changes threads. -void sceKernelDeleteSema(SceUID id) +int sceKernelDeleteSema(SceUID id) { - DEBUG_LOG(HLE,"sceKernelDeleteSema(%i)", id); + DEBUG_LOG(HLE, "sceKernelDeleteSema(%i)", id); u32 error; Semaphore *s = kernelObjects.Get(id, error); if (s) { bool wokeThreads = __KernelClearSemaThreads(s, SCE_KERNEL_ERROR_WAIT_DELETE); - RETURN(kernelObjects.Destroy(id)); - if (wokeThreads) - __KernelReSchedule("semaphore deleted"); + hleReSchedule("semaphore deleted"); + + return kernelObjects.Destroy(id); } else { ERROR_LOG(HLE, "sceKernelDeleteSema : Trying to delete invalid semaphore %i", id); - RETURN(error); + return error; } } //int sceKernelDeleteSema(SceUID semaid, SceKernelSemaInfo *info); -// void because it changes threads. -void sceKernelReferSemaStatus(SceUID id, u32 infoPtr) +int sceKernelReferSemaStatus(SceUID id, u32 infoPtr) { u32 error; Semaphore *s = kernelObjects.Get(id, error); if (s) { - DEBUG_LOG(HLE,"sceKernelReferSemaStatus(%i, %08x)", id, infoPtr); + DEBUG_LOG(HLE, "sceKernelReferSemaStatus(%i, %08x)", id, infoPtr); Memory::WriteStruct(infoPtr, &s->ns); - RETURN(0); + return 0; } else { - ERROR_LOG(HLE,"Error %08x", error); - RETURN(error); + ERROR_LOG(HLE, "sceKernelReferSemaStatus: error %08x", error); + return error; } } //int sceKernelSignalSema(SceUID semaid, int signal); -// void because it changes threads. -void sceKernelSignalSema(SceUID id, int signal) +int sceKernelSignalSema(SceUID id, int signal) { u32 error; Semaphore *s = kernelObjects.Get(id, error); if (s) { if (s->ns.currentCount + signal - s->ns.numWaitThreads > s->ns.maxCount) - { - RETURN(SCE_KERNEL_ERROR_SEMA_OVF); - return; - } + return SCE_KERNEL_ERROR_SEMA_OVF; int oldval = s->ns.currentCount; s->ns.currentCount += signal; - DEBUG_LOG(HLE,"sceKernelSignalSema(%i, %i) (old: %i, new: %i)", id, signal, oldval, s->ns.currentCount); + DEBUG_LOG(HLE, "sceKernelSignalSema(%i, %i) (old: %i, new: %i)", id, signal, oldval, s->ns.currentCount); - // We need to set the return value BEFORE processing other threads. - RETURN(0); - - // TODO: PSP_SEMA_ATTR_PRIORITY bool wokeThreads = false; - std::vector::iterator iter; + std::vector::iterator iter, end, best; retry: - for (iter = s->waitingThreads.begin(); iter != s->waitingThreads.end(); ++iter) + for (iter = s->waitingThreads.begin(), end = s->waitingThreads.end(); iter != end; ++iter) { - SceUID threadID = *iter; - SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_SEMA, error); - // The waitID may be different after a timeout. - if (waitID != s->GetUID()) + if ((s->ns.attr & PSP_SEMA_ATTR_PRIORITY) != 0) + best = __KernelSemaFindPriority(s->waitingThreads, iter); + else + best = iter; + + if (__KernelUnlockSemaForThread(s, *best, error, 0, wokeThreads)) { - s->waitingThreads.erase(iter); - goto retry; - } - - int wVal = (int)__KernelGetWaitValue(threadID, error); - u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); - - if (wVal <= s->ns.currentCount) - { - s->ns.currentCount -= wVal; - s->ns.numWaitThreads--; - - if (timeoutPtr != 0 && semaWaitTimer != 0) - { - // Remove any event for this thread. - u64 cyclesLeft = CoreTiming::UnscheduleEvent(semaWaitTimer, threadID); - Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); - } - - __KernelResumeThreadFromWait(threadID, 0); - s->waitingThreads.erase(iter); - wokeThreads = true; + s->waitingThreads.erase(best); goto retry; } } if (wokeThreads) - __KernelReSchedule("semaphore signaled"); + hleReSchedule("semaphore signaled"); + + return 0; } else { ERROR_LOG(HLE, "sceKernelSignalSema : Trying to signal invalid semaphore %i", id); - RETURN(error;) + return error; } } @@ -323,68 +319,61 @@ void __KernelSetSemaTimeout(Semaphore *s, u32 timeoutPtr) CoreTiming::ScheduleEvent(usToCycles(micro), semaWaitTimer, __KernelGetCurThread()); } -void __KernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr, const char *badSemaMessage, bool processCallbacks) +int __KernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr, const char *badSemaMessage, bool processCallbacks) { u32 error; Semaphore *s = kernelObjects.Get(id, error); if (s) { if (wantedCount > s->ns.maxCount || wantedCount <= 0) - { - RETURN(SCE_KERNEL_ERROR_ILLEGAL_COUNT); - return; - } - - // We need to set the return value BEFORE processing callbacks / etc. - RETURN(0); + return SCE_KERNEL_ERROR_ILLEGAL_COUNT; if (s->ns.currentCount >= wantedCount) + { s->ns.currentCount -= wantedCount; + if (processCallbacks) + hleCheckCurrentCallbacks(); + } else { s->ns.numWaitThreads++; s->waitingThreads.push_back(__KernelGetCurThread()); __KernelSetSemaTimeout(s, timeoutPtr); __KernelWaitCurThread(WAITTYPE_SEMA, id, wantedCount, timeoutPtr, processCallbacks); - if (processCallbacks) - __KernelCheckCallbacks(); } + + return 0; } else { ERROR_LOG(HLE, badSemaMessage, id); - RETURN(error); + return error; } } //int sceKernelWaitSema(SceUID semaid, int signal, SceUInt *timeout); -// void because it changes threads. -void sceKernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr) +int sceKernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr) { - DEBUG_LOG(HLE,"sceKernelWaitSema(%i, %i, %i)", id, wantedCount, timeoutPtr); + DEBUG_LOG(HLE, "sceKernelWaitSema(%i, %i, %i)", id, wantedCount, timeoutPtr); - __KernelWaitSema(id, wantedCount, timeoutPtr, "sceKernelWaitSema: Trying to wait for invalid semaphore %i", false); + return __KernelWaitSema(id, wantedCount, timeoutPtr, "sceKernelWaitSema: Trying to wait for invalid semaphore %i", false); } //int sceKernelWaitSemaCB(SceUID semaid, int signal, SceUInt *timeout); -// void because it changes threads. -void sceKernelWaitSemaCB(SceUID id, int wantedCount, u32 timeoutPtr) +int sceKernelWaitSemaCB(SceUID id, int wantedCount, u32 timeoutPtr) { - DEBUG_LOG(HLE,"sceKernelWaitSemaCB(%i, %i, %i)", id, wantedCount, timeoutPtr); + DEBUG_LOG(HLE, "sceKernelWaitSemaCB(%i, %i, %i)", id, wantedCount, timeoutPtr); - __KernelWaitSema(id, wantedCount, timeoutPtr, "sceKernelWaitSemaCB: Trying to wait for invalid semaphore %i", true); + return __KernelWaitSema(id, wantedCount, timeoutPtr, "sceKernelWaitSemaCB: Trying to wait for invalid semaphore %i", true); } // Should be same as WaitSema but without the wait, instead returning SCE_KERNEL_ERROR_SEMA_ZERO -void sceKernelPollSema(SceUID id, int wantedCount) +int sceKernelPollSema(SceUID id, int wantedCount) { - DEBUG_LOG(HLE,"sceKernelPollSema(%i, %i)", id, wantedCount); + DEBUG_LOG(HLE, "sceKernelPollSema(%i, %i)", id, wantedCount); if (wantedCount <= 0) - { - RETURN(SCE_KERNEL_ERROR_ILLEGAL_COUNT); - return; - } + return SCE_KERNEL_ERROR_ILLEGAL_COUNT; u32 error; Semaphore *s = kernelObjects.Get(id, error); @@ -393,15 +382,15 @@ void sceKernelPollSema(SceUID id, int wantedCount) if (s->ns.currentCount >= wantedCount) { s->ns.currentCount -= wantedCount; - RETURN(0); + return 0; } else - RETURN(SCE_KERNEL_ERROR_SEMA_ZERO); + return SCE_KERNEL_ERROR_SEMA_ZERO; } else { ERROR_LOG(HLE, "sceKernelPollSema: Trying to poll invalid semaphore %i", id); - RETURN(error); + return error; } } diff --git a/Core/HLE/sceKernelSemaphore.h b/Core/HLE/sceKernelSemaphore.h index e6628fec9d..32150c6307 100644 --- a/Core/HLE/sceKernelSemaphore.h +++ b/Core/HLE/sceKernelSemaphore.h @@ -17,13 +17,13 @@ #pragma once -void sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr); -void sceKernelCreateSema(const char* name, u32 attr, int initVal, int maxVal, u32 optionPtr); -void sceKernelDeleteSema(SceUID id); -void sceKernelPollSema(SceUID id, int wantedCount); -void sceKernelReferSemaStatus(SceUID id, u32 infoPtr); -void sceKernelSignalSema(SceUID id, int signal); -void sceKernelWaitSema(SceUID semaid, int signal, u32 timeoutPtr); -void sceKernelWaitSemaCB(SceUID semaid, int signal, u32 timeoutPtr); +int sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr); +int sceKernelCreateSema(const char* name, u32 attr, int initVal, int maxVal, u32 optionPtr); +int sceKernelDeleteSema(SceUID id); +int sceKernelPollSema(SceUID id, int wantedCount); +int sceKernelReferSemaStatus(SceUID id, u32 infoPtr); +int sceKernelSignalSema(SceUID id, int signal); +int sceKernelWaitSema(SceUID semaid, int signal, u32 timeoutPtr); +int sceKernelWaitSemaCB(SceUID semaid, int signal, u32 timeoutPtr); void __KernelSemaTimeout(u64 userdata, int cycleslate); diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index 387bef79cf..1f5d969f05 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -256,6 +256,7 @@ public: SceUID moduleId; bool isProcessingCallbacks; + u32 currentCallbackId; ThreadContext context; @@ -267,7 +268,7 @@ public: u32 stackBlock; }; -void __KernelExecuteMipsCallOnCurrentThread(int callId); +void __KernelExecuteMipsCallOnCurrentThread(int callId, bool reschedAfter); int g_inCbCount = 0; @@ -396,7 +397,7 @@ void __KernelIdle() // In Advance, we might trigger an interrupt such as vblank. // If we end up in an interrupt, we don't want to reschedule. // However, we have to reschedule... damn. - __KernelReSchedule("idle"); + hleReSchedule("idle"); } void __KernelThreadingShutdown() @@ -617,10 +618,9 @@ u32 __KernelResumeThreadFromWait(SceUID threadID, int retval) } } -// DANGEROUS // Only run when you can safely accept a context switch // Triggers a waitable event, that is, it wakes up all threads that waits for it -// If any changes were made, it will context switch +// If any changes were made, it will context switch after the syscall bool __KernelTriggerWait(WaitType type, int id, bool useRetVal, int retVal, bool dontSwitch) { bool doneAnything = false; @@ -648,7 +648,7 @@ bool __KernelTriggerWait(WaitType type, int id, bool useRetVal, int retVal, bool // TODO: time waster char temp[256]; sprintf(temp, "resumed from wait %s", waitTypeStrings[(int)type]); - __KernelReSchedule(temp); + hleReSchedule(temp); } } return true; @@ -680,7 +680,7 @@ void __KernelWaitCurThread(WaitType type, SceUID waitID, u32 waitValue, u32 time char temp[256]; sprintf(temp, "started wait %s", waitTypeStrings[(int)type]); - __KernelReSchedule(processCallbacks, temp); + hleReSchedule(processCallbacks, temp); // TODO: Remove thread from Ready queue? } @@ -753,20 +753,27 @@ Thread *__KernelNextThread() { void __KernelReSchedule(const char *reason) { - // cancel rescheduling when in interrupt or callback, otherwise everything will be fucked up - if (__IsInInterrupt() || __KernelInCallback()) - { - reason = "In Interrupt Or Callback"; - return; - } + // cancel rescheduling when in interrupt or callback, otherwise everything will be fucked up + if (__IsInInterrupt() || __KernelInCallback()) + { + reason = "In Interrupt Or Callback"; + return; + } - // Execute any pending events while we're doing scheduling. - CoreTiming::Advance(); - if (__IsInInterrupt() || __KernelInCallback()) - { - reason = "In Interrupt Or Callback"; - return; - } + // This may get us running a callback, don't reschedule out of it. + if (__KernelCheckCallbacks()) + { + reason = "Began interrupt or callback."; + return; + } + + // Execute any pending events while we're doing scheduling. + CoreTiming::Advance(); + if (__IsInInterrupt() || __KernelInCallback()) + { + reason = "In Interrupt Or Callback"; + return; + } retry: Thread *nextThread = __KernelNextThread(); @@ -792,7 +799,6 @@ void __KernelReSchedule(bool doCallbacks, const char *reason) { if (thread) thread->isProcessingCallbacks = doCallbacks; - __KernelCheckCallbacks(); } __KernelReSchedule(reason); if (doCallbacks && thread == currentThread) { @@ -923,26 +929,19 @@ void __KernelSetupRootThread(SceUID moduleID, int args, const char *argp, int pr } -void sceKernelCreateThread() +int sceKernelCreateThread(const char *threadName, u32 entry, u32 prio, int stacksize, u32 attr, u32 optionAddr) { - u32 nameAddr = PARAM(0); - const char *threadName = Memory::GetCharPointer(nameAddr); - u32 entry = PARAM(1); - u32 prio = PARAM(2); - int stacksize = PARAM(3); - u32 attr = PARAM(4); - //ignore PARAM(5) - SceUID id; __KernelCreateThread(id, curModule, threadName, entry, prio, stacksize, attr); - INFO_LOG(HLE,"%i = sceKernelCreateThread(name=\"%s\", entry= %08x, stacksize=%i )", id, threadName, entry, stacksize); - RETURN(id); + INFO_LOG(HLE, "%i = sceKernelCreateThread(name=\"%s\", entry=%08x, prio=%x, stacksize=%i)", id, threadName, entry, prio, stacksize); + if (optionAddr != 0) + WARN_LOG(HLE, "sceKernelCreateThread: unsupported options parameter.", threadName); + return id; } // int sceKernelStartThread(SceUID threadToStartID, SceSize argSize, void *argBlock) -// void because it reschedules. -void sceKernelStartThread(SceUID threadToStartID, u32 argSize, u32 argBlockPtr) +int sceKernelStartThread(SceUID threadToStartID, u32 argSize, u32 argBlockPtr) { if (threadToStartID != currentThread->GetUID()) { @@ -952,16 +951,13 @@ void sceKernelStartThread(SceUID threadToStartID, u32 argSize, u32 argBlockPtr) { ERROR_LOG(HLE,"%08x=sceKernelStartThread(thread=%i, argSize=%i, argPtr= %08x): thread does not exist!", error,threadToStartID,argSize,argBlockPtr) - RETURN(error); - return; + return error; } if (startThread->nt.status != THREADSTATUS_DORMANT) { -printf("NOT DORMANT\n"); //Not dormant, WTF? - RETURN(ERROR_KERNEL_THREAD_IS_NOT_DORMANT); - return; + return ERROR_KERNEL_THREAD_IS_NOT_DORMANT; } INFO_LOG(HLE,"sceKernelStartThread(thread=%i, argSize=%i, argPtr= %08x )", @@ -990,14 +986,14 @@ printf("NOT DORMANT\n"); if (!argBlockPtr && argSize > 0) { WARN_LOG(HLE,"sceKernelStartThread : had NULL arg"); } - RETURN(0); - __KernelReSchedule("thread started"); + hleReSchedule("thread started"); + return 0; } else { ERROR_LOG(HLE,"thread %i trying to start itself", threadToStartID); - RETURN(-1); + return -1; } } @@ -1052,7 +1048,7 @@ void __KernelReturnFromThread() // Find threads that waited for me // Wake them if (!__KernelTriggerWait(WAITTYPE_THREADEND, __KernelGetCurThread())) - __KernelReSchedule("return from thread"); + hleReSchedule("return from thread"); // The stack will be deallocated when the thread is deleted. } @@ -1067,7 +1063,7 @@ void sceKernelExitThread() //Find threads that waited for me // Wake them if (!__KernelTriggerWait(WAITTYPE_THREADEND, __KernelGetCurThread())) - __KernelReSchedule("exited thread"); + hleReSchedule("exited thread"); // The stack will be deallocated when the thread is deleted. } @@ -1082,7 +1078,7 @@ void _sceKernelExitThread() //Find threads that waited for this one // Wake them if (!__KernelTriggerWait(WAITTYPE_THREADEND, __KernelGetCurThread())) - __KernelReSchedule("exit-deleted thread"); + hleReSchedule("exit-deleted thread"); // The stack will be deallocated when the thread is deleted. } @@ -1134,66 +1130,63 @@ u32 sceKernelResumeDispatchThread(u32 suspended) void sceKernelRotateThreadReadyQueue() { DEBUG_LOG(HLE,"sceKernelRotateThreadReadyQueue : rescheduling"); - __KernelReSchedule("rotatethreadreadyqueue"); + hleReSchedule("rotatethreadreadyqueue"); } -void sceKernelDeleteThread() +int sceKernelDeleteThread(int threadHandle) { - int threadHandle = PARAM(0); if (threadHandle != currentThread->GetUID()) { //TODO: remove from threadqueue! DEBUG_LOG(HLE,"sceKernelDeleteThread(%i)",threadHandle); - u32 error; - Thread *t = kernelObjects.Get(threadHandle, error); - if (t) - { - __KernelRemoveFromThreadQueue(t); - __KernelFireThreadEnd(t); + u32 error; + Thread *t = kernelObjects.Get(threadHandle, error); + if (t) + { + __KernelRemoveFromThreadQueue(t); + __KernelFireThreadEnd(t); - RETURN(kernelObjects.Destroy(threadHandle)); + __KernelTriggerWait(WAITTYPE_THREADEND, threadHandle); - __KernelTriggerWait(WAITTYPE_THREADEND, threadHandle); - - //TODO: should we really reschedule here? - //if (!__KernelTriggerWait(WAITTYPE_THREADEND, threadHandle)) - // __KernelReSchedule("thread deleted"); - } + //TODO: should we really reschedule here? + //if (!__KernelTriggerWait(WAITTYPE_THREADEND, threadHandle)) + // hleReSchedule("thread deleted"); + return kernelObjects.Destroy(threadHandle); + } } else { ERROR_LOG(HLE, "Thread \"%s\" tries to delete itself! :(",currentThread->GetName()); - RETURN(-1); + return -1; } } -void sceKernelTerminateDeleteThread() +int sceKernelTerminateDeleteThread(int threadno) { - int threadno = PARAM(0); if (threadno != currentThread->GetUID()) { //TODO: remove from threadqueue! INFO_LOG(HLE, "sceKernelTerminateDeleteThread(%i)", threadno); - RETURN(0); //kernelObjects.Destroy(threadno)); //TODO: should we really reschedule here? if (!__KernelTriggerWait(WAITTYPE_THREADEND, threadno)) - __KernelReSchedule("termdeletethread"); + hleReSchedule("termdeletethread"); + + return 0; //kernelObjects.Destroy(threadno)); } else { ERROR_LOG(HLE, "Thread \"%s\" trying to delete itself! :(", currentThread->GetName()); - RETURN(-1); + return -1; } } -void sceKernelTerminateThread(u32 threadID) +int sceKernelTerminateThread(u32 threadID) { if (threadID != currentThread->GetUID()) { INFO_LOG(HLE, "sceKernelTerminateThread(%i)", threadID); - RETURN(0); u32 error; Thread *t = kernelObjects.Get(threadID, error); @@ -1204,11 +1197,12 @@ void sceKernelTerminateThread(u32 threadID) __KernelTriggerWait(WAITTYPE_THREADEND, threadID); } // TODO: Return an error if it doesn't exist? + return 0; } else { ERROR_LOG(HLE, "Thread \"%s\" trying to delete itself! :(", currentThread->GetName()); - RETURN(-1); + return -1; } } @@ -1275,8 +1269,6 @@ void sceKernelDelayThreadCB() SceUID curThread = __KernelGetCurThread(); __KernelScheduleWakeup(curThread, usec); __KernelWaitCurThread(WAITTYPE_DELAY, curThread, 0, 0, true); - if (__KernelCheckCallbacks()) - __KernelExecutePendingMipsCalls(); } void sceKernelDelayThread() @@ -1363,7 +1355,6 @@ void sceKernelSleepThreadCB() DEBUG_LOG(HLE, "sceKernelSleepThreadCB()"); __KernelSleepThread(true); __KernelCheckCallbacks(); - __KernelExecutePendingMipsCalls(); } void sceKernelWaitThreadEnd() @@ -1479,7 +1470,7 @@ void sceKernelNotifyCallback() u32 arg = PARAM(1); DEBUG_LOG(HLE,"sceKernelNotifyCallback(%i, %i)", cbId, arg); - __KernelNotifyCallback(THREAD_CALLBACK_USER_DEFINED, __KernelGetCurThread(), cbId, arg); + __KernelNotifyCallback(THREAD_CALLBACK_USER_DEFINED, cbId, arg); RETURN(0); } @@ -1593,7 +1584,7 @@ void Thread::setReturnValue(u32 retval) { if (this == currentThread) { if (g_inCbCount) { - int callId = currentMIPS->r[MIPS_REG_CALL_ID]; + int callId = this->currentCallbackId; MipsCall *call = mipsCalls.get(callId); if (call) { call->savedV0 = retval; @@ -1623,7 +1614,7 @@ void __KernelSwitchContext(Thread *target, const char *reason) currentThread->nt.waitType = WAITTYPE_NONE; currentThread->nt.waitID = 0; - __KernelExecutePendingMipsCalls(); + __KernelExecutePendingMipsCalls(true); } void __KernelChangeThreadState(Thread *thread, ThreadStatus newStatus) { @@ -1654,7 +1645,8 @@ bool __CanExecuteCallbackNow(Thread *thread) { return g_inCbCount == 0; } -void __KernelCallAddress(Thread *thread, u32 entryPoint, Action *afterAction, bool returnVoid, std::vector args) { +void __KernelCallAddress(Thread *thread, u32 entryPoint, Action *afterAction, bool returnVoid, std::vector args, bool reschedAfter) +{ if (thread) { ActionAfterMipsCall *after = new ActionAfterMipsCall(); after->chainedAction = afterAction; @@ -1663,6 +1655,7 @@ void __KernelCallAddress(Thread *thread, u32 entryPoint, Action *afterAction, bo after->waitType = thread->nt.waitType; after->waitId = thread->nt.waitID; after->waitInfo = thread->waitInfo; + after->isProcessingCallbacks = thread->isProcessingCallbacks; afterAction = after; @@ -1688,7 +1681,7 @@ void __KernelCallAddress(Thread *thread, u32 entryPoint, Action *afterAction, bo if (__CanExecuteCallbackNow(thread)) { thread = currentThread; __KernelChangeThreadState(thread, THREADSTATUS_RUNNING); - __KernelExecuteMipsCallOnCurrentThread(callId); + __KernelExecuteMipsCallOnCurrentThread(callId, reschedAfter); called = true; } } @@ -1699,7 +1692,7 @@ void __KernelCallAddress(Thread *thread, u32 entryPoint, Action *afterAction, bo } } -void __KernelExecuteMipsCallOnCurrentThread(int callId) +void __KernelExecuteMipsCallOnCurrentThread(int callId, bool reschedAfter) { if (g_inCbCount > 0) { WARN_LOG(HLE, "__KernelExecuteMipsCallOnCurrentThread: Already in a callback!"); @@ -1713,12 +1706,17 @@ void __KernelExecuteMipsCallOnCurrentThread(int callId) call->savedV0 = currentMIPS->r[MIPS_REG_V0]; call->savedV1 = currentMIPS->r[MIPS_REG_V1]; call->savedIdRegister = currentMIPS->r[MIPS_REG_CALL_ID]; + call->savedId = currentThread->currentCallbackId; call->returnVoid = false; + call->reschedAfter = reschedAfter; // Set up the new state currentMIPS->pc = call->entryPoint; currentMIPS->r[MIPS_REG_RA] = __KernelMipsCallReturnAddress(); + // We put this two places in case the game overwrites it. + // We may want it later to "inject" return values. currentMIPS->r[MIPS_REG_CALL_ID] = callId; + currentThread->currentCallbackId = callId; for (int i = 0; i < call->numArgs; i++) { currentMIPS->r[MIPS_REG_A0 + i] = call->args[i]; } @@ -1728,7 +1726,9 @@ void __KernelExecuteMipsCallOnCurrentThread(int callId) void __KernelReturnFromMipsCall() { - int callId = currentMIPS->r[MIPS_REG_CALL_ID]; + int callId = currentThread->currentCallbackId; + if (currentMIPS->r[MIPS_REG_CALL_ID] != callId) + WARN_LOG(HLE, "__KernelReturnFromMipsCall(): s0 is %08x != %08x", currentMIPS->r[MIPS_REG_CALL_ID], callId); MipsCall *call = mipsCalls.pop(callId); @@ -1745,19 +1745,20 @@ void __KernelReturnFromMipsCall() currentMIPS->r[MIPS_REG_V0] = call->savedV0; currentMIPS->r[MIPS_REG_V1] = call->savedV1; currentMIPS->r[MIPS_REG_CALL_ID] = call->savedIdRegister; + currentThread->currentCallbackId = call->savedId; g_inCbCount--; // yeah! back in the real world, let's keep going. Should we process more callbacks? - __KernelCheckCallbacks(); - if (!__KernelExecutePendingMipsCalls()) + if (!__KernelExecutePendingMipsCalls(call->reschedAfter)) { - // We should definitely reschedule as we might still be asleep. - except if we came from checkcallbacks? - __KernelReSchedule("return from callback"); + // Sometimes, we want to stay on the thread. + if (call->reschedAfter) + hleReSchedule("return from callback"); } } -bool __KernelExecutePendingMipsCalls() +bool __KernelExecutePendingMipsCalls(bool reschedAfter) { Thread *thread = __GetCurrentThread(); @@ -1771,7 +1772,7 @@ bool __KernelExecutePendingMipsCalls() // Pop off the first pending mips call int callId = thread->pendingMipsCalls.front(); thread->pendingMipsCalls.pop_front(); - __KernelExecuteMipsCallOnCurrentThread(callId); + __KernelExecuteMipsCallOnCurrentThread(callId, reschedAfter); return true; } return false; @@ -1787,7 +1788,7 @@ public: }; // Executes the callback, when it next is context switched to. -void __KernelRunCallbackOnThread(SceUID cbId, Thread *thread) +void __KernelRunCallbackOnThread(SceUID cbId, Thread *thread, bool reschedAfter) { u32 error; Callback *cb = kernelObjects.Get(cbId, error); @@ -1811,7 +1812,7 @@ void __KernelRunCallbackOnThread(SceUID cbId, Thread *thread) cb->nc.notifyArg = 0; Action *action = new ActionAfterCallback(cbId); - __KernelCallAddress(thread, cb->nc.entrypoint, action, false, args); + __KernelCallAddress(thread, cb->nc.entrypoint, action, false, args, reschedAfter); } void ActionAfterCallback::run() { @@ -1833,15 +1834,16 @@ void ActionAfterCallback::run() { // Check callbacks on the current thread only. // Returns true if any callbacks were processed on the current thread. -bool __KernelCheckThreadCallbacks(Thread *thread) { - if (!thread->isProcessingCallbacks) +bool __KernelCheckThreadCallbacks(Thread *thread, bool force) +{ + if (!thread->isProcessingCallbacks && !force) return false; for (int i = 0; i < THREAD_CALLBACK_NUM_TYPES; i++) { if (thread->readyCallbacks[i].size()) { SceUID readyCallback = thread->readyCallbacks[i].front(); thread->readyCallbacks[i].pop_front(); - __KernelRunCallbackOnThread(readyCallback, thread); // makes pending + __KernelRunCallbackOnThread(readyCallback, thread, !force); // makes pending return true; } } @@ -1857,11 +1859,14 @@ bool __KernelCheckCallbacks() { for (std::vector::iterator iter = threadqueue.begin(); iter != threadqueue.end(); iter++) { Thread *thread = *iter; - if (thread->isProcessingCallbacks && __KernelCheckThreadCallbacks(thread)) { + if (__KernelCheckThreadCallbacks(thread, false)) { processed = true; } } // } while (processed && currentThread == __KernelGetCurThread()); + + if (processed) + return __KernelExecutePendingMipsCalls(true); return processed; } @@ -1869,30 +1874,24 @@ bool __KernelForceCallbacks() { Thread *curThread = __GetCurrentThread(); - // This thread can now process callbacks. - curThread->isProcessingCallbacks = true; - - bool callbacksProcessed = __KernelCheckThreadCallbacks(curThread); - - // Note - same thread as above - checking callbacks may switch threads. - curThread->isProcessingCallbacks = false; + bool callbacksProcessed = __KernelCheckThreadCallbacks(curThread, true); + if (callbacksProcessed) + __KernelExecutePendingMipsCalls(false); return callbacksProcessed; } -void sceKernelCheckCallback() { - Thread *curThread = __GetCurrentThread(); +void sceKernelCheckCallback() +{ + // Start with yes. + RETURN(1); bool callbacksProcessed = __KernelForceCallbacks(); if (callbacksProcessed) { - curThread->setReturnValue(1); ERROR_LOG(HLE,"sceKernelCheckCallback() - processed a callback."); - __KernelExecutePendingMipsCalls(); } else { RETURN(0); - DEBUG_LOG(HLE,"sceKernelCheckCallback() - no callbacks to process, simply rescheduling"); - __KernelReSchedule(false, "checkcallbackhack"); } } @@ -1924,7 +1923,7 @@ u32 __KernelUnregisterCallback(RegisteredCallbackType type, SceUID cbId) } } -void __KernelNotifyCallback(RegisteredCallbackType type, SceUID threadId, SceUID cbId, int notifyArg) +void __KernelNotifyCallback(RegisteredCallbackType type, SceUID cbId, int notifyArg) { u32 error; @@ -1937,7 +1936,7 @@ void __KernelNotifyCallback(RegisteredCallbackType type, SceUID threadId, SceUID cb->nc.notifyCount++; cb->nc.notifyArg = notifyArg; - Thread *t = kernelObjects.Get(threadId, error); + Thread *t = kernelObjects.Get(cb->nc.threadId, error); t->readyCallbacks[type].remove(cbId); t->readyCallbacks[type].push_back(cbId); } @@ -1949,7 +1948,7 @@ u32 __KernelNotifyCallbackType(RegisteredCallbackType type, SceUID cbId, int not Thread *t = *iter; for (std::set::iterator citer = t->registeredCallbacks[type].begin(); citer != t->registeredCallbacks[type].end(); citer++) { if (cbId == -1 || cbId == *citer) { - __KernelNotifyCallback(type, t->GetUID(), *citer, notifyArg); + __KernelNotifyCallback(type, *citer, notifyArg); } } } diff --git a/Core/HLE/sceKernelThread.h b/Core/HLE/sceKernelThread.h index 3782ccef33..30998ea4ad 100644 --- a/Core/HLE/sceKernelThread.h +++ b/Core/HLE/sceKernelThread.h @@ -26,16 +26,16 @@ void sceKernelChangeThreadPriority(); -void sceKernelCreateThread(); +int sceKernelCreateThread(const char *threadName, u32 entry, u32 prio, int stacksize, u32 attr, u32 optionAddr); void sceKernelDelayThread(); void sceKernelDelayThreadCB(); -void sceKernelDeleteThread(); +int sceKernelDeleteThread(int threadHandle); void sceKernelExitDeleteThread(); void sceKernelExitThread(); void _sceKernelExitThread(); void sceKernelGetThreadId(); void sceKernelGetThreadCurrentPriority(); -void sceKernelStartThread(SceUID threadToStartID, u32 argSize, u32 argBlockPtr); +int sceKernelStartThread(SceUID threadToStartID, u32 argSize, u32 argBlockPtr); u32 sceKernelSuspendDispatchThread(); u32 sceKernelResumeDispatchThread(u32 suspended); void sceKernelWaitThreadEnd(); @@ -47,8 +47,8 @@ void sceKernelSuspendThread(); void sceKernelResumeThread(); void sceKernelWakeupThread(); void sceKernelCancelWakeupThread(); -void sceKernelTerminateDeleteThread(); -void sceKernelTerminateThread(u32 threadID); +int sceKernelTerminateDeleteThread(int threadno); +int sceKernelTerminateThread(u32 threadID); void sceKernelWaitThreadEndCB(); void sceKernelGetThreadExitStatus(); void sceKernelGetThreadmanIdType(); @@ -169,8 +169,8 @@ bool __KernelCheckCallbacks(); bool __KernelForceCallbacks(); class Thread; void __KernelSwitchContext(Thread *target, const char *reason); -bool __KernelExecutePendingMipsCalls(); -void __KernelNotifyCallback(RegisteredCallbackType type, SceUID threadId, SceUID cbId, int notifyArg); +bool __KernelExecutePendingMipsCalls(bool reschedAfter); +void __KernelNotifyCallback(RegisteredCallbackType type, SceUID cbId, int notifyArg); // A call into game code. These can be pending on a thread. // Similar to Callback-s (NOT CallbackInfos) in JPCSP. @@ -188,6 +188,8 @@ struct MipsCall { u32 savedV1; bool returnVoid; const char *tag; + u32 savedId; + bool reschedAfter; }; enum ThreadStatus { diff --git a/Core/HLE/scePower.cpp b/Core/HLE/scePower.cpp index d4c49b0f27..bfe1943bc1 100644 --- a/Core/HLE/scePower.cpp +++ b/Core/HLE/scePower.cpp @@ -34,133 +34,102 @@ void __PowerInit() { memset(powerCbSlots, 0, sizeof(powerCbSlots)); } -int scePowerGetBatteryLifePercent() -{ +int scePowerGetBatteryLifePercent() { DEBUG_LOG(HLE, "100=scePowerGetBatteryLifePercent"); return 100; } -int scePowerIsPowerOnline() -{ +int scePowerIsPowerOnline() { DEBUG_LOG(HLE, "1=scePowerIsPowerOnline"); return 1; } -int scePowerIsBatteryExist() -{ +int scePowerIsBatteryExist() { DEBUG_LOG(HLE, "1=scePowerIsBatteryExist"); return 1; } -int scePowerIsBatteryCharging() -{ +int scePowerIsBatteryCharging() { DEBUG_LOG(HLE, "0=scePowerIsBatteryCharging"); return 0; } -int scePowerGetBatteryChargingStatus() -{ +int scePowerGetBatteryChargingStatus() { DEBUG_LOG(HLE, "0=scePowerGetBatteryChargingStatus"); return 0; } -int scePowerIsLowBattery() -{ +int scePowerIsLowBattery() { DEBUG_LOG(HLE, "0=scePowerIsLowBattery"); return 0; } -int scePowerRegisterCallback(int slot, int cbId) -{ +int scePowerRegisterCallback(int slot, int cbId) { DEBUG_LOG(HLE,"0=scePowerRegisterCallback(%i, %i)", slot, cbId); int foundSlot = -1; - if (slot == POWER_CB_AUTO) // -1 signifies auto select of bank - { - for(int i=0; i < numberOfCBPowerSlots; i++) - { - if ((powerCbSlots[i]==0) && (foundSlot == POWER_CB_AUTO)) // found an empty slot - { + if (slot == POWER_CB_AUTO) { // -1 signifies auto select of bank + for (int i=0; i < numberOfCBPowerSlots; i++) { + if ((powerCbSlots[i]==0) && (foundSlot == POWER_CB_AUTO)) { // found an empty slot powerCbSlots[i] = cbId; foundSlot = i; } } - } - else - { - if (powerCbSlots[slot] == 0) - { + } else { + if (powerCbSlots[slot] == 0) { powerCbSlots[slot] = cbId; foundSlot = 0; - } - else - { + } else { // slot already in use! foundSlot = POWER_CB_AUTO; } } - if (foundSlot>=0) - { + if (foundSlot>=0) { __KernelRegisterCallback(THREAD_CALLBACK_POWER, cbId); - - // Immediately notify - RETURN(0); - - __KernelNotifyCallbackType(THREAD_CALLBACK_POWER, cbId, 0x185); // TODO: I have no idea what the 0x185 is from the flags, but its needed for the test to pass. Need another example of it being called + __KernelNotifyCallbackType(THREAD_CALLBACK_POWER, cbId, 0x185); // TODO: I have no idea what the 0x185 is from the flags, but its needed for the test to pass. Need another example of it being called } return foundSlot; } -int scePowerUnregisterCallback(int slotId) -{ - if (slotId < 0 || slotId >= numberOfCBPowerSlots) - { +int scePowerUnregisterCallback(int slotId) { + if (slotId < 0 || slotId >= numberOfCBPowerSlots) { return -1; } - if (powerCbSlots[slotId] != 0) - { + if (powerCbSlots[slotId] != 0) { int cbId = powerCbSlots[slotId]; DEBUG_LOG(HLE,"0=scePowerUnregisterCallback(%i) (cbid = %i)", slotId, cbId); __KernelUnregisterCallback(THREAD_CALLBACK_POWER, cbId); powerCbSlots[slotId] = 0; - } - else - { + } else { return 0x80000025; // TODO: docs say a value less than 0, test checks for this specifically. why?? } return 0; } -int sceKernelPowerLock(int lockType) -{ +int sceKernelPowerLock(int lockType) { DEBUG_LOG(HLE,"0=sceKernelPowerLock(%i)", lockType); return 0; } -int sceKernelPowerUnlock(int lockType) -{ + +int sceKernelPowerUnlock(int lockType) { DEBUG_LOG(HLE,"0=sceKernelPowerUnlock(%i)", lockType); return 0; } -int sceKernelPowerTick(int flag) -{ + +int sceKernelPowerTick(int flag) { DEBUG_LOG(HLE,"UNIMPL 0=sceKernelPowerTick(%i)", flag); return 0; } #define ERROR_POWER_VMEM_IN_USE 0x802b0200 -int sceKernelVolatileMemTryLock(int type, int paddr, int psize) -{ - - if (!volatileMemLocked) - { +int sceKernelVolatileMemTryLock(int type, int paddr, int psize) { + if (!volatileMemLocked) { INFO_LOG(HLE,"sceKernelVolatileMemTryLock(%i, %08x, %i) - success", type, paddr, psize); volatileMemLocked = true; - } - else - { + } else { ERROR_LOG(HLE, "sceKernelVolatileMemTryLock(%i, %08x, %i) - already locked!", type, paddr, psize); return ERROR_POWER_VMEM_IN_USE; } @@ -174,47 +143,45 @@ int sceKernelVolatileMemTryLock(int type, int paddr, int psize) return 0; } -int sceKernelVolatileMemUnlock(int type) -{ - INFO_LOG(HLE,"sceKernelVolatileMemUnlock(%i)", type); - // TODO: sanity check - volatileMemLocked = false; +int sceKernelVolatileMemUnlock(int type) { + if (volatileMemLocked) { + INFO_LOG(HLE,"sceKernelVolatileMemUnlock(%i)", type); + volatileMemLocked = false; + } else { + ERROR_LOG(HLE, "sceKernelVolatileMemUnlock(%i) FAILED - not locked", type); + } return 0; } -int sceKernelVolatileMemLock(int type, int paddr, int psize) -{ +int sceKernelVolatileMemLock(int type, int paddr, int psize) { return sceKernelVolatileMemTryLock(type, paddr, psize); } -void scePowerSetClockFrequency(u32 cpufreq, u32 busfreq, u32 gpufreq) -{ +void scePowerSetClockFrequency(u32 cpufreq, u32 busfreq, u32 gpufreq) { CoreTiming::SetClockFrequencyMHz(cpufreq); - INFO_LOG(HLE,"scePowerSetClockFrequency(%i,%i,%i)", cpufreq, busfreq, gpufreq); } -void scePowerGetCpuClockFrequencyInt() { +u32 scePowerGetCpuClockFrequencyInt() { int freq = CoreTiming::GetClockFrequencyMHz(); INFO_LOG(HLE,"%i=scePowerGetCpuClockFrequencyInt()", freq); - RETURN(freq); + return freq; } -void scePowerGetPllClockFrequencyInt() { +u32 scePowerGetPllClockFrequencyInt() { int freq = CoreTiming::GetClockFrequencyMHz() / 2; INFO_LOG(HLE,"%i=scePowerGetPllClockFrequencyInt()", freq); - RETURN(freq); + return freq; } -void scePowerGetBusClockFrequencyInt() { +u32 scePowerGetBusClockFrequencyInt() { int freq = CoreTiming::GetClockFrequencyMHz() / 2; INFO_LOG(HLE,"%i=scePowerGetBusClockFrequencyInt()", freq); - RETURN(freq); + return freq; } -static const HLEFunction scePower[] = -{ +static const HLEFunction scePower[] = { {0x04B7766E,&WrapI_II,"scePowerRegisterCallback"}, {0x2B51FE2F,0,"scePower_2B51FE2F"}, {0x442BFBAC,0,"scePowerGetBacklightMaximum"}, @@ -249,27 +216,26 @@ static const HLEFunction scePower[] = {0xAC32C9CC,0,"scePowerRequestSuspend"}, {0x2875994B,0,"scePower_2875994B"}, {0x0074EF9B,0,"scePowerGetResumeCount"}, - {0xDFA8BAF8,&WrapI_I,"scePowerUnregisterCallback"}, - {0xDB9D28DD,&WrapI_I,"scePowerUnregitserCallback"}, //haha + {0xDFA8BAF8,WrapI_I,"scePowerUnregisterCallback"}, + {0xDB9D28DD,WrapI_I,"scePowerUnregitserCallback"}, //haha {0x843FBF43,0,"scePowerSetCpuClockFrequency"}, {0xB8D7B3FB,0,"scePowerSetBusClockFrequency"}, {0xFEE03A2F,0,"scePowerGetCpuClockFrequency"}, {0x478FE6F5,0,"scePowerGetBusClockFrequency"}, - {0xFDB5BFE9,scePowerGetCpuClockFrequencyInt,"scePowerGetCpuClockFrequencyInt"}, - {0xBD681969,scePowerGetBusClockFrequencyInt,"scePowerGetBusClockFrequencyInt"}, + {0xFDB5BFE9,WrapU_V,"scePowerGetCpuClockFrequencyInt"}, + {0xBD681969,WrapU_V,"scePowerGetBusClockFrequencyInt"}, {0xB1A52C83,0,"scePowerGetCpuClockFrequencyFloat"}, {0x9BADB3EB,0,"scePowerGetBusClockFrequencyFloat"}, - {0x737486F2,&WrapV_UUU,"scePowerSetClockFrequency"}, - {0x34f9c463,scePowerGetPllClockFrequencyInt,"scePowerGetPllClockFrequencyInt"}, + {0x737486F2,WrapV_UUU,"scePowerSetClockFrequency"}, + {0x34f9c463,WrapU_V,"scePowerGetPllClockFrequencyInt"}, {0xea382a27,0,"scePowerGetPllClockFrequencyFloat"}, - {0xebd177d6,&WrapV_UUU,"scePower_driver_EBD177D6"}, //TODO: used in a few places, jpcsp says is the same as scePowerSetClockFrequency + {0xebd177d6,WrapV_UUU,"scePower_driver_EBD177D6"}, //TODO: used in a few places, jpcsp says is the same as scePowerSetClockFrequency {0x469989ad,0,"scePower_469989ad"}, {0xa85880d0,0,"scePower_a85880d0"}, }; //890129c in tyshooter looks bogus -const HLEFunction sceSuspendForUser[] = -{ +const HLEFunction sceSuspendForUser[] = { {0xEADB1BD7,&WrapI_I,"sceKernelPowerLock"}, //(int param) set param to 0 {0x3AEE7261,&WrapI_I,"sceKernelPowerUnlock"},//(int param) set param to 0 {0x090ccb3f,&WrapI_I,"sceKernelPowerTick"}, diff --git a/Core/HLE/sceSas.cpp b/Core/HLE/sceSas.cpp index 4e7236645a..22769103ff 100644 --- a/Core/HLE/sceSas.cpp +++ b/Core/HLE/sceSas.cpp @@ -41,6 +41,18 @@ static const int PSP_SAS_ADSR_DECAY=2; static const int PSP_SAS_ADSR_SUSTAIN=4; static const int PSP_SAS_ADSR_RELEASE=8; + +struct WaveformEffect +{ + int type; + int delay; + int feedback ; + int leftVol; + int rightVol; + int isDryOn; + int isWetOn; +}; + static const double f[5][2] = { { 0.0, 0.0 }, { 60.0 / 64.0, 0.0 }, @@ -133,6 +145,7 @@ bool VagDecoder::Decode() struct Voice { u32 vagAddr; + u32 pcmAddr; int samplePos; int size; int loop; @@ -151,8 +164,8 @@ struct Voice int sustainLevel; int releaseType; int pitch; - bool endFlag; - bool PauseFlag; + int setPaused; + int height; bool playing; VagDecoder vag; @@ -163,9 +176,12 @@ class SasInstance public: enum { NUM_VOICES = 32 }; Voice voices[NUM_VOICES]; + WaveformEffect waveformEffect; int grainSize; int maxVoices; int sampleRate; + int outputMode; + int length; void mix(u32 outAddr); }; @@ -186,7 +202,7 @@ void SasInstance::mix(u32 outAddr) if (voice.playing && voice.vagAddr != 0) { - for (int i = 0; i < grainSize; i++) + for (int i = 0; i < sas.grainSize; i++) { int sample = voice.vag.GetSample(); voice.samplePos++; @@ -195,7 +211,8 @@ void SasInstance::mix(u32 outAddr) voice.playing = false; break; } - int l = sample; int r = sample; //* (voice.volumeLeft >> 16), r = sample * (voice.volumeRight >> 16); + int l = sample; + int r = sample; //* (voice.volumeLeft >> 16), r = sample * (voice.volumeRight >> 16); // TODO: should mix into a temporary 32-bit buffer and then clip down out[i * 2] += l; @@ -205,20 +222,21 @@ void SasInstance::mix(u32 outAddr) } } -u32 sceSasInit(u32 core, u32 grainSize, u32 maxVoices, u32 unknown, u32 sampleRate) +u32 sceSasInit(u32 core, u32 grainSize, u32 maxVoices, u32 outputMode, u32 sampleRate) { DEBUG_LOG(HLE,"0=sceSasInit()"); memset(&sas, 0, sizeof(sas)); sas.grainSize = grainSize; sas.maxVoices = maxVoices; sas.sampleRate = sampleRate; + sas.outputMode = outputMode; for (int i = 0; i < 32; i++) { sas.voices[i].playing = false; } return 0; } -u32 sceSasGetEndFlag() +u32 sceSasGetEndFlag(u32 core) { u32 endFlag = 0; for (int i = 0; i < sas.maxVoices; i++) { @@ -260,9 +278,20 @@ void sceSasSetVoice(u32 core, int voiceNum, u32 vagAddr, int size, int loop) RETURN(0); } +u32 sceSasSetPause(u32 core, int voicebit, int pause) +{ + DEBUG_LOG(HLE,"0=sceSasSetPause(core=%08x, voicebit=%i, pause=%i)", core, voicebit, pause); + for (int i = 0; voicebit != 0; i++, voicebit >>= 1) { + if ((voicebit & 1) != 0) { + sas.voices[i].setPaused=pause; + } + } + return 0; +} + void sceSasSetVolume(u32 core, int voiceNum, int l, int r, int el, int er) { - DEBUG_LOG(HLE,"UNIMPL 0=sceSasSetVolume(core=%08x, voicenum=%i, l=%i, r=%i, el=%i, er=%i", core, voiceNum, l, r, el, er); + DEBUG_LOG(HLE,"0=sceSasSetVolume(core=%08x, voiceNum=%i, l=%i, r=%i, el=%i, er=%i", core, voiceNum, l, r, el, er); Voice &v = sas.voices[voiceNum]; v.volumeLeft = l; v.volumeRight = r; @@ -273,13 +302,13 @@ void sceSasSetPitch(u32 core, int voiceNum, int pitch) { Voice &v = sas.voices[voiceNum]; v.pitch = pitch; - DEBUG_LOG(HLE,"UNIMPL 0=sceSasSetPitch(core=%08x, voicenum=%i, pitch=%i)", core, voiceNum, pitch); + DEBUG_LOG(HLE,"0=sceSasSetPitch(core=%08x, voiceNum=%i, pitch=%i)", core, voiceNum, pitch); RETURN(0); } void sceSasSetKeyOn(u32 core, int voiceNum) { - DEBUG_LOG(HLE,"0=sceSasSetKeyOff(core=%08x, voicenum=%i)", core, voiceNum); + DEBUG_LOG(HLE,"0=sceSasSetKeyOn(core=%08x, voiceNum=%i)", core, voiceNum); Voice &v = sas.voices[voiceNum]; v.vag.Start(Memory::GetPointer(v.vagAddr)); v.playing = true; @@ -290,7 +319,7 @@ void sceSasSetKeyOn(u32 core, int voiceNum) // sceSasSetKeyOff can be used to start sounds, that just sound during the Release phase! void sceSasSetKeyOff(u32 core, int voiceNum) { - DEBUG_LOG(HLE,"0=sceSasSetKeyOff(core=%08x, voicenum=%i)", core, voiceNum); + DEBUG_LOG(HLE,"0=sceSasSetKeyOff(core=%08x, voiceNum=%i)", core, voiceNum); Voice &v = sas.voices[voiceNum]; v.playing = false; // not right! Should directly enter Release envelope stage instead! RETURN(0); @@ -298,18 +327,18 @@ void sceSasSetKeyOff(u32 core, int voiceNum) u32 sceSasSetNoise(u32 core, int voiceNum, int freq) { - DEBUG_LOG(HLE,"0=sceSasSetVoice(core=%08x, voiceNum=%i, freq=%i)", core, voiceNum, freq); + DEBUG_LOG(HLE,"0=sceSasSetNoise(core=%08x, voiceNum=%i, freq=%i)", core, voiceNum, freq); Voice &v = sas.voices[voiceNum]; v.freq = freq; - return(0); + return 0; } u32 sceSasSetSL(u32 core, int voiceNum, int level) { - DEBUG_LOG(HLE,"0=sceSasSetSL(core=%08x, voicenum=%i, level=%i)", core, voiceNum, level); + DEBUG_LOG(HLE,"0=sceSasSetSL(core=%08x, voiceNum=%i, level=%i)", core, voiceNum, level); Voice &v = sas.voices[voiceNum]; v.sustainLevel = level; - return(0); + return 0; } u32 sceSasSetADSR(u32 core, int voiceNum,int flag ,int a, int d, int s, int r) @@ -331,7 +360,7 @@ u32 sceSasSetADSRMode(u32 core, int voiceNum,int flag ,int a, int d, int s, int if ((flag & 0x2) != 0) v.decayType = d; if ((flag & 0x4) != 0) v.sustainType = s; if ((flag & 0x8) != 0) v.releaseType = r; - return 0; + return 0 ; } // http://code.google.com/p/jpcsp/source/browse/trunk/src/jpcsp/HLE/modules150/sceSasCore.java @@ -370,9 +399,9 @@ int sustainType(int bitfield2) { case 2: return PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE; case 4: return PSP_SAS_ADSR_CURVE_MODE_LINEAR_BENT; case 6: return PSP_SAS_ADSR_CURVE_MODE_EXPONENT_DECREASE; - } - DEBUG_LOG(HLE,"sasSetSimpleADSR,ERROR_SAS_INVALID_ADSR_CURVE_MODE"); - + } + ERROR_LOG(HLE,"sasSetSimpleADSR,ERROR_SAS_INVALID_ADSR_CURVE_MODE"); + return 0; } int releaseType(int bitfield2) { @@ -385,7 +414,7 @@ int releaseRate(int bitfield2) { return 0; } if (releaseType(bitfield2) == PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE) { - return (0x40000000 >> (n + 2)); + return (0x40000000 >> (n + 2)); } return (0x8000000 >> n); } @@ -426,17 +455,22 @@ u32 sceSasGetEnvelopeHeight(u32 core, u32 voiceNum) void sceSasRevType(u32 core, int type) { - DEBUG_LOG(HLE,"UNIMPL 0=sceSasRevType(core=%08x, type=%i)", core, type); + DEBUG_LOG(HLE,"0=sceSasRevType(core=%08x, type=%i)", core, type); + + sas.waveformEffect.type=type; RETURN(0); } -void sceSasRevParam(u32 core, int param1, int param2) +void sceSasRevParam(u32 core, int delay, int feedback) { - DEBUG_LOG(HLE,"UNIMPL 0=sceSasRevParam(core=%08x, param1=%i, param2=%i)", core, param1, param2); + DEBUG_LOG(HLE,"0=sceSasRevParam(core=%08x, delay=%i, feedback=%i)", core, delay, feedback); + + sas.waveformEffect.delay = delay; + sas.waveformEffect.feedback = feedback; RETURN(0); } -u32 sceSasGetPauseFlag() +u32 sceSasGetPauseFlag(u32 core) { u32 PauseFlag = 0; for (int i = 0; i < sas.maxVoices; i++) { @@ -447,33 +481,80 @@ u32 sceSasGetPauseFlag() return PauseFlag; } - - -void sceSasRevEVOL(u32 core, int param1, int param2) +void sceSasRevEVOL(u32 core, int lv, int rv) { - DEBUG_LOG(HLE,"UNIMPL 0=sceSasRevEVOL(core=%08x, param1=%i, param2=%i)", core, param1, param2); + DEBUG_LOG(HLE,"0=sceSasRevEVOL(core=%08x, leftVolume=%i, rightVolume=%i)", core, lv, rv); + + sas.waveformEffect.leftVol = lv; + sas.waveformEffect.rightVol = rv; RETURN(0); } -void sceSasRevVON(u32 core, int param1, int param2) +void sceSasRevVON(u32 core, int dry, int wet) { - DEBUG_LOG(HLE,"UNIMPL 0=sceSasRevEVOL(core=%08x, param1=%i, param2=%i)", core, param1, param2); + DEBUG_LOG(HLE,"0=sceSasRevVON(core=%08x, dry=%i, wet=%i)", core, dry, wet); + + sas.waveformEffect.isDryOn = (dry > 0); + sas.waveformEffect.isWetOn = (wet > 0); RETURN(0); } -void sceSasGetOutputMode(u32 core, int param1, int param2) +u32 sceSasGetGrain(u32 core) { - DEBUG_LOG(HLE,"UNIMPL 0=sceSasGetOutputMode(core=%08x, param1=%i, param2=%i)", core, param1, param2); + DEBUG_LOG(HLE,"0=sceSasGetGrain(core=%08x)", core); + return sas.grainSize; + +} + +u32 sceSasSetGrain(u32 core, int grain) +{ + DEBUG_LOG(HLE,"0=sceSasSetGrain(core=%08x, grain=%i)", core, grain); + sas.grainSize = grain; + return 0; +} + +u32 sceSasGetOutputMode(u32 core) +{ + DEBUG_LOG(HLE,"0=sceSasGetOutputMode(core=%08x)", core); + return sas.outputMode; +} + +u32 sceSasSetOutputMode(u32 core, u32 outputMode) +{ + DEBUG_LOG(HLE,"0=sceSasSetOutputMode(core=%08x, outputMode=%i)", core, outputMode); + sas.outputMode = outputMode; + return 0; +} + +void sceSasSetVoicePCM(u32 core, int voiceNum, u32 pcmAddr, int size, int loop) +{ + DEBUG_LOG(HLE,"0=sceSasSetVoicePCM(core=%08x, voicenum=%i, pcmAddr=%08x, size=%i, loop=%i)",core, voiceNum, pcmAddr, size, loop); + Voice &v = sas.voices[voiceNum]; + v.pcmAddr = pcmAddr; + v.size = size; + v.loop = loop; + v.playing = true; RETURN(0); } +u32 sceSasGetAllEnvelopeHeights(u32 core, u32 heightsAddr) +{ + DEBUG_LOG(HLE,"0=sceSasGetAllEnvelopeHeights(core=%08x, heightsAddr=%i)", core, heightsAddr); + if (Memory::IsValidAddress(heightsAddr)) { + for (int i = 0; i < sas.length; i++) { + int voiceHeight = sas.voices[i].height; + Memory::Write_U32(voiceHeight, heightsAddr + i * 4); + } + } + return 0; +} const HLEFunction sceSasCore[] = { {0x42778a9f, WrapU_UUUUU, "__sceSasInit"}, // (SceUID * sasCore, int grain, int maxVoices, int outputMode, int sampleRate) {0xa3589d81, WrapV_UU<_sceSasCore>, "__sceSasCore"}, {0x50a14dfc, WrapV_UU<_sceSasCoreWithMix>, "__sceSasCoreWithMix"}, // Process and mix into buffer (int sasCore, int sasInOut, int leftVolume, int rightVolume) - {0x68a46b95, WrapU_V, "__sceSasGetEndFlag"}, // int sasCore + {0x68a46b95, WrapU_U, "__sceSasGetEndFlag"}, // int sasCore {0x440ca7d8, WrapV_UIIIII, "__sceSasSetVolume"}, {0xad84d37f, WrapV_UII, "__sceSasSetPitch"}, {0x99944089, WrapV_UIUII, "__sceSasSetVoice"}, // (int sasCore, int voice, int vagAddr, int size, int loopmode) @@ -489,16 +570,16 @@ const HLEFunction sceSasCore[] = {0xd5a229c9, WrapV_UII, "__sceSasRevEVOL"}, // (int sasCore, int leftVol, int rightVol) // effect volume {0x33d4ab37, WrapV_UI, "__sceSasRevType"}, // (int sasCore, int type) {0x267a6dd2, WrapV_UII, "__sceSasRevParam"}, // (int sasCore, int delay, int feedback) - {0x2c8e6ab3, WrapU_V, "__sceSasGetPauseFlag"}, // int sasCore - {0x787d04d5, 0, "__sceSasSetPause"}, + {0x2c8e6ab3, WrapU_U, "__sceSasGetPauseFlag"}, // int sasCore + {0x787d04d5, WrapU_UII, "__sceSasSetPause"}, {0xa232cbe6, 0, "__sceSasSetTriangularWave"}, // (int sasCore, int voice, int unknown) {0xd5ebbbcd, 0, "__sceSasSetSteepWave"}, // (int sasCore, int voice, int unknown) // square wave? - {0xBD11B7C2, 0, "__sceSasGetGrain"}, - {0xd1e0a01e, 0, "__sceSasSetGrain"}, - {0xe175ef66, WrapV_UII, "__sceSasGetOutputmode"}, - {0xe855bf76, 0, "__sceSasSetOutputmode"}, - {0x07f58c24, 0, "__sceSasGetAllEnvelopeHeights"}, // (int sasCore, int heightAddr) 32-bit heights, 0-0x40000000 - {0xE1CD9561, 0, "__sceSasSetVoicePCM"}, + {0xBD11B7C2, WrapU_U, "__sceSasGetGrain"}, + {0xd1e0a01e, WrapU_UI, "__sceSasSetGrain"}, + {0xe175ef66, WrapU_U, "__sceSasGetOutputmode"}, + {0xe855bf76, WrapU_UU, "__sceSasSetOutputmode"}, + {0x07f58c24, WrapU_UU, "__sceSasGetAllEnvelopeHeights"}, // (int sasCore, int heightAddr) 32-bit heights, 0-0x40000000 + {0xE1CD9561, WrapV_UIUII, "__sceSasSetVoicePCM"}, }; void Register_sceSasCore() diff --git a/Core/HLE/sceUmd.cpp b/Core/HLE/sceUmd.cpp index 1a2e40afa8..4ab88c44bc 100644 --- a/Core/HLE/sceUmd.cpp +++ b/Core/HLE/sceUmd.cpp @@ -107,13 +107,10 @@ u32 sceUmdGetDiscInfo(u32 infoAddr) return PSP_ERROR_UMD_INVALID_PARAM; } -void sceUmdActivate(u32 unknown, const char *name) +int sceUmdActivate(u32 unknown, const char *name) { if (unknown < 1 || unknown > 2) - { - RETURN(PSP_ERROR_UMD_INVALID_PARAM); - return; - } + return PSP_ERROR_UMD_INVALID_PARAM; bool changed = umdActivated == 0; __KernelUmdActivate(); @@ -129,20 +126,18 @@ void sceUmdActivate(u32 unknown, const char *name) u32 notifyArg = UMD_PRESENT | UMD_READABLE; __KernelNotifyCallbackType(THREAD_CALLBACK_UMD, -1, notifyArg); - RETURN(0); if (changed) - __KernelReSchedule("umd activated"); + hleReSchedule("umd activated"); + + return 0; } -void sceUmdDeactivate(u32 unknown, const char *name) +int sceUmdDeactivate(u32 unknown, const char *name) { // Why 18? No idea. if (unknown < 0 || unknown > 18) - { - RETURN(PSP_ERROR_UMD_INVALID_PARAM); - return; - } + return PSP_ERROR_UMD_INVALID_PARAM; bool changed = umdActivated != 0; __KernelUmdDeactivate(); @@ -158,10 +153,11 @@ void sceUmdDeactivate(u32 unknown, const char *name) u32 notifyArg = UMD_PRESENT | UMD_READY; __KernelNotifyCallbackType(THREAD_CALLBACK_UMD, -1, notifyArg); - RETURN(0); if (changed) - __KernelReSchedule("umd deactivated"); + hleReSchedule("umd deactivated"); + + return 0; } u32 sceUmdRegisterUMDCallBack(u32 cbId) @@ -260,17 +256,13 @@ void sceUmdWaitDriveStatWithTimer(u32 stat, u32 timeout) } -void sceUmdWaitDriveStatCB(u32 stat, u32 timeout) +int sceUmdWaitDriveStatCB(u32 stat, u32 timeout) { - RETURN(0); - if (driveCBId != -1) { DEBUG_LOG(HLE,"0=sceUmdWaitDriveStatCB(stat = %08x, timeout = %d)", stat, timeout); - bool callbacksProcessed = __KernelForceCallbacks(); - if (callbacksProcessed) - __KernelExecutePendingMipsCalls(); + hleCheckCurrentCallbacks(); } else { @@ -284,8 +276,11 @@ void sceUmdWaitDriveStatCB(u32 stat, u32 timeout) __UmdWaitStat(timeout); __KernelWaitCurThread(WAITTYPE_UMD, 1, stat, 0, true); - __KernelCheckCallbacks(); } + else if (driveCBId != -1) + hleReSchedule("umd stat waited"); + + return 0; } void sceUmdCancelWaitDriveStat() @@ -307,13 +302,13 @@ u32 sceUmdGetErrorStat() const HLEFunction sceUmdUser[] = { - {0xC6183D47,WrapV_UC,"sceUmdActivate"}, + {0xC6183D47,WrapI_UC,"sceUmdActivate"}, {0x6B4A146C,&WrapU_V,"sceUmdGetDriveStat"}, {0x46EBB729,WrapI_V,"sceUmdCheckMedium"}, - {0xE83742BA,WrapV_UC,"sceUmdDeactivate"}, + {0xE83742BA,WrapI_UC,"sceUmdDeactivate"}, {0x8EF08FCE,WrapV_U,"sceUmdWaitDriveStat"}, {0x56202973,WrapV_UU,"sceUmdWaitDriveStatWithTimer"}, - {0x4A9E5E29,WrapV_UU,"sceUmdWaitDriveStatCB"}, + {0x4A9E5E29,WrapI_UU,"sceUmdWaitDriveStatCB"}, {0x6af9b50a,sceUmdCancelWaitDriveStat,"sceUmdCancelWaitDriveStat"}, {0x6B4A146C,&WrapU_V,"sceUmdGetDriveStat"}, {0x20628E6F,&WrapU_V,"sceUmdGetErrorStat"}, diff --git a/Core/HLE/sceVaudio.cpp b/Core/HLE/sceVaudio.cpp index 6ca72b69d0..8b7168e631 100644 --- a/Core/HLE/sceVaudio.cpp +++ b/Core/HLE/sceVaudio.cpp @@ -16,17 +16,30 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include "HLE.h" - +#include "FunctionWrappers.h" #include "sceVaudio.h" -const HLEFunction sceVaudio[] = -{ - {0x03b6807d, 0, "sceVaudio_0x03b6807d"}, - {0x67585dfd, 0, "sceVaudio_0x67585dfd"}, - {0x8986295e, 0, "sceVaudio_0x8986295e"}, +u32 sceVaudioOutputBlocking() { + ERROR_LOG(HLE, "UNIMPL sceVaudioOutputBlocking(...)"); + return 0; +} + +u32 sceVaudioChReserve() { + ERROR_LOG(HLE, "UNIMPL sceVaudioChReserve(...)"); + return 0; +} + +u32 sceVaudioChRelease() { + ERROR_LOG(HLE, "UNIMPL sceVaudioChRelease(...)"); + return 0; +} + +const HLEFunction sceVaudio[] = { + {0x03b6807d, WrapU_V, "sceVaudioOutputBlockingFunction"}, + {0x67585dfd, WrapU_V, "sceVaudioChReserveFunction"}, + {0x8986295e, WrapU_V, "sceVaudioChReleaseFunction"}, }; -void Register_sceVaudio() -{ +void Register_sceVaudio() { RegisterModule("sceVaudio",ARRAY_SIZE(sceVaudio), sceVaudio ); } diff --git a/pspautotests b/pspautotests index 099ac403dd..e9b4496e32 160000 --- a/pspautotests +++ b/pspautotests @@ -1 +1 @@ -Subproject commit 099ac403ddb436f94e7b2227e5c491027641e556 +Subproject commit e9b4496e32bb592dfff14b93abf284ff20783d3c diff --git a/test.py b/test.py index e6b53b375f..81f815872f 100755 --- a/test.py +++ b/test.py @@ -60,13 +60,16 @@ tests_good = [ "threads/lwmutex/create/create", "threads/lwmutex/delete/delete", "threads/lwmutex/lock/lock", + "threads/lwmutex/priority/priority", "threads/lwmutex/try/try", "threads/lwmutex/try600/try600", "threads/lwmutex/unlock/unlock", "threads/mbx/mbx", + "threads/mutex/mutex", "threads/mutex/create/create", "threads/mutex/delete/delete", "threads/mutex/lock/lock", + "threads/mutex/priority/priority", "threads/mutex/try/try", "threads/mutex/unlock/unlock", "threads/semaphores/semaphores", @@ -74,6 +77,7 @@ tests_good = [ "threads/semaphores/create/create", "threads/semaphores/delete/delete", "threads/semaphores/poll/poll", + "threads/semaphores/priority/priority", "threads/semaphores/refer/refer", "threads/semaphores/signal/signal", "threads/semaphores/wait/wait", @@ -89,10 +93,7 @@ tests_next = [ "threads/fpl/fpl", "threads/k0/k0", "threads/msgpipe/msgpipe", - "threads/mutex/mutex", - "threads/mutex/priority/priority", "threads/scheduling/scheduling", - "threads/semaphores/priority/priority", "threads/threads/threads", "threads/vpl/vpl", "threads/vtimers/vtimer",