This commit is contained in:
Xele02 2012-12-09 16:52:33 +01:00
commit 4fce289c02
21 changed files with 895 additions and 794 deletions

View file

@ -83,6 +83,11 @@ template<int func(u32)> void WrapI_U() {
RETURN(retval); RETURN(retval);
} }
template<int func(u32, int)> void WrapI_UI() {
int retval = func(PARAM(0), PARAM(1));
RETURN(retval);
}
template<u32 func(int, u32, int)> void WrapU_IUI() { template<u32 func(int, u32, int)> void WrapU_IUI() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2)); u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
RETURN(retval); RETURN(retval);
@ -103,6 +108,8 @@ template<u32 func(int)> void WrapU_I() {
RETURN(retval); RETURN(retval);
} }
template<int func(int)> void WrapI_I() { template<int func(int)> void WrapI_I() {
int retval = func(PARAM(0)); int retval = func(PARAM(0));
RETURN(retval); RETURN(retval);
@ -128,6 +135,11 @@ template<void func(u32, const char *)> void WrapV_UC() {
func(PARAM(0), Memory::GetCharPointer(PARAM(1))); func(PARAM(0), Memory::GetCharPointer(PARAM(1)));
} }
template<int func(u32, const char *)> void WrapI_UC() {
int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)));
RETURN(retval);
}
template<u32 func(u32, int , int , int, int, int, int)> void WrapU_UIIIIII() { template<u32 func(u32, int , int , int, int, int, int)> void WrapU_UIIIIII() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6)); u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6));
RETURN(retval); RETURN(retval);
@ -220,6 +232,12 @@ template<int func(const char *, u32, u32, u32)> void WrapI_CUUU() {
RETURN(retval); RETURN(retval);
} }
template<int func(const char *, u32, u32, int, u32, u32)> void WrapI_CUUIUU() {
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
PARAM(3), PARAM(4), PARAM(5));
RETURN(retval);
}
template<u32 func(const char *, u32)> void WrapU_CU() { template<u32 func(const char *, u32)> void WrapU_CU() {
u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1)); u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1));
RETURN((u32) retval); RETURN((u32) retval);
@ -262,6 +280,11 @@ template<void func(u32, int, u32)> void WrapV_UIU() {
func(PARAM(0), PARAM(1), PARAM(2)); func(PARAM(0), PARAM(1), PARAM(2));
} }
template<int func(u32, int, u32)> void WrapI_UIU() {
int retval = func(PARAM(0), PARAM(1), PARAM(2));
RETURN(retval);
}
template<void func(int, u32, u32, u32, u32)> void WrapV_IUUUU() { template<void func(int, u32, u32, u32, u32)> void WrapV_IUUUU() {
func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
} }
@ -278,16 +301,33 @@ template<void func(const char *, u32, int, u32)> void WrapV_CUIU() {
func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3)); func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3));
} }
template<int func(const char *, u32, int, u32)> void WrapI_CUIU() {
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3));
RETURN(retval);
}
template<void func(u32, const char *, u32, int, u32)> void WrapV_UCUIU() { template<void func(u32, const char *, u32, int, u32)> void WrapV_UCUIU() {
func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3), func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3),
PARAM(4)); PARAM(4));
} }
template<int func(u32, const char *, u32, int, u32)> void WrapI_UCUIU() {
int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2),
PARAM(3), PARAM(4));
RETURN(retval);
}
template<void func(const char *, u32, int, int, u32)> void WrapV_CUIIU() { template<void func(const char *, u32, int, int, u32)> void WrapV_CUIIU() {
func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3), func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3),
PARAM(4)); PARAM(4));
} }
template<int func(const char *, u32, int, int, u32)> void WrapI_CUIIU() {
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
PARAM(3), PARAM(4));
RETURN(retval);
}
template<u32 func(u32, u32, u32, u32)> void WrapU_UUUU() { template<u32 func(u32, u32, u32, u32)> void WrapU_UUUU() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
RETURN(retval); RETURN(retval);

View file

@ -25,10 +25,27 @@
#include "sceIo.h" #include "sceIo.h"
#include "sceAudio.h" #include "sceAudio.h"
#include "sceKernelMemory.h" #include "sceKernelMemory.h"
#include "sceKernelThread.h"
#include "../MIPS/MIPSCodeUtils.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<HLEModule> moduleDB; static std::vector<HLEModule> moduleDB;
static std::vector<Syscall> unresolvedSyscalls; static std::vector<Syscall> unresolvedSyscalls;
static int hleAfterSyscall = HLE_AFTER_NOTHING;
static const char *hleAfterSyscallReschedReason = NULL;
void HLEInit() void HLEInit()
{ {
@ -177,6 +194,47 @@ const char *GetFuncName(int moduleIndex, int func)
return "[unknown]"; 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) void CallSyscall(u32 op)
{ {
u32 callno = (op >> 6) & 0xFFFFF; //20 bits u32 callno = (op >> 6) & 0xFFFFF; //20 bits
@ -192,6 +250,9 @@ void CallSyscall(u32 op)
if (func) if (func)
{ {
func(); func();
if (hleAfterSyscall != HLE_AFTER_NOTHING)
hleFinishSyscall();
} }
else else
{ {

View file

@ -73,6 +73,14 @@ int GetModuleIndex(const char *modulename);
void RegisterModule(const char *name, int numFunctions, const HLEFunction *funcTable); 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 HLEInit();
void HLEShutdown(); void HLEShutdown();

View file

@ -46,8 +46,8 @@ const int audioIntervalUs = (int)(1000000ULL * hwBlockSize / hwSampleRate);
const int audioHostIntervalUs = (int)(1000000ULL * hostAttemptBlockSize / hwSampleRate); const int audioHostIntervalUs = (int)(1000000ULL * hostAttemptBlockSize / hwSampleRate);
// High and low watermarks, basically. // High and low watermarks, basically.
const int chanQueueMaxSizeFactor = 2; const int chanQueueMaxSizeFactor = 4;
const int chanQueueMinSizeFactor = 1; const int chanQueueMinSizeFactor = 2;
FixedSizeQueue<s16, hwBlockSize * 8> outAudioQueue; FixedSizeQueue<s16, hwBlockSize * 8> outAudioQueue;

View file

@ -6,7 +6,7 @@
// This program is distributed in the hope that it will be useful, // This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // 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. // GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program. // 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 // Not sure about the range of volume, I often see 0x800 so that might be either
// max or 50%? // max or 50%?
void sceAudioOutputBlocking(u32 chan, u32 vol, u32 samplePtr) u32 sceAudioOutputBlocking(u32 chan, u32 vol, u32 samplePtr) {
{ if (samplePtr == 0) {
if (samplePtr == 0)
{
ERROR_LOG(HLE, "sceAudioOutputBlocking - Sample pointer null"); 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"); ERROR_LOG(HLE,"sceAudioOutputBlocking() - BAD CHANNEL");
RETURN(SCE_ERROR_AUDIO_INVALID_CHANNEL); return SCE_ERROR_AUDIO_INVALID_CHANNEL;
} } else if (!chans[chan].reserved) {
else if (!chans[chan].reserved)
{
ERROR_LOG(HLE,"sceAudioOutputBlocking() - channel not reserved"); ERROR_LOG(HLE,"sceAudioOutputBlocking() - channel not reserved");
RETURN(SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED); return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED;
} } else {
else
{
DEBUG_LOG(HLE, "sceAudioOutputBlocking(%d, %d, %08x )",chan,vol,samplePtr); DEBUG_LOG(HLE, "sceAudioOutputBlocking(%d, %d, %08x )",chan,vol,samplePtr);
chans[chan].leftVolume = vol; chans[chan].leftVolume = vol;
chans[chan].rightVolume = vol; chans[chan].rightVolume = vol;
chans[chan].sampleAddress = samplePtr; chans[chan].sampleAddress = samplePtr;
RETURN(0); return __AudioEnqueue(chans[chan], chan, true);
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);
}
} }
} }
void sceAudioOutputPannedBlocking(u32 chan, u32 volume1, u32 volume2, u32 samplePtr) u32 sceAudioOutputPannedBlocking(u32 chan, u32 volume1, u32 volume2, u32 samplePtr) {
{ if (samplePtr == 0) {
if (samplePtr == 0) ERROR_LOG(HLE, "sceAudioOutputPannedBlocking - Sample pointer null");
{ return 0;
ERROR_LOG(HLE, "sceAudioOutputPannedBlocking - Sample pointer null"); } else if (chan < 0 || chan >= MAX_CHANNEL) {
RETURN(0);
}
else if (chan < 0 || chan >= MAX_CHANNEL)
{
ERROR_LOG(HLE,"sceAudioOutputPannedBlocking() - BAD CHANNEL"); ERROR_LOG(HLE,"sceAudioOutputPannedBlocking() - BAD CHANNEL");
RETURN(SCE_ERROR_AUDIO_INVALID_CHANNEL); return SCE_ERROR_AUDIO_INVALID_CHANNEL;
} } else if (!chans[chan].reserved) {
else if (!chans[chan].reserved)
{
ERROR_LOG(HLE,"sceAudioOutputPannedBlocking() - CHANNEL NOT RESERVED"); ERROR_LOG(HLE,"sceAudioOutputPannedBlocking() - CHANNEL NOT RESERVED");
RETURN(SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED); return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED;
} } else {
else DEBUG_LOG(HLE, "sceAudioOutputPannedBlocking(%d,%d,%d, %08x )", chan, volume1, volume2, samplePtr);
{
DEBUG_LOG(HLE, "sceAudioOutputPannedBlocking(%d,%d,%d, %08x )", chan, volume1, volume2, samplePtr);
chans[chan].leftVolume = volume1; chans[chan].leftVolume = volume1;
chans[chan].rightVolume = volume2; chans[chan].rightVolume = volume2;
chans[chan].sampleAddress = samplePtr; chans[chan].sampleAddress = samplePtr;
RETURN(0); return __AudioEnqueue(chans[chan], chan, true);
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);
}
} }
} }
u32 sceAudioOutput(u32 chan, u32 vol, u32 samplePtr) 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"); ERROR_LOG(HLE,"sceAudioOutput() - BAD CHANNEL");
return SCE_ERROR_AUDIO_INVALID_CHANNEL; return SCE_ERROR_AUDIO_INVALID_CHANNEL;
} }
@ -175,7 +149,7 @@ int sceAudioGetChannelRestLength(u32 chan)
static int GetFreeChannel() static int GetFreeChannel()
{ {
for (int i = 0; i < MAX_CHANNEL; i++) for (int i = 0; i < MAX_CHANNEL; i++)
{ {
if (!chans[i].reserved) if (!chans[i].reserved)
{ {
return i; return i;
@ -240,64 +214,64 @@ u32 sceAudioChRelease(u32 chan)
u32 sceAudioSetChannelDataLen(u32 chan, u32 len) u32 sceAudioSetChannelDataLen(u32 chan, u32 len)
{ {
if (chan < 0 || chan >= MAX_CHANNEL) if (chan < 0 || chan >= MAX_CHANNEL)
{ {
ERROR_LOG(HLE,"sceAudioSetChannelDataLen(%i, %i) - BAD CHANNEL", chan, len); ERROR_LOG(HLE,"sceAudioSetChannelDataLen(%i, %i) - BAD CHANNEL", chan, len);
return SCE_ERROR_AUDIO_INVALID_CHANNEL; return SCE_ERROR_AUDIO_INVALID_CHANNEL;
} }
else if (!chans[chan].reserved) else if (!chans[chan].reserved)
{ {
ERROR_LOG(HLE,"sceAudioSetChannelDataLen(%i, %i) - channel not reserved", chan, len); ERROR_LOG(HLE,"sceAudioSetChannelDataLen(%i, %i) - channel not reserved", chan, len);
return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED; return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED;
} }
else else
{ {
DEBUG_LOG(HLE, "sceAudioSetChannelDataLen(%i, %i)", chan, len); DEBUG_LOG(HLE, "sceAudioSetChannelDataLen(%i, %i)", chan, len);
//chans[chan].dataLen = len; //chans[chan].dataLen = len;
chans[chan].sampleCount = len; chans[chan].sampleCount = len;
return 0; return 0;
} }
} }
u32 sceAudioChangeChannelConfig(u32 chan, u32 format) u32 sceAudioChangeChannelConfig(u32 chan, u32 format)
{ {
if (chan < 0 || chan >= MAX_CHANNEL) if (chan < 0 || chan >= MAX_CHANNEL)
{ {
ERROR_LOG(HLE,"sceAudioChangeChannelConfig(%i, %i) - invalid channel number", chan, format); ERROR_LOG(HLE,"sceAudioChangeChannelConfig(%i, %i) - invalid channel number", chan, format);
return SCE_ERROR_AUDIO_INVALID_CHANNEL; return SCE_ERROR_AUDIO_INVALID_CHANNEL;
} }
else if (!chans[chan].reserved) else if (!chans[chan].reserved)
{ {
ERROR_LOG(HLE,"sceAudioChangeChannelConfig(%i, %i) - channel not reserved", chan, format); ERROR_LOG(HLE,"sceAudioChangeChannelConfig(%i, %i) - channel not reserved", chan, format);
return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED; return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED;
} }
else else
{ {
DEBUG_LOG(HLE, "sceAudioChangeChannelConfig(%i, %i)", chan, format); DEBUG_LOG(HLE, "sceAudioChangeChannelConfig(%i, %i)", chan, format);
chans[chan].format = format; chans[chan].format = format;
return 0; return 0;
} }
} }
u32 sceAudioChangeChannelVolume(u32 chan, u32 lvolume, u32 rvolume) u32 sceAudioChangeChannelVolume(u32 chan, u32 lvolume, u32 rvolume)
{ {
if (chan < 0 || chan >= MAX_CHANNEL) if (chan < 0 || chan >= MAX_CHANNEL)
{ {
ERROR_LOG(HLE,"sceAudioChangeChannelVolume(%i, %i, %i) - invalid channel number", chan, lvolume, rvolume); ERROR_LOG(HLE,"sceAudioChangeChannelVolume(%i, %i, %i) - invalid channel number", chan, lvolume, rvolume);
return SCE_ERROR_AUDIO_INVALID_CHANNEL; return SCE_ERROR_AUDIO_INVALID_CHANNEL;
} }
else if (!chans[chan].reserved) else if (!chans[chan].reserved)
{ {
ERROR_LOG(HLE,"sceAudioChangeChannelVolume(%i, %i, %i) - channel not reserved", chan, lvolume, rvolume); ERROR_LOG(HLE,"sceAudioChangeChannelVolume(%i, %i, %i) - channel not reserved", chan, lvolume, rvolume);
return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED; return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED;
} }
else else
{ {
DEBUG_LOG(HLE, "sceAudioChangeChannelVolume(%i, %i, %i)", chan, lvolume, rvolume); DEBUG_LOG(HLE, "sceAudioChangeChannelVolume(%i, %i, %i)", chan, lvolume, rvolume);
chans[chan].leftVolume = lvolume; chans[chan].leftVolume = lvolume;
chans[chan].rightVolume = rvolume; chans[chan].rightVolume = rvolume;
return 0; return 0;
} }
} }
u32 sceAudioInit() u32 sceAudioInit()
@ -321,16 +295,13 @@ u32 sceAudioOutput2Reserve(u32 sampleCount)
return 0; return 0;
} }
void sceAudioOutput2OutputBlocking(u32 vol, u32 dataPtr) u32 sceAudioOutput2OutputBlocking(u32 vol, u32 dataPtr)
{ {
DEBUG_LOG(HLE,"FAKE sceAudioOutput2OutputBlocking(%i, %08x)", vol, dataPtr); DEBUG_LOG(HLE,"FAKE sceAudioOutput2OutputBlocking(%i, %08x)", vol, dataPtr);
chans[0].leftVolume = vol; chans[0].leftVolume = vol;
chans[0].rightVolume = vol; chans[0].rightVolume = vol;
chans[0].sampleAddress = dataPtr; chans[0].sampleAddress = dataPtr;
RETURN(0); return __AudioEnqueue(chans[0], 0, true);
u32 retval = __AudioEnqueue(chans[0], 0, true);
if (retval < 0)
RETURN(retval);
} }
u32 sceAudioOutput2ChangeLength(u32 sampleCount) u32 sceAudioOutput2ChangeLength(u32 sampleCount)
@ -342,7 +313,7 @@ u32 sceAudioOutput2ChangeLength(u32 sampleCount)
u32 sceAudioOutput2GetRestSample() u32 sceAudioOutput2GetRestSample()
{ {
WARN_LOG(HLE,"UNTESTED sceAudioOutput2GetRestSample()"); WARN_LOG(HLE,"UNTESTED sceAudioOutput2GetRestSample()");
return chans[0].sampleQueue.size() * 2; 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 // Newer simplified single channel audio output. Presumably for games that use Atrac3
// directly from Sas instead of playing it on a separate audio channel. // directly from Sas instead of playing it on a separate audio channel.
{0x01562ba3, WrapU_U<sceAudioOutput2Reserve>, "sceAudioOutput2Reserve"}, {0x01562ba3, WrapU_U<sceAudioOutput2Reserve>, "sceAudioOutput2Reserve"},
{0x2d53f36e, WrapV_UU<sceAudioOutput2OutputBlocking>, "sceAudioOutput2OutputBlocking"}, {0x2d53f36e, WrapU_UU<sceAudioOutput2OutputBlocking>, "sceAudioOutput2OutputBlocking"},
{0x63f2889c, WrapU_U<sceAudioOutput2ChangeLength>, "sceAudioOutput2ChangeLength"}, {0x63f2889c, WrapU_U<sceAudioOutput2ChangeLength>, "sceAudioOutput2ChangeLength"},
{0x647cef33, WrapU_V<sceAudioOutput2GetRestSample>, "sceAudioOutput2GetRestSample"}, {0x647cef33, WrapU_V<sceAudioOutput2GetRestSample>, "sceAudioOutput2GetRestSample"},
{0x43196845, WrapU_V<sceAudioOutput2Release>, "sceAudioOutput2Release"}, {0x43196845, WrapU_V<sceAudioOutput2Release>, "sceAudioOutput2Release"},
{0x80F1F7E0, WrapU_V<sceAudioInit>, "sceAudioInit"}, {0x80F1F7E0, WrapU_V<sceAudioInit>, "sceAudioInit"},
{0x210567F7, WrapU_V<sceAudioEnd>, "sceAudioEnd"}, {0x210567F7, WrapU_V<sceAudioEnd>, "sceAudioEnd"},
{0xA2BEAA6C, WrapU_U<sceAudioSetFrequency>, "sceAudioSetFrequency"}, {0xA2BEAA6C, WrapU_U<sceAudioSetFrequency>, "sceAudioSetFrequency"},
{0x927AC32B, 0, "sceAudioSetVolumeOffset"}, {0x927AC32B, 0, "sceAudioSetVolumeOffset"},
// The oldest and standard audio interface. Supports 8 channels, most games use 1-2. // The oldest and standard audio interface. Supports 8 channels, most games use 1-2.
{0x8c1009b2, WrapU_UUU<sceAudioOutput>, "sceAudioOutput"}, {0x8c1009b2, WrapU_UUU<sceAudioOutput>, "sceAudioOutput"},
{0x136CAF51, WrapV_UUU<sceAudioOutputBlocking>, "sceAudioOutputBlocking"}, {0x136CAF51, WrapU_UUU<sceAudioOutputBlocking>, "sceAudioOutputBlocking"},
{0xE2D56B2D, WrapU_UUUU<sceAudioOutputPanned>, "sceAudioOutputPanned"}, {0xE2D56B2D, WrapU_UUUU<sceAudioOutputPanned>, "sceAudioOutputPanned"},
{0x13F592BC, WrapV_UUUU<sceAudioOutputPannedBlocking>, "sceAudioOutputPannedBlocking"}, //(u32, u32, u32, void *)Output sound, blocking {0x13F592BC, WrapU_UUUU<sceAudioOutputPannedBlocking>, "sceAudioOutputPannedBlocking"}, //(u32, u32, u32, void *)Output sound, blocking
{0x5EC81C55, WrapU_UUU<sceAudioChReserve>, "sceAudioChReserve"}, //(u32, u32 samplecount, u32) Initialize channel and allocate buffer long, long samplecount, long);//init buffer? returns handle, minus if error {0x5EC81C55, WrapU_UUU<sceAudioChReserve>, "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>, "sceAudioChRelease"}, //(long handle)Terminate channel and deallocate buffer //free buffer? {0x6FC46853, WrapU_U<sceAudioChRelease>, "sceAudioChRelease"}, //(long handle)Terminate channel and deallocate buffer //free buffer?
{0xE9D97901, WrapI_U<sceAudioGetChannelRestLen>, "sceAudioGetChannelRestLen"}, {0xE9D97901, WrapI_U<sceAudioGetChannelRestLen>, "sceAudioGetChannelRestLen"},
{0xB011922F, WrapI_U<sceAudioGetChannelRestLen>, "sceAudioGetChannelRestLength"}, // Is there a difference between this and sceAudioGetChannelRestLen? {0xB011922F, WrapI_U<sceAudioGetChannelRestLen>, "sceAudioGetChannelRestLength"}, // Is there a difference between this and sceAudioGetChannelRestLen?
{0xCB2E439E, WrapU_UU<sceAudioSetChannelDataLen>, "sceAudioSetChannelDataLen"}, //(u32, u32) {0xCB2E439E, WrapU_UU<sceAudioSetChannelDataLen>, "sceAudioSetChannelDataLen"}, //(u32, u32)
{0x95FD0C2D, WrapU_UU<sceAudioChangeChannelConfig>, "sceAudioChangeChannelConfig"}, {0x95FD0C2D, WrapU_UU<sceAudioChangeChannelConfig>, "sceAudioChangeChannelConfig"},
{0xB7E1D8E7, WrapU_UUU<sceAudioChangeChannelVolume>, "sceAudioChangeChannelVolume"}, {0xB7E1D8E7, WrapU_UUU<sceAudioChangeChannelVolume>, "sceAudioChangeChannelVolume"},
// I guess these are like the others but do sample rate conversion? // I guess these are like the others but do sample rate conversion?
{0x38553111, 0, "sceAudioSRCChReserve"}, {0x38553111, 0, "sceAudioSRCChReserve"},
@ -405,9 +376,9 @@ const HLEFunction sceAudio[] =
// Microphone interface // Microphone interface
{0x7de61688, 0, "sceAudioInputInit"}, {0x7de61688, 0, "sceAudioInputInit"},
{0xE926D3FB, 0, "sceAudioInputInitEx"}, {0xE926D3FB, 0, "sceAudioInputInitEx"},
{0x6d4bec68, 0, "sceAudioInput"}, {0x6d4bec68, 0, "sceAudioInput"},
{0x086e5895, 0, "sceAudioInputBlocking"}, {0x086e5895, 0, "sceAudioInputBlocking"},
{0xa708c6a6, 0, "sceAudioGetInputLength"}, {0xa708c6a6, 0, "sceAudioGetInputLength"},
{0xA633048E, 0, "sceAudioPollInputEnd"}, {0xA633048E, 0, "sceAudioPollInputEnd"},
{0x87b2e651, 0, "sceAudioWaitInputEnd"}, {0x87b2e651, 0, "sceAudioWaitInputEnd"},
}; };
@ -416,5 +387,5 @@ const HLEFunction sceAudio[] =
void Register_sceAudio() void Register_sceAudio()
{ {
RegisterModule("sceAudio", ARRAY_SIZE(sceAudio), sceAudio); RegisterModule("sceAudio", ARRAY_SIZE(sceAudio), sceAudio);
} }

View file

@ -337,21 +337,18 @@ void sceDisplayWaitVblankCB()
{ {
DEBUG_LOG(HLE,"sceDisplayWaitVblankCB()"); DEBUG_LOG(HLE,"sceDisplayWaitVblankCB()");
__KernelWaitCurThread(WAITTYPE_VBLANK, 0, 0, 0, true); __KernelWaitCurThread(WAITTYPE_VBLANK, 0, 0, 0, true);
__KernelCheckCallbacks();
} }
void sceDisplayWaitVblankStartCB() void sceDisplayWaitVblankStartCB()
{ {
DEBUG_LOG(HLE,"sceDisplayWaitVblankStartCB()"); DEBUG_LOG(HLE,"sceDisplayWaitVblankStartCB()");
__KernelWaitCurThread(WAITTYPE_VBLANK, 0, 0, 0, true); __KernelWaitCurThread(WAITTYPE_VBLANK, 0, 0, 0, true);
__KernelCheckCallbacks();
} }
void sceDisplayWaitVblankStartMultiCB() void sceDisplayWaitVblankStartMultiCB()
{ {
DEBUG_LOG(HLE,"sceDisplayWaitVblankStartMultiCB()"); DEBUG_LOG(HLE,"sceDisplayWaitVblankStartMultiCB()");
__KernelWaitCurThread(WAITTYPE_VBLANK, 0, 0, 0, true); __KernelWaitCurThread(WAITTYPE_VBLANK, 0, 0, 0, true);
__KernelCheckCallbacks();
} }
void sceDisplayGetVcount() void sceDisplayGetVcount()

View file

@ -332,30 +332,30 @@ const HLEFunction ThreadManForUser[] =
{0xCD203292,&WrapU_V<sceKernelCancelEventFlag>, "sceKernelCancelEventFlag"}, {0xCD203292,&WrapU_V<sceKernelCancelEventFlag>, "sceKernelCancelEventFlag"},
{0xA66B0120,&WrapU_IU<sceKernelReferEventFlagStatus>, "sceKernelReferEventFlagStatus"}, {0xA66B0120,&WrapU_IU<sceKernelReferEventFlagStatus>, "sceKernelReferEventFlagStatus"},
{0x8FFDF9A2,&WrapV_IIU<sceKernelCancelSema>, "sceKernelCancelSema"}, {0x8FFDF9A2,&WrapI_IIU<sceKernelCancelSema>, "sceKernelCancelSema"},
{0xD6DA4BA1,&WrapV_CUIIU<sceKernelCreateSema>, "sceKernelCreateSema"}, {0xD6DA4BA1,&WrapI_CUIIU<sceKernelCreateSema>, "sceKernelCreateSema"},
{0x28b6489c,&WrapV_I<sceKernelDeleteSema>, "sceKernelDeleteSema"}, {0x28b6489c,&WrapI_I<sceKernelDeleteSema>, "sceKernelDeleteSema"},
{0x58b1f937,&WrapV_II<sceKernelPollSema>, "sceKernelPollSema"}, {0x58b1f937,&WrapI_II<sceKernelPollSema>, "sceKernelPollSema"},
{0xBC6FEBC5,&WrapV_IU<sceKernelReferSemaStatus>, "sceKernelReferSemaStatus"}, {0xBC6FEBC5,&WrapI_IU<sceKernelReferSemaStatus>, "sceKernelReferSemaStatus"},
{0x3F53E640,&WrapV_II<sceKernelSignalSema>, "sceKernelSignalSema"}, {0x3F53E640,&WrapI_II<sceKernelSignalSema>, "sceKernelSignalSema"},
{0x4E3A1105,&WrapV_IIU<sceKernelWaitSema>, "sceKernelWaitSema"}, {0x4E3A1105,&WrapI_IIU<sceKernelWaitSema>, "sceKernelWaitSema"},
{0x6d212bac,&WrapV_IIU<sceKernelWaitSemaCB>, "sceKernelWaitSemaCB"}, {0x6d212bac,&WrapI_IIU<sceKernelWaitSemaCB>, "sceKernelWaitSemaCB"},
{0x60107536,&WrapV_U<sceKernelDeleteLwMutex>, "sceKernelDeleteLwMutex"}, {0x60107536,&WrapI_U<sceKernelDeleteLwMutex>, "sceKernelDeleteLwMutex"},
{0x19CFF145,&WrapV_UCUIU<sceKernelCreateLwMutex>, "sceKernelCreateLwMutex"}, {0x19CFF145,&WrapI_UCUIU<sceKernelCreateLwMutex>, "sceKernelCreateLwMutex"},
{0xf8170fbe,&WrapV_I<sceKernelDeleteMutex>, "sceKernelDeleteMutex"}, {0xf8170fbe,&WrapI_I<sceKernelDeleteMutex>, "sceKernelDeleteMutex"},
{0xB011B11F,&WrapV_IIU<sceKernelLockMutex>, "sceKernelLockMutex"}, {0xB011B11F,&WrapI_IIU<sceKernelLockMutex>, "sceKernelLockMutex"},
{0x5bf4dd27,&WrapV_IIU<sceKernelLockMutexCB>, "sceKernelLockMutexCB"}, {0x5bf4dd27,&WrapI_IIU<sceKernelLockMutexCB>, "sceKernelLockMutexCB"},
{0x6b30100f,&WrapV_II<sceKernelUnlockMutex>, "sceKernelUnlockMutex"}, {0x6b30100f,&WrapI_II<sceKernelUnlockMutex>, "sceKernelUnlockMutex"},
{0xb7d098c6,&WrapV_CUIU<sceKernelCreateMutex>, "sceKernelCreateMutex"}, {0xb7d098c6,&WrapI_CUIU<sceKernelCreateMutex>, "sceKernelCreateMutex"},
{0x0DDCD2C9,&WrapV_II<sceKernelTryLockMutex>, "sceKernelTryLockMutex"}, {0x0DDCD2C9,&WrapI_II<sceKernelTryLockMutex>, "sceKernelTryLockMutex"},
// NOTE: LockLwMutex and UnlockLwMutex are in Kernel_Library, see sceKernelInterrupt.cpp. // NOTE: LockLwMutex and UnlockLwMutex are in Kernel_Library, see sceKernelInterrupt.cpp.
{0xFCCFAD26,sceKernelCancelWakeupThread,"sceKernelCancelWakeupThread"}, {0xFCCFAD26,sceKernelCancelWakeupThread,"sceKernelCancelWakeupThread"},
{0xea748e31,sceKernelChangeCurrentThreadAttr,"sceKernelChangeCurrentThreadAttr"}, {0xea748e31,sceKernelChangeCurrentThreadAttr,"sceKernelChangeCurrentThreadAttr"},
{0x71bc9871,sceKernelChangeThreadPriority,"sceKernelChangeThreadPriority"}, {0x71bc9871,sceKernelChangeThreadPriority,"sceKernelChangeThreadPriority"},
{0x446D8DE6,sceKernelCreateThread,"sceKernelCreateThread"}, {0x446D8DE6,WrapI_CUUIUU<sceKernelCreateThread>,"sceKernelCreateThread"},
{0x9fa03cd3,sceKernelDeleteThread,"sceKernelDeleteThread"}, {0x9fa03cd3,WrapI_I<sceKernelDeleteThread>,"sceKernelDeleteThread"},
{0xBD123D9E,0,"sceKernelDelaySysClockThread"}, {0xBD123D9E,0,"sceKernelDelaySysClockThread"},
{0x1181E963,0,"sceKernelDelaySysClockThreadCB"}, {0x1181E963,0,"sceKernelDelaySysClockThreadCB"},
{0xceadeb47,sceKernelDelayThread,"sceKernelDelayThread"}, {0xceadeb47,sceKernelDelayThread,"sceKernelDelayThread"},
@ -375,10 +375,10 @@ const HLEFunction ThreadManForUser[] =
{0x912354a7,sceKernelRotateThreadReadyQueue,"sceKernelRotateThreadReadyQueue"}, {0x912354a7,sceKernelRotateThreadReadyQueue,"sceKernelRotateThreadReadyQueue"},
{0x9ACE131E,sceKernelSleepThread,"sceKernelSleepThread"}, {0x9ACE131E,sceKernelSleepThread,"sceKernelSleepThread"},
{0x82826f70,sceKernelSleepThreadCB,"sceKernelSleepThreadCB"}, {0x82826f70,sceKernelSleepThreadCB,"sceKernelSleepThreadCB"},
{0xF475845D,&WrapV_IUU<sceKernelStartThread>,"sceKernelStartThread"}, {0xF475845D,&WrapI_IUU<sceKernelStartThread>,"sceKernelStartThread"},
{0x9944f31f,sceKernelSuspendThread,"sceKernelSuspendThread"}, {0x9944f31f,sceKernelSuspendThread,"sceKernelSuspendThread"},
{0x616403ba,WrapV_U<sceKernelTerminateThread>,"sceKernelTerminateThread"}, {0x616403ba,WrapI_U<sceKernelTerminateThread>,"sceKernelTerminateThread"},
{0x383f7bcc,sceKernelTerminateDeleteThread,"sceKernelTerminateDeleteThread"}, {0x383f7bcc,WrapI_I<sceKernelTerminateDeleteThread>,"sceKernelTerminateDeleteThread"},
{0x840E8133,sceKernelWaitThreadEndCB,"sceKernelWaitThreadEndCB"}, {0x840E8133,sceKernelWaitThreadEndCB,"sceKernelWaitThreadEndCB"},
{0xd13bde95,sceKernelCheckThreadStack,"sceKernelCheckThreadStack"}, {0xd13bde95,sceKernelCheckThreadStack,"sceKernelCheckThreadStack"},

View file

@ -232,7 +232,6 @@ void sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32
timeout = Memory::Read_U32(timeoutPtr); timeout = Memory::Read_U32(timeoutPtr);
__KernelWaitCurThread(WAITTYPE_EVENTFLAG, id, 0, 0, true); // sets RETURN __KernelWaitCurThread(WAITTYPE_EVENTFLAG, id, 0, 0, true); // sets RETURN
__KernelCheckCallbacks();
} }
} }
else else

View file

@ -439,11 +439,11 @@ const HLEFunction Kernel_Library[] =
{0x47a0b729,sceKernelIsCpuIntrSuspended, "sceKernelIsCpuIntrSuspended"}, //flags {0x47a0b729,sceKernelIsCpuIntrSuspended, "sceKernelIsCpuIntrSuspended"}, //flags
{0xb55249d2,sceKernelIsCpuIntrEnable, "sceKernelIsCpuIntrEnable"}, {0xb55249d2,sceKernelIsCpuIntrEnable, "sceKernelIsCpuIntrEnable"},
{0xa089eca4,sceKernelMemset, "sceKernelMemset"}, {0xa089eca4,sceKernelMemset, "sceKernelMemset"},
{0xDC692EE3,&WrapV_UI<sceKernelTryLockLwMutex>, "sceKernelTryLockLwMutex"}, {0xDC692EE3,&WrapI_UI<sceKernelTryLockLwMutex>, "sceKernelTryLockLwMutex"},
{0x37431849,&WrapV_UI<sceKernelTryLockLwMutex_600>, "sceKernelTryLockLwMutex_600"}, {0x37431849,&WrapI_UI<sceKernelTryLockLwMutex_600>, "sceKernelTryLockLwMutex_600"},
{0xbea46419,&WrapV_UIU<sceKernelLockLwMutex>, "sceKernelLockLwMutex"}, {0xbea46419,&WrapI_UIU<sceKernelLockLwMutex>, "sceKernelLockLwMutex"},
{0x1FC64E09,&WrapV_UIU<sceKernelLockLwMutexCB>, "sceKernelLockLwMutexCB"}, {0x1FC64E09,&WrapI_UIU<sceKernelLockLwMutexCB>, "sceKernelLockLwMutexCB"},
{0x15b6446b,&WrapV_UI<sceKernelUnlockLwMutex>, "sceKernelUnlockLwMutex"}, {0x15b6446b,&WrapI_UI<sceKernelUnlockLwMutex>, "sceKernelUnlockLwMutex"},
{0x293b45b8,sceKernelGetThreadId, "sceKernelGetThreadId"}, {0x293b45b8,sceKernelGetThreadId, "sceKernelGetThreadId"},
{0x1839852A,&WrapU_UUU<sceKernelMemcpy>,"sce_paf_private_memcpy"}, {0x1839852A,&WrapU_UUU<sceKernelMemcpy>,"sce_paf_private_memcpy"},
}; };

View file

@ -161,26 +161,39 @@ void __KernelMutexEraseLock(Mutex *mutex)
mutex->nm.lockThread = -1; mutex->nm.lockThread = -1;
} }
void sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optionsPtr) std::vector<SceUID>::iterator __KernelMutexFindPriority(std::vector<SceUID> &waiting)
{
_dbg_assert_msg_(HLE, !waiting.empty(), "__KernelMutexFindPriority: Trying to find best of no threads.");
std::vector<SceUID>::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) if (!mutexInitComplete)
__KernelMutexInit(); __KernelMutexInit();
u32 error = 0;
if (!name) if (!name)
error = SCE_KERNEL_ERROR_ERROR; return SCE_KERNEL_ERROR_ERROR;
else if (initialCount < 0) 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) if ((attr & PSP_MUTEX_ATTR_ALLOW_RECURSIVE) == 0 && initialCount > 1)
error = SCE_KERNEL_ERROR_ILLEGAL_COUNT; return SCE_KERNEL_ERROR_ILLEGAL_COUNT;
if (error) DEBUG_LOG(HLE, "sceKernelCreateMutex(%s, %08x, %d, %08x)", name, attr, initialCount, optionsPtr);
{
RETURN(error);
return;
}
DEBUG_LOG(HLE,"sceKernelCreateMutex(%s, %08x, %d, %08x)", name, attr, initialCount, optionsPtr);
Mutex *mutex = new Mutex(); Mutex *mutex = new Mutex();
SceUID id = kernelObjects.Create(mutex); SceUID id = kernelObjects.Create(mutex);
@ -198,12 +211,39 @@ void sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 opti
__KernelMutexAcquireLock(mutex, initialCount); __KernelMutexAcquireLock(mutex, initialCount);
if (optionsPtr != 0) 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); DEBUG_LOG(HLE,"sceKernelDeleteMutex(%i)", id);
u32 error; u32 error;
@ -213,35 +253,19 @@ void sceKernelDeleteMutex(SceUID id)
bool wokeThreads = false; bool wokeThreads = false;
std::vector<SceUID>::iterator iter, end; std::vector<SceUID>::iterator iter, end;
for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter) for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter)
{ wokeThreads |= __KernelUnlockMutexForThread(mutex, *iter, error, SCE_KERNEL_ERROR_WAIT_DELETE);
SceUID threadID = *iter;
SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_MUTEX, error);
// The waitID may be different after a timeout.
if (waitID != id)
continue;
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) if (mutex->nm.lockThread != -1)
__KernelMutexEraseLock(mutex); __KernelMutexEraseLock(mutex);
mutex->waitingThreads.clear(); mutex->waitingThreads.clear();
RETURN(kernelObjects.Destroy<Mutex>(id));
if (wokeThreads) if (wokeThreads)
__KernelReSchedule("mutex deleted"); hleReSchedule("mutex deleted");
return kernelObjects.Destroy<Mutex>(id);
} }
else else
RETURN(error); return error;
} }
bool __KernelLockMutex(Mutex *mutex, int count, u32 &error) bool __KernelLockMutex(Mutex *mutex, int count, u32 &error)
@ -289,37 +313,17 @@ bool __KernelUnlockMutex(Mutex *mutex, u32 &error)
{ {
__KernelMutexEraseLock(mutex); __KernelMutexEraseLock(mutex);
// TODO: PSP_MUTEX_ATTR_PRIORITY
bool wokeThreads = false; bool wokeThreads = false;
std::vector<SceUID>::iterator iter, end; std::vector<SceUID>::iterator iter;
retry: while (!wokeThreads && !mutex->waitingThreads.empty())
for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter)
{ {
SceUID threadID = *iter; if ((mutex->nm.attr & PSP_MUTEX_ATTR_PRIORITY) != 0)
SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_MUTEX, error); iter = __KernelMutexFindPriority(mutex->waitingThreads);
// The waitID may be different after a timeout. else
if (waitID != mutex->GetUID()) iter = mutex->waitingThreads.begin();
{
mutex->waitingThreads.erase(iter);
goto retry;
}
int wVal = (int)__KernelGetWaitValue(threadID, error); wokeThreads |= __KernelUnlockMutexForThread(mutex, *iter, error, 0);
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;
mutex->waitingThreads.erase(iter); mutex->waitingThreads.erase(iter);
break;
} }
if (!wokeThreads) if (!wokeThreads)
@ -345,10 +349,10 @@ void __KernelMutexThreadEnd(SceUID threadID)
u32 error; u32 error;
// If it was waiting on the mutex, it should finish now. // If it was waiting on the mutex, it should finish now.
SceUID mutexID = __KernelGetWaitID(threadID, WAITTYPE_MUTEX, error); SceUID waitingMutexID = __KernelGetWaitID(threadID, WAITTYPE_MUTEX, error);
if (mutexID) if (waitingMutexID)
{ {
Mutex *mutex = kernelObjects.Get<Mutex>(mutexID, error); Mutex *mutex = kernelObjects.Get<Mutex>(waitingMutexID, error);
if (mutex) if (mutex)
mutex->waitingThreads.erase(std::remove(mutex->waitingThreads.begin(), mutex->waitingThreads.end(), threadID), mutex->waitingThreads.end()); 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) // int sceKernelLockMutex(SceUID id, int count, int *timeout)
// void because it changes threads. int sceKernelLockMutex(SceUID id, int count, u32 timeoutPtr)
void 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; u32 error;
Mutex *mutex = kernelObjects.Get<Mutex>(id, error); Mutex *mutex = kernelObjects.Get<Mutex>(id, error);
if (__KernelLockMutex(mutex, count, error)) if (__KernelLockMutex(mutex, count, error))
{ return 0;
RETURN(0);
}
else if (error) else if (error)
RETURN(error); return error;
else else
{ {
mutex->waitingThreads.push_back(__KernelGetCurThread()); mutex->waitingThreads.push_back(__KernelGetCurThread());
__KernelWaitMutex(mutex, timeoutPtr); __KernelWaitMutex(mutex, timeoutPtr);
__KernelWaitCurThread(WAITTYPE_MUTEX, id, count, timeoutPtr, false); __KernelWaitCurThread(WAITTYPE_MUTEX, id, count, timeoutPtr, false);
// Return value will be overwritten by wait.
return 0;
} }
} }
// int sceKernelLockMutexCB(SceUID id, int count, int *timeout) // int sceKernelLockMutexCB(SceUID id, int count, int *timeout)
// void because it changes threads. int sceKernelLockMutexCB(SceUID id, int count, u32 timeoutPtr)
void 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; u32 error;
Mutex *mutex = kernelObjects.Get<Mutex>(id, error); Mutex *mutex = kernelObjects.Get<Mutex>(id, error);
if (__KernelLockMutex(mutex, count, error)) if (__KernelLockMutex(mutex, count, error))
{ {
RETURN(0); hleCheckCurrentCallbacks();
return 0;
} }
else if (error) else if (error)
RETURN(error); return error;
else else
{ {
mutex->waitingThreads.push_back(__KernelGetCurThread()); mutex->waitingThreads.push_back(__KernelGetCurThread());
__KernelWaitMutex(mutex, timeoutPtr); __KernelWaitMutex(mutex, timeoutPtr);
__KernelWaitCurThread(WAITTYPE_MUTEX, id, count, timeoutPtr, true); __KernelWaitCurThread(WAITTYPE_MUTEX, id, count, timeoutPtr, true);
__KernelCheckCallbacks();
// Return value will be overwritten by wait.
return 0;
} }
} }
// int sceKernelTryLockMutex(SceUID id, int count) // int sceKernelTryLockMutex(SceUID id, int count)
// void because it changes threads. int sceKernelTryLockMutex(SceUID id, int count)
void sceKernelTryLockMutex(SceUID id, int count)
{ {
DEBUG_LOG(HLE,"sceKernelTryLockMutex(%i, %i)", id, count); DEBUG_LOG(HLE, "sceKernelTryLockMutex(%i, %i)", id, count);
u32 error; u32 error;
Mutex *mutex = kernelObjects.Get<Mutex>(id, error); Mutex *mutex = kernelObjects.Get<Mutex>(id, error);
if (__KernelLockMutex(mutex, count, error)) if (__KernelLockMutex(mutex, count, error))
RETURN(0); return 0;
else if (error) else if (error)
RETURN(error); return error;
else else
RETURN(PSP_MUTEX_ERROR_TRYLOCK_FAILED); return PSP_MUTEX_ERROR_TRYLOCK_FAILED;
} }
// int sceKernelUnlockMutex(SceUID id, int count) // int sceKernelUnlockMutex(SceUID id, int count)
// void because it changes threads. int sceKernelUnlockMutex(SceUID id, int count)
void sceKernelUnlockMutex(SceUID id, int count)
{ {
DEBUG_LOG(HLE,"sceKernelUnlockMutex(%i, %i)", id, count); DEBUG_LOG(HLE, "sceKernelUnlockMutex(%i, %i)", id, count);
u32 error; u32 error;
Mutex *mutex = kernelObjects.Get<Mutex>(id, error); Mutex *mutex = kernelObjects.Get<Mutex>(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) if (error)
{ return error;
RETURN(error); if (count <= 0)
return; 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; mutex->nm.lockLevel -= count;
RETURN(0);
if (mutex->nm.lockLevel == 0) if (mutex->nm.lockLevel == 0)
{ {
if (__KernelUnlockMutex(mutex, error)) 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) if (!mutexInitComplete)
__KernelMutexInit(); __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) if (!name)
error = SCE_KERNEL_ERROR_ERROR; return SCE_KERNEL_ERROR_ERROR;
else if (initialCount < 0) 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) else if ((attr & PSP_MUTEX_ATTR_ALLOW_RECURSIVE) == 0 && initialCount > 1)
error = SCE_KERNEL_ERROR_ILLEGAL_COUNT; return SCE_KERNEL_ERROR_ILLEGAL_COUNT;
if (error)
{
RETURN(error);
return;
}
LwMutex *mutex = new LwMutex(); LwMutex *mutex = new LwMutex();
SceUID id = kernelObjects.Create(mutex); SceUID id = kernelObjects.Create(mutex);
@ -525,20 +516,44 @@ void sceKernelCreateLwMutex(u32 workareaPtr, const char *name, u32 attr, int ini
Memory::WriteStruct(workareaPtr, &workarea); Memory::WriteStruct(workareaPtr, &workarea);
if (optionsPtr != 0) 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)) if (!workareaPtr || !Memory::IsValidAddress(workareaPtr))
{ return SCE_KERNEL_ERROR_ILLEGAL_ADDR;
RETURN(SCE_KERNEL_ERROR_ILLEGAL_ADDR);
return;
}
NativeLwMutexWorkarea workarea; NativeLwMutexWorkarea workarea;
Memory::ReadStruct(workareaPtr, &workarea); Memory::ReadStruct(workareaPtr, &workarea);
@ -550,35 +565,19 @@ void sceKernelDeleteLwMutex(u32 workareaPtr)
bool wokeThreads = false; bool wokeThreads = false;
std::vector<SceUID>::iterator iter, end; std::vector<SceUID>::iterator iter, end;
for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter) for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter)
{ wokeThreads |= __KernelUnlockLwMutexForThread(mutex, workarea, *iter, error, SCE_KERNEL_ERROR_WAIT_DELETE);
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;
}
mutex->waitingThreads.clear(); mutex->waitingThreads.clear();
RETURN(kernelObjects.Destroy<LwMutex>(workarea.uid));
workarea.clear(); workarea.clear();
Memory::WriteStruct(workareaPtr, &workarea); Memory::WriteStruct(workareaPtr, &workarea);
if (wokeThreads) if (wokeThreads)
__KernelReSchedule("lwmutex deleted"); hleReSchedule("lwmutex deleted");
return kernelObjects.Destroy<LwMutex>(mutex->GetUID());
} }
else else
RETURN(error); return error;
} }
bool __KernelLockLwMutex(NativeLwMutexWorkarea &workarea, int count, u32 &error) bool __KernelLockLwMutex(NativeLwMutexWorkarea &workarea, int count, u32 &error)
@ -641,38 +640,17 @@ bool __KernelUnlockLwMutex(NativeLwMutexWorkarea &workarea, u32 &error)
return false; return false;
} }
// TODO: PSP_MUTEX_ATTR_PRIORITY
bool wokeThreads = false; bool wokeThreads = false;
std::vector<SceUID>::iterator iter, end; std::vector<SceUID>::iterator iter;
retry: while (!wokeThreads && !mutex->waitingThreads.empty())
for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter)
{ {
SceUID threadID = *iter; if ((mutex->nm.attr & PSP_MUTEX_ATTR_PRIORITY) != 0)
SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_LWMUTEX, error); iter = __KernelMutexFindPriority(mutex->waitingThreads);
// The waitID may be different after a timeout. else
if (waitID != mutex->GetUID()) iter = mutex->waitingThreads.begin();
{
mutex->waitingThreads.erase(iter);
goto retry;
}
int wVal = (int)__KernelGetWaitValue(threadID, error); wokeThreads |= __KernelUnlockLwMutexForThread(mutex, workarea, *iter, error, 0);
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;
mutex->waitingThreads.erase(iter); mutex->waitingThreads.erase(iter);
break;
} }
if (!wokeThreads) if (!wokeThreads)
@ -710,9 +688,9 @@ void __KernelWaitLwMutex(LwMutex *mutex, u32 timeoutPtr)
CoreTiming::ScheduleEvent(usToCycles(micro), lwMutexWaitTimer, __KernelGetCurThread()); 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; NativeLwMutexWorkarea workarea;
Memory::ReadStruct(workareaPtr, &workarea); Memory::ReadStruct(workareaPtr, &workarea);
@ -721,17 +699,18 @@ void sceKernelTryLockLwMutex(u32 workareaPtr, int count)
if (__KernelLockLwMutex(workarea, count, error)) if (__KernelLockLwMutex(workarea, count, error))
{ {
Memory::WriteStruct(workareaPtr, &workarea); Memory::WriteStruct(workareaPtr, &workarea);
RETURN(0); return 0;
} }
// Unlike sceKernelTryLockLwMutex_600, this always returns the same error.
else if (error) else if (error)
RETURN(PSP_MUTEX_ERROR_TRYLOCK_FAILED); return PSP_MUTEX_ERROR_TRYLOCK_FAILED;
else 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; NativeLwMutexWorkarea workarea;
Memory::ReadStruct(workareaPtr, &workarea); Memory::ReadStruct(workareaPtr, &workarea);
@ -740,17 +719,17 @@ void sceKernelTryLockLwMutex_600(u32 workareaPtr, int count)
if (__KernelLockLwMutex(workarea, count, error)) if (__KernelLockLwMutex(workarea, count, error))
{ {
Memory::WriteStruct(workareaPtr, &workarea); Memory::WriteStruct(workareaPtr, &workarea);
RETURN(0); return 0;
} }
else if (error) else if (error)
RETURN(error); return error;
else 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; NativeLwMutexWorkarea workarea;
Memory::ReadStruct(workareaPtr, &workarea); Memory::ReadStruct(workareaPtr, &workarea);
@ -759,10 +738,10 @@ void sceKernelLockLwMutex(u32 workareaPtr, int count, u32 timeoutPtr)
if (__KernelLockLwMutex(workarea, count, error)) if (__KernelLockLwMutex(workarea, count, error))
{ {
Memory::WriteStruct(workareaPtr, &workarea); Memory::WriteStruct(workareaPtr, &workarea);
RETURN(0); return 0;
} }
else if (error) else if (error)
RETURN(error); return error;
else else
{ {
LwMutex *mutex = kernelObjects.Get<LwMutex>(workarea.uid, error); LwMutex *mutex = kernelObjects.Get<LwMutex>(workarea.uid, error);
@ -771,15 +750,18 @@ void sceKernelLockLwMutex(u32 workareaPtr, int count, u32 timeoutPtr)
mutex->waitingThreads.push_back(__KernelGetCurThread()); mutex->waitingThreads.push_back(__KernelGetCurThread());
__KernelWaitLwMutex(mutex, timeoutPtr); __KernelWaitLwMutex(mutex, timeoutPtr);
__KernelWaitCurThread(WAITTYPE_LWMUTEX, workarea.uid, count, timeoutPtr, false); __KernelWaitCurThread(WAITTYPE_LWMUTEX, workarea.uid, count, timeoutPtr, false);
// Return value will be overwritten by wait.
return 0;
} }
else 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; NativeLwMutexWorkarea workarea;
Memory::ReadStruct(workareaPtr, &workarea); Memory::ReadStruct(workareaPtr, &workarea);
@ -788,10 +770,11 @@ void sceKernelLockLwMutexCB(u32 workareaPtr, int count, u32 timeoutPtr)
if (__KernelLockLwMutex(workarea, count, error)) if (__KernelLockLwMutex(workarea, count, error))
{ {
Memory::WriteStruct(workareaPtr, &workarea); Memory::WriteStruct(workareaPtr, &workarea);
RETURN(0); hleCheckCurrentCallbacks();
return 0;
} }
else if (error) else if (error)
RETURN(error); return error;
else else
{ {
LwMutex *mutex = kernelObjects.Get<LwMutex>(workarea.uid, error); LwMutex *mutex = kernelObjects.Get<LwMutex>(workarea.uid, error);
@ -800,48 +783,44 @@ void sceKernelLockLwMutexCB(u32 workareaPtr, int count, u32 timeoutPtr)
mutex->waitingThreads.push_back(__KernelGetCurThread()); mutex->waitingThreads.push_back(__KernelGetCurThread());
__KernelWaitLwMutex(mutex, timeoutPtr); __KernelWaitLwMutex(mutex, timeoutPtr);
__KernelWaitCurThread(WAITTYPE_LWMUTEX, workarea.uid, count, timeoutPtr, true); __KernelWaitCurThread(WAITTYPE_LWMUTEX, workarea.uid, count, timeoutPtr, true);
__KernelCheckCallbacks();
// Return value will be overwritten by wait.
return 0;
} }
else 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; NativeLwMutexWorkarea workarea;
Memory::ReadStruct(workareaPtr, &workarea); Memory::ReadStruct(workareaPtr, &workarea);
u32 error = 0;
if (workarea.uid == -1) if (workarea.uid == -1)
error = PSP_LWMUTEX_ERROR_NO_SUCH_LWMUTEX; return PSP_LWMUTEX_ERROR_NO_SUCH_LWMUTEX;
else if (count <= 0) 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) 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()) 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) else if (workarea.lockLevel < count)
error = PSP_LWMUTEX_ERROR_UNLOCK_UNDERFLOW; return PSP_LWMUTEX_ERROR_UNLOCK_UNDERFLOW;
if (error)
{
RETURN(error);
return;
}
workarea.lockLevel -= count; workarea.lockLevel -= count;
RETURN(0);
if (workarea.lockLevel == 0) if (workarea.lockLevel == 0)
{ {
u32 error;
if (__KernelUnlockLwMutex(workarea, error)) if (__KernelUnlockLwMutex(workarea, error))
__KernelReSchedule("lwmutex unlocked"); hleReSchedule("lwmutex unlocked");
Memory::WriteStruct(workareaPtr, &workarea); Memory::WriteStruct(workareaPtr, &workarea);
} }
else else
Memory::WriteStruct(workareaPtr, &workarea); Memory::WriteStruct(workareaPtr, &workarea);
return 0;
} }

View file

@ -17,20 +17,20 @@
#pragma once #pragma once
void sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optionsPtr); int sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optionsPtr);
void sceKernelDeleteMutex(SceUID id); int sceKernelDeleteMutex(SceUID id);
void sceKernelLockMutex(SceUID id, int count, u32 timeoutPtr); int sceKernelLockMutex(SceUID id, int count, u32 timeoutPtr);
void sceKernelLockMutexCB(SceUID id, int count, u32 timeoutPtr); int sceKernelLockMutexCB(SceUID id, int count, u32 timeoutPtr);
void sceKernelTryLockMutex(SceUID id, int count); int sceKernelTryLockMutex(SceUID id, int count);
void sceKernelUnlockMutex(SceUID id, int count); int sceKernelUnlockMutex(SceUID id, int count);
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);
void sceKernelDeleteLwMutex(u32 workareaPtr); int sceKernelDeleteLwMutex(u32 workareaPtr);
void sceKernelTryLockLwMutex(u32 workareaPtr, int count); int sceKernelTryLockLwMutex(u32 workareaPtr, int count);
void sceKernelTryLockLwMutex_600(u32 workareaPtr, int count); int sceKernelTryLockLwMutex_600(u32 workareaPtr, int count);
void sceKernelLockLwMutex(u32 workareaPtr, int count, u32 timeoutPtr); int sceKernelLockLwMutex(u32 workareaPtr, int count, u32 timeoutPtr);
void sceKernelLockLwMutexCB(u32 workareaPtr, int count, u32 timeoutPtr); int sceKernelLockLwMutexCB(u32 workareaPtr, int count, u32 timeoutPtr);
void sceKernelUnlockLwMutex(u32 workareaPtr, int count); int sceKernelUnlockLwMutex(u32 workareaPtr, int count);
void __KernelMutexTimeout(u64 userdata, int cyclesLate); void __KernelMutexTimeout(u64 userdata, int cyclesLate);
void __KernelLwMutexTimeout(u64 userdata, int cyclesLate); void __KernelLwMutexTimeout(u64 userdata, int cyclesLate);

View file

@ -70,59 +70,87 @@ void __KernelSemaInit()
semaInitComplete = true; 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.) // Resume all waiting threads (for delete / cancel.)
// Returns true if it woke any threads. // Returns true if it woke any threads.
bool __KernelClearSemaThreads(Semaphore *s, int reason) bool __KernelClearSemaThreads(Semaphore *s, int reason)
{ {
u32 error;
bool wokeThreads = false; bool wokeThreads = false;
std::vector<SceUID>::iterator iter, end;
// TODO: PSP_SEMA_ATTR_PRIORITY for (iter = s->waitingThreads.begin(), end = s->waitingThreads.end(); iter != end; ++iter)
std::vector<SceUID>::iterator iter; __KernelUnlockSemaForThread(s, *iter, error, reason, wokeThreads);
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;
}
s->waitingThreads.clear(); s->waitingThreads.clear();
return wokeThreads; return wokeThreads;
} }
// int sceKernelCancelSema(SceUID id, int newCount, int *numWaitThreads); std::vector<SceUID>::iterator __KernelSemaFindPriority(std::vector<SceUID> &waiting, std::vector<SceUID>::iterator begin)
// void because it changes threads.
void sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr)
{ {
DEBUG_LOG(HLE,"sceKernelCancelSema(%i)", id); _dbg_assert_msg_(HLE, !waiting.empty(), "__KernelSemaFindPriority: Trying to find best of no threads.");
std::vector<SceUID>::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; u32 error;
Semaphore *s = kernelObjects.Get<Semaphore>(id, error); Semaphore *s = kernelObjects.Get<Semaphore>(id, error);
if (s) if (s)
{ {
if (newCount > s->ns.maxCount) if (newCount > s->ns.maxCount)
{ return SCE_KERNEL_ERROR_ILLEGAL_COUNT;
RETURN(SCE_KERNEL_ERROR_ILLEGAL_COUNT);
return;
}
if (numWaitThreadsPtr) if (numWaitThreadsPtr)
{
Memory::Write_U32(s->ns.numWaitThreads, numWaitThreadsPtr); Memory::Write_U32(s->ns.numWaitThreads, numWaitThreadsPtr);
}
if (newCount < 0) if (newCount < 0)
s->ns.currentCount = s->ns.initCount; s->ns.currentCount = s->ns.initCount;
@ -130,31 +158,26 @@ void sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr)
s->ns.currentCount = newCount; s->ns.currentCount = newCount;
s->ns.numWaitThreads = 0; s->ns.numWaitThreads = 0;
// We need to set the return value BEFORE rescheduling threads.
RETURN(0);
if (__KernelClearSemaThreads(s, SCE_KERNEL_ERROR_WAIT_CANCEL)) if (__KernelClearSemaThreads(s, SCE_KERNEL_ERROR_WAIT_CANCEL))
__KernelReSchedule("semaphore canceled"); hleReSchedule("semaphore canceled");
return 0;
} }
else else
{ {
ERROR_LOG(HLE, "sceKernelCancelSema : Trying to cancel invalid semaphore %i", id); 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); //SceUID sceKernelCreateSema(const char *name, SceUInt attr, int initVal, int maxVal, SceKernelSemaOptParam *option);
// void because it changes threads. int sceKernelCreateSema(const char* name, u32 attr, int initVal, int maxVal, u32 optionPtr)
void sceKernelCreateSema(const char* name, u32 attr, int initVal, int maxVal, u32 optionPtr)
{ {
if (!semaInitComplete) if (!semaInitComplete)
__KernelSemaInit(); __KernelSemaInit();
if (!name) if (!name)
{ return SCE_KERNEL_ERROR_ERROR;
RETURN(SCE_KERNEL_ERROR_ERROR);
return;
}
Semaphore *s = new Semaphore; Semaphore *s = new Semaphore;
SceUID id = kernelObjects.Create(s); 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.maxCount = maxVal;
s->ns.numWaitThreads = 0; 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) 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); //int sceKernelDeleteSema(SceUID semaid);
// void because it changes threads. int sceKernelDeleteSema(SceUID id)
void sceKernelDeleteSema(SceUID id)
{ {
DEBUG_LOG(HLE,"sceKernelDeleteSema(%i)", id); DEBUG_LOG(HLE, "sceKernelDeleteSema(%i)", id);
u32 error; u32 error;
Semaphore *s = kernelObjects.Get<Semaphore>(id, error); Semaphore *s = kernelObjects.Get<Semaphore>(id, error);
if (s) if (s)
{ {
bool wokeThreads = __KernelClearSemaThreads(s, SCE_KERNEL_ERROR_WAIT_DELETE); bool wokeThreads = __KernelClearSemaThreads(s, SCE_KERNEL_ERROR_WAIT_DELETE);
RETURN(kernelObjects.Destroy<Semaphore>(id));
if (wokeThreads) if (wokeThreads)
__KernelReSchedule("semaphore deleted"); hleReSchedule("semaphore deleted");
return kernelObjects.Destroy<Semaphore>(id);
} }
else else
{ {
ERROR_LOG(HLE, "sceKernelDeleteSema : Trying to delete invalid semaphore %i", id); ERROR_LOG(HLE, "sceKernelDeleteSema : Trying to delete invalid semaphore %i", id);
RETURN(error); return error;
} }
} }
//int sceKernelDeleteSema(SceUID semaid, SceKernelSemaInfo *info); //int sceKernelDeleteSema(SceUID semaid, SceKernelSemaInfo *info);
// void because it changes threads. int sceKernelReferSemaStatus(SceUID id, u32 infoPtr)
void sceKernelReferSemaStatus(SceUID id, u32 infoPtr)
{ {
u32 error; u32 error;
Semaphore *s = kernelObjects.Get<Semaphore>(id, error); Semaphore *s = kernelObjects.Get<Semaphore>(id, error);
if (s) if (s)
{ {
DEBUG_LOG(HLE,"sceKernelReferSemaStatus(%i, %08x)", id, infoPtr); DEBUG_LOG(HLE, "sceKernelReferSemaStatus(%i, %08x)", id, infoPtr);
Memory::WriteStruct(infoPtr, &s->ns); Memory::WriteStruct(infoPtr, &s->ns);
RETURN(0); return 0;
} }
else else
{ {
ERROR_LOG(HLE,"Error %08x", error); ERROR_LOG(HLE, "sceKernelReferSemaStatus: error %08x", error);
RETURN(error); return error;
} }
} }
//int sceKernelSignalSema(SceUID semaid, int signal); //int sceKernelSignalSema(SceUID semaid, int signal);
// void because it changes threads. int sceKernelSignalSema(SceUID id, int signal)
void sceKernelSignalSema(SceUID id, int signal)
{ {
u32 error; u32 error;
Semaphore *s = kernelObjects.Get<Semaphore>(id, error); Semaphore *s = kernelObjects.Get<Semaphore>(id, error);
if (s) if (s)
{ {
if (s->ns.currentCount + signal - s->ns.numWaitThreads > s->ns.maxCount) if (s->ns.currentCount + signal - s->ns.numWaitThreads > s->ns.maxCount)
{ return SCE_KERNEL_ERROR_SEMA_OVF;
RETURN(SCE_KERNEL_ERROR_SEMA_OVF);
return;
}
int oldval = s->ns.currentCount; int oldval = s->ns.currentCount;
s->ns.currentCount += signal; 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; bool wokeThreads = false;
std::vector<SceUID>::iterator iter; std::vector<SceUID>::iterator iter, end, best;
retry: 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; if ((s->ns.attr & PSP_SEMA_ATTR_PRIORITY) != 0)
SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_SEMA, error); best = __KernelSemaFindPriority(s->waitingThreads, iter);
// The waitID may be different after a timeout. else
if (waitID != s->GetUID()) best = iter;
if (__KernelUnlockSemaForThread(s, *best, error, 0, wokeThreads))
{ {
s->waitingThreads.erase(iter); s->waitingThreads.erase(best);
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;
goto retry; goto retry;
} }
} }
if (wokeThreads) if (wokeThreads)
__KernelReSchedule("semaphore signaled"); hleReSchedule("semaphore signaled");
return 0;
} }
else else
{ {
ERROR_LOG(HLE, "sceKernelSignalSema : Trying to signal invalid semaphore %i", id); 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()); 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; u32 error;
Semaphore *s = kernelObjects.Get<Semaphore>(id, error); Semaphore *s = kernelObjects.Get<Semaphore>(id, error);
if (s) if (s)
{ {
if (wantedCount > s->ns.maxCount || wantedCount <= 0) if (wantedCount > s->ns.maxCount || wantedCount <= 0)
{ return SCE_KERNEL_ERROR_ILLEGAL_COUNT;
RETURN(SCE_KERNEL_ERROR_ILLEGAL_COUNT);
return;
}
// We need to set the return value BEFORE processing callbacks / etc.
RETURN(0);
if (s->ns.currentCount >= wantedCount) if (s->ns.currentCount >= wantedCount)
{
s->ns.currentCount -= wantedCount; s->ns.currentCount -= wantedCount;
if (processCallbacks)
hleCheckCurrentCallbacks();
}
else else
{ {
s->ns.numWaitThreads++; s->ns.numWaitThreads++;
s->waitingThreads.push_back(__KernelGetCurThread()); s->waitingThreads.push_back(__KernelGetCurThread());
__KernelSetSemaTimeout(s, timeoutPtr); __KernelSetSemaTimeout(s, timeoutPtr);
__KernelWaitCurThread(WAITTYPE_SEMA, id, wantedCount, timeoutPtr, processCallbacks); __KernelWaitCurThread(WAITTYPE_SEMA, id, wantedCount, timeoutPtr, processCallbacks);
if (processCallbacks)
__KernelCheckCallbacks();
} }
return 0;
} }
else else
{ {
ERROR_LOG(HLE, badSemaMessage, id); ERROR_LOG(HLE, badSemaMessage, id);
RETURN(error); return error;
} }
} }
//int sceKernelWaitSema(SceUID semaid, int signal, SceUInt *timeout); //int sceKernelWaitSema(SceUID semaid, int signal, SceUInt *timeout);
// void because it changes threads. int sceKernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr)
void 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); //int sceKernelWaitSemaCB(SceUID semaid, int signal, SceUInt *timeout);
// void because it changes threads. int sceKernelWaitSemaCB(SceUID id, int wantedCount, u32 timeoutPtr)
void 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 // 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) if (wantedCount <= 0)
{ return SCE_KERNEL_ERROR_ILLEGAL_COUNT;
RETURN(SCE_KERNEL_ERROR_ILLEGAL_COUNT);
return;
}
u32 error; u32 error;
Semaphore *s = kernelObjects.Get<Semaphore>(id, error); Semaphore *s = kernelObjects.Get<Semaphore>(id, error);
@ -393,15 +382,15 @@ void sceKernelPollSema(SceUID id, int wantedCount)
if (s->ns.currentCount >= wantedCount) if (s->ns.currentCount >= wantedCount)
{ {
s->ns.currentCount -= wantedCount; s->ns.currentCount -= wantedCount;
RETURN(0); return 0;
} }
else else
RETURN(SCE_KERNEL_ERROR_SEMA_ZERO); return SCE_KERNEL_ERROR_SEMA_ZERO;
} }
else else
{ {
ERROR_LOG(HLE, "sceKernelPollSema: Trying to poll invalid semaphore %i", id); ERROR_LOG(HLE, "sceKernelPollSema: Trying to poll invalid semaphore %i", id);
RETURN(error); return error;
} }
} }

View file

@ -17,13 +17,13 @@
#pragma once #pragma once
void sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr); int sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr);
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);
void sceKernelDeleteSema(SceUID id); int sceKernelDeleteSema(SceUID id);
void sceKernelPollSema(SceUID id, int wantedCount); int sceKernelPollSema(SceUID id, int wantedCount);
void sceKernelReferSemaStatus(SceUID id, u32 infoPtr); int sceKernelReferSemaStatus(SceUID id, u32 infoPtr);
void sceKernelSignalSema(SceUID id, int signal); int sceKernelSignalSema(SceUID id, int signal);
void sceKernelWaitSema(SceUID semaid, int signal, u32 timeoutPtr); int sceKernelWaitSema(SceUID semaid, int signal, u32 timeoutPtr);
void sceKernelWaitSemaCB(SceUID semaid, int signal, u32 timeoutPtr); int sceKernelWaitSemaCB(SceUID semaid, int signal, u32 timeoutPtr);
void __KernelSemaTimeout(u64 userdata, int cycleslate); void __KernelSemaTimeout(u64 userdata, int cycleslate);

View file

@ -256,6 +256,7 @@ public:
SceUID moduleId; SceUID moduleId;
bool isProcessingCallbacks; bool isProcessingCallbacks;
u32 currentCallbackId;
ThreadContext context; ThreadContext context;
@ -267,7 +268,7 @@ public:
u32 stackBlock; u32 stackBlock;
}; };
void __KernelExecuteMipsCallOnCurrentThread(int callId); void __KernelExecuteMipsCallOnCurrentThread(int callId, bool reschedAfter);
int g_inCbCount = 0; int g_inCbCount = 0;
@ -396,7 +397,7 @@ void __KernelIdle()
// In Advance, we might trigger an interrupt such as vblank. // In Advance, we might trigger an interrupt such as vblank.
// If we end up in an interrupt, we don't want to reschedule. // If we end up in an interrupt, we don't want to reschedule.
// However, we have to reschedule... damn. // However, we have to reschedule... damn.
__KernelReSchedule("idle"); hleReSchedule("idle");
} }
void __KernelThreadingShutdown() void __KernelThreadingShutdown()
@ -617,10 +618,9 @@ u32 __KernelResumeThreadFromWait(SceUID threadID, int retval)
} }
} }
// DANGEROUS
// Only run when you can safely accept a context switch // 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 // 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 __KernelTriggerWait(WaitType type, int id, bool useRetVal, int retVal, bool dontSwitch)
{ {
bool doneAnything = false; bool doneAnything = false;
@ -648,7 +648,7 @@ bool __KernelTriggerWait(WaitType type, int id, bool useRetVal, int retVal, bool
// TODO: time waster // TODO: time waster
char temp[256]; char temp[256];
sprintf(temp, "resumed from wait %s", waitTypeStrings[(int)type]); sprintf(temp, "resumed from wait %s", waitTypeStrings[(int)type]);
__KernelReSchedule(temp); hleReSchedule(temp);
} }
} }
return true; return true;
@ -680,7 +680,7 @@ void __KernelWaitCurThread(WaitType type, SceUID waitID, u32 waitValue, u32 time
char temp[256]; char temp[256];
sprintf(temp, "started wait %s", waitTypeStrings[(int)type]); sprintf(temp, "started wait %s", waitTypeStrings[(int)type]);
__KernelReSchedule(processCallbacks, temp); hleReSchedule(processCallbacks, temp);
// TODO: Remove thread from Ready queue? // TODO: Remove thread from Ready queue?
} }
@ -753,20 +753,27 @@ Thread *__KernelNextThread() {
void __KernelReSchedule(const char *reason) void __KernelReSchedule(const char *reason)
{ {
// cancel rescheduling when in interrupt or callback, otherwise everything will be fucked up // cancel rescheduling when in interrupt or callback, otherwise everything will be fucked up
if (__IsInInterrupt() || __KernelInCallback()) if (__IsInInterrupt() || __KernelInCallback())
{ {
reason = "In Interrupt Or Callback"; reason = "In Interrupt Or Callback";
return; return;
} }
// Execute any pending events while we're doing scheduling. // This may get us running a callback, don't reschedule out of it.
CoreTiming::Advance(); if (__KernelCheckCallbacks())
if (__IsInInterrupt() || __KernelInCallback()) {
{ reason = "Began interrupt or callback.";
reason = "In Interrupt Or Callback"; return;
return; }
}
// Execute any pending events while we're doing scheduling.
CoreTiming::Advance();
if (__IsInInterrupt() || __KernelInCallback())
{
reason = "In Interrupt Or Callback";
return;
}
retry: retry:
Thread *nextThread = __KernelNextThread(); Thread *nextThread = __KernelNextThread();
@ -792,7 +799,6 @@ void __KernelReSchedule(bool doCallbacks, const char *reason)
{ {
if (thread) if (thread)
thread->isProcessingCallbacks = doCallbacks; thread->isProcessingCallbacks = doCallbacks;
__KernelCheckCallbacks();
} }
__KernelReSchedule(reason); __KernelReSchedule(reason);
if (doCallbacks && thread == currentThread) { 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; SceUID id;
__KernelCreateThread(id, curModule, threadName, entry, prio, stacksize, attr); __KernelCreateThread(id, curModule, threadName, entry, prio, stacksize, attr);
INFO_LOG(HLE,"%i = sceKernelCreateThread(name=\"%s\", entry= %08x, stacksize=%i )", id, threadName, entry, stacksize); INFO_LOG(HLE, "%i = sceKernelCreateThread(name=\"%s\", entry=%08x, prio=%x, stacksize=%i)", id, threadName, entry, prio, stacksize);
RETURN(id); if (optionAddr != 0)
WARN_LOG(HLE, "sceKernelCreateThread: unsupported options parameter.", threadName);
return id;
} }
// int sceKernelStartThread(SceUID threadToStartID, SceSize argSize, void *argBlock) // int sceKernelStartThread(SceUID threadToStartID, SceSize argSize, void *argBlock)
// void because it reschedules. int sceKernelStartThread(SceUID threadToStartID, u32 argSize, u32 argBlockPtr)
void sceKernelStartThread(SceUID threadToStartID, u32 argSize, u32 argBlockPtr)
{ {
if (threadToStartID != currentThread->GetUID()) 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_LOG(HLE,"%08x=sceKernelStartThread(thread=%i, argSize=%i, argPtr= %08x): thread does not exist!",
error,threadToStartID,argSize,argBlockPtr) error,threadToStartID,argSize,argBlockPtr)
RETURN(error); return error;
return;
} }
if (startThread->nt.status != THREADSTATUS_DORMANT) if (startThread->nt.status != THREADSTATUS_DORMANT)
{ {
printf("NOT DORMANT\n");
//Not dormant, WTF? //Not dormant, WTF?
RETURN(ERROR_KERNEL_THREAD_IS_NOT_DORMANT); return ERROR_KERNEL_THREAD_IS_NOT_DORMANT;
return;
} }
INFO_LOG(HLE,"sceKernelStartThread(thread=%i, argSize=%i, argPtr= %08x )", INFO_LOG(HLE,"sceKernelStartThread(thread=%i, argSize=%i, argPtr= %08x )",
@ -990,14 +986,14 @@ printf("NOT DORMANT\n");
if (!argBlockPtr && argSize > 0) { if (!argBlockPtr && argSize > 0) {
WARN_LOG(HLE,"sceKernelStartThread : had NULL arg"); WARN_LOG(HLE,"sceKernelStartThread : had NULL arg");
} }
RETURN(0);
__KernelReSchedule("thread started"); hleReSchedule("thread started");
return 0;
} }
else else
{ {
ERROR_LOG(HLE,"thread %i trying to start itself", threadToStartID); 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 // Find threads that waited for me
// Wake them // Wake them
if (!__KernelTriggerWait(WAITTYPE_THREADEND, __KernelGetCurThread())) if (!__KernelTriggerWait(WAITTYPE_THREADEND, __KernelGetCurThread()))
__KernelReSchedule("return from thread"); hleReSchedule("return from thread");
// The stack will be deallocated when the thread is deleted. // The stack will be deallocated when the thread is deleted.
} }
@ -1067,7 +1063,7 @@ void sceKernelExitThread()
//Find threads that waited for me //Find threads that waited for me
// Wake them // Wake them
if (!__KernelTriggerWait(WAITTYPE_THREADEND, __KernelGetCurThread())) if (!__KernelTriggerWait(WAITTYPE_THREADEND, __KernelGetCurThread()))
__KernelReSchedule("exited thread"); hleReSchedule("exited thread");
// The stack will be deallocated when the thread is deleted. // The stack will be deallocated when the thread is deleted.
} }
@ -1082,7 +1078,7 @@ void _sceKernelExitThread()
//Find threads that waited for this one //Find threads that waited for this one
// Wake them // Wake them
if (!__KernelTriggerWait(WAITTYPE_THREADEND, __KernelGetCurThread())) if (!__KernelTriggerWait(WAITTYPE_THREADEND, __KernelGetCurThread()))
__KernelReSchedule("exit-deleted thread"); hleReSchedule("exit-deleted thread");
// The stack will be deallocated when the thread is deleted. // The stack will be deallocated when the thread is deleted.
} }
@ -1134,66 +1130,63 @@ u32 sceKernelResumeDispatchThread(u32 suspended)
void sceKernelRotateThreadReadyQueue() void sceKernelRotateThreadReadyQueue()
{ {
DEBUG_LOG(HLE,"sceKernelRotateThreadReadyQueue : rescheduling"); DEBUG_LOG(HLE,"sceKernelRotateThreadReadyQueue : rescheduling");
__KernelReSchedule("rotatethreadreadyqueue"); hleReSchedule("rotatethreadreadyqueue");
} }
void sceKernelDeleteThread() int sceKernelDeleteThread(int threadHandle)
{ {
int threadHandle = PARAM(0);
if (threadHandle != currentThread->GetUID()) if (threadHandle != currentThread->GetUID())
{ {
//TODO: remove from threadqueue! //TODO: remove from threadqueue!
DEBUG_LOG(HLE,"sceKernelDeleteThread(%i)",threadHandle); DEBUG_LOG(HLE,"sceKernelDeleteThread(%i)",threadHandle);
u32 error; u32 error;
Thread *t = kernelObjects.Get<Thread>(threadHandle, error); Thread *t = kernelObjects.Get<Thread>(threadHandle, error);
if (t) if (t)
{ {
__KernelRemoveFromThreadQueue(t); __KernelRemoveFromThreadQueue(t);
__KernelFireThreadEnd(t); __KernelFireThreadEnd(t);
RETURN(kernelObjects.Destroy<Thread>(threadHandle)); __KernelTriggerWait(WAITTYPE_THREADEND, threadHandle);
__KernelTriggerWait(WAITTYPE_THREADEND, threadHandle); //TODO: should we really reschedule here?
//if (!__KernelTriggerWait(WAITTYPE_THREADEND, threadHandle))
//TODO: should we really reschedule here? // hleReSchedule("thread deleted");
//if (!__KernelTriggerWait(WAITTYPE_THREADEND, threadHandle)) return kernelObjects.Destroy<Thread>(threadHandle);
// __KernelReSchedule("thread deleted"); }
}
} }
else else
{ {
ERROR_LOG(HLE, "Thread \"%s\" tries to delete itself! :(",currentThread->GetName()); 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()) if (threadno != currentThread->GetUID())
{ {
//TODO: remove from threadqueue! //TODO: remove from threadqueue!
INFO_LOG(HLE, "sceKernelTerminateDeleteThread(%i)", threadno); INFO_LOG(HLE, "sceKernelTerminateDeleteThread(%i)", threadno);
RETURN(0); //kernelObjects.Destroy<Thread>(threadno));
//TODO: should we really reschedule here? //TODO: should we really reschedule here?
if (!__KernelTriggerWait(WAITTYPE_THREADEND, threadno)) if (!__KernelTriggerWait(WAITTYPE_THREADEND, threadno))
__KernelReSchedule("termdeletethread"); hleReSchedule("termdeletethread");
return 0; //kernelObjects.Destroy<Thread>(threadno));
} }
else else
{ {
ERROR_LOG(HLE, "Thread \"%s\" trying to delete itself! :(", currentThread->GetName()); 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()) if (threadID != currentThread->GetUID())
{ {
INFO_LOG(HLE, "sceKernelTerminateThread(%i)", threadID); INFO_LOG(HLE, "sceKernelTerminateThread(%i)", threadID);
RETURN(0);
u32 error; u32 error;
Thread *t = kernelObjects.Get<Thread>(threadID, error); Thread *t = kernelObjects.Get<Thread>(threadID, error);
@ -1204,11 +1197,12 @@ void sceKernelTerminateThread(u32 threadID)
__KernelTriggerWait(WAITTYPE_THREADEND, threadID); __KernelTriggerWait(WAITTYPE_THREADEND, threadID);
} }
// TODO: Return an error if it doesn't exist? // TODO: Return an error if it doesn't exist?
return 0;
} }
else else
{ {
ERROR_LOG(HLE, "Thread \"%s\" trying to delete itself! :(", currentThread->GetName()); ERROR_LOG(HLE, "Thread \"%s\" trying to delete itself! :(", currentThread->GetName());
RETURN(-1); return -1;
} }
} }
@ -1275,8 +1269,6 @@ void sceKernelDelayThreadCB()
SceUID curThread = __KernelGetCurThread(); SceUID curThread = __KernelGetCurThread();
__KernelScheduleWakeup(curThread, usec); __KernelScheduleWakeup(curThread, usec);
__KernelWaitCurThread(WAITTYPE_DELAY, curThread, 0, 0, true); __KernelWaitCurThread(WAITTYPE_DELAY, curThread, 0, 0, true);
if (__KernelCheckCallbacks())
__KernelExecutePendingMipsCalls();
} }
void sceKernelDelayThread() void sceKernelDelayThread()
@ -1363,7 +1355,6 @@ void sceKernelSleepThreadCB()
DEBUG_LOG(HLE, "sceKernelSleepThreadCB()"); DEBUG_LOG(HLE, "sceKernelSleepThreadCB()");
__KernelSleepThread(true); __KernelSleepThread(true);
__KernelCheckCallbacks(); __KernelCheckCallbacks();
__KernelExecutePendingMipsCalls();
} }
void sceKernelWaitThreadEnd() void sceKernelWaitThreadEnd()
@ -1479,7 +1470,7 @@ void sceKernelNotifyCallback()
u32 arg = PARAM(1); u32 arg = PARAM(1);
DEBUG_LOG(HLE,"sceKernelNotifyCallback(%i, %i)", cbId, arg); 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); RETURN(0);
} }
@ -1593,7 +1584,7 @@ void Thread::setReturnValue(u32 retval)
{ {
if (this == currentThread) { if (this == currentThread) {
if (g_inCbCount) { if (g_inCbCount) {
int callId = currentMIPS->r[MIPS_REG_CALL_ID]; int callId = this->currentCallbackId;
MipsCall *call = mipsCalls.get(callId); MipsCall *call = mipsCalls.get(callId);
if (call) { if (call) {
call->savedV0 = retval; call->savedV0 = retval;
@ -1623,7 +1614,7 @@ void __KernelSwitchContext(Thread *target, const char *reason)
currentThread->nt.waitType = WAITTYPE_NONE; currentThread->nt.waitType = WAITTYPE_NONE;
currentThread->nt.waitID = 0; currentThread->nt.waitID = 0;
__KernelExecutePendingMipsCalls(); __KernelExecutePendingMipsCalls(true);
} }
void __KernelChangeThreadState(Thread *thread, ThreadStatus newStatus) { void __KernelChangeThreadState(Thread *thread, ThreadStatus newStatus) {
@ -1654,7 +1645,8 @@ bool __CanExecuteCallbackNow(Thread *thread) {
return g_inCbCount == 0; return g_inCbCount == 0;
} }
void __KernelCallAddress(Thread *thread, u32 entryPoint, Action *afterAction, bool returnVoid, std::vector<int> args) { void __KernelCallAddress(Thread *thread, u32 entryPoint, Action *afterAction, bool returnVoid, std::vector<int> args, bool reschedAfter)
{
if (thread) { if (thread) {
ActionAfterMipsCall *after = new ActionAfterMipsCall(); ActionAfterMipsCall *after = new ActionAfterMipsCall();
after->chainedAction = afterAction; after->chainedAction = afterAction;
@ -1663,6 +1655,7 @@ void __KernelCallAddress(Thread *thread, u32 entryPoint, Action *afterAction, bo
after->waitType = thread->nt.waitType; after->waitType = thread->nt.waitType;
after->waitId = thread->nt.waitID; after->waitId = thread->nt.waitID;
after->waitInfo = thread->waitInfo; after->waitInfo = thread->waitInfo;
after->isProcessingCallbacks = thread->isProcessingCallbacks;
afterAction = after; afterAction = after;
@ -1688,7 +1681,7 @@ void __KernelCallAddress(Thread *thread, u32 entryPoint, Action *afterAction, bo
if (__CanExecuteCallbackNow(thread)) { if (__CanExecuteCallbackNow(thread)) {
thread = currentThread; thread = currentThread;
__KernelChangeThreadState(thread, THREADSTATUS_RUNNING); __KernelChangeThreadState(thread, THREADSTATUS_RUNNING);
__KernelExecuteMipsCallOnCurrentThread(callId); __KernelExecuteMipsCallOnCurrentThread(callId, reschedAfter);
called = true; 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) { if (g_inCbCount > 0) {
WARN_LOG(HLE, "__KernelExecuteMipsCallOnCurrentThread: Already in a callback!"); WARN_LOG(HLE, "__KernelExecuteMipsCallOnCurrentThread: Already in a callback!");
@ -1713,12 +1706,17 @@ void __KernelExecuteMipsCallOnCurrentThread(int callId)
call->savedV0 = currentMIPS->r[MIPS_REG_V0]; call->savedV0 = currentMIPS->r[MIPS_REG_V0];
call->savedV1 = currentMIPS->r[MIPS_REG_V1]; call->savedV1 = currentMIPS->r[MIPS_REG_V1];
call->savedIdRegister = currentMIPS->r[MIPS_REG_CALL_ID]; call->savedIdRegister = currentMIPS->r[MIPS_REG_CALL_ID];
call->savedId = currentThread->currentCallbackId;
call->returnVoid = false; call->returnVoid = false;
call->reschedAfter = reschedAfter;
// Set up the new state // Set up the new state
currentMIPS->pc = call->entryPoint; currentMIPS->pc = call->entryPoint;
currentMIPS->r[MIPS_REG_RA] = __KernelMipsCallReturnAddress(); 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; currentMIPS->r[MIPS_REG_CALL_ID] = callId;
currentThread->currentCallbackId = callId;
for (int i = 0; i < call->numArgs; i++) { for (int i = 0; i < call->numArgs; i++) {
currentMIPS->r[MIPS_REG_A0 + i] = call->args[i]; currentMIPS->r[MIPS_REG_A0 + i] = call->args[i];
} }
@ -1728,7 +1726,9 @@ void __KernelExecuteMipsCallOnCurrentThread(int callId)
void __KernelReturnFromMipsCall() 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); MipsCall *call = mipsCalls.pop(callId);
@ -1745,19 +1745,20 @@ void __KernelReturnFromMipsCall()
currentMIPS->r[MIPS_REG_V0] = call->savedV0; currentMIPS->r[MIPS_REG_V0] = call->savedV0;
currentMIPS->r[MIPS_REG_V1] = call->savedV1; currentMIPS->r[MIPS_REG_V1] = call->savedV1;
currentMIPS->r[MIPS_REG_CALL_ID] = call->savedIdRegister; currentMIPS->r[MIPS_REG_CALL_ID] = call->savedIdRegister;
currentThread->currentCallbackId = call->savedId;
g_inCbCount--; g_inCbCount--;
// yeah! back in the real world, let's keep going. Should we process more callbacks? // yeah! back in the real world, let's keep going. Should we process more callbacks?
__KernelCheckCallbacks(); if (!__KernelExecutePendingMipsCalls(call->reschedAfter))
if (!__KernelExecutePendingMipsCalls())
{ {
// We should definitely reschedule as we might still be asleep. - except if we came from checkcallbacks? // Sometimes, we want to stay on the thread.
__KernelReSchedule("return from callback"); if (call->reschedAfter)
hleReSchedule("return from callback");
} }
} }
bool __KernelExecutePendingMipsCalls() bool __KernelExecutePendingMipsCalls(bool reschedAfter)
{ {
Thread *thread = __GetCurrentThread(); Thread *thread = __GetCurrentThread();
@ -1771,7 +1772,7 @@ bool __KernelExecutePendingMipsCalls()
// Pop off the first pending mips call // Pop off the first pending mips call
int callId = thread->pendingMipsCalls.front(); int callId = thread->pendingMipsCalls.front();
thread->pendingMipsCalls.pop_front(); thread->pendingMipsCalls.pop_front();
__KernelExecuteMipsCallOnCurrentThread(callId); __KernelExecuteMipsCallOnCurrentThread(callId, reschedAfter);
return true; return true;
} }
return false; return false;
@ -1787,7 +1788,7 @@ public:
}; };
// Executes the callback, when it next is context switched to. // 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; u32 error;
Callback *cb = kernelObjects.Get<Callback>(cbId, error); Callback *cb = kernelObjects.Get<Callback>(cbId, error);
@ -1811,7 +1812,7 @@ void __KernelRunCallbackOnThread(SceUID cbId, Thread *thread)
cb->nc.notifyArg = 0; cb->nc.notifyArg = 0;
Action *action = new ActionAfterCallback(cbId); 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() { void ActionAfterCallback::run() {
@ -1833,15 +1834,16 @@ void ActionAfterCallback::run() {
// Check callbacks on the current thread only. // Check callbacks on the current thread only.
// Returns true if any callbacks were processed on the current thread. // Returns true if any callbacks were processed on the current thread.
bool __KernelCheckThreadCallbacks(Thread *thread) { bool __KernelCheckThreadCallbacks(Thread *thread, bool force)
if (!thread->isProcessingCallbacks) {
if (!thread->isProcessingCallbacks && !force)
return false; return false;
for (int i = 0; i < THREAD_CALLBACK_NUM_TYPES; i++) { for (int i = 0; i < THREAD_CALLBACK_NUM_TYPES; i++) {
if (thread->readyCallbacks[i].size()) { if (thread->readyCallbacks[i].size()) {
SceUID readyCallback = thread->readyCallbacks[i].front(); SceUID readyCallback = thread->readyCallbacks[i].front();
thread->readyCallbacks[i].pop_front(); thread->readyCallbacks[i].pop_front();
__KernelRunCallbackOnThread(readyCallback, thread); // makes pending __KernelRunCallbackOnThread(readyCallback, thread, !force); // makes pending
return true; return true;
} }
} }
@ -1857,11 +1859,14 @@ bool __KernelCheckCallbacks() {
for (std::vector<Thread *>::iterator iter = threadqueue.begin(); iter != threadqueue.end(); iter++) { for (std::vector<Thread *>::iterator iter = threadqueue.begin(); iter != threadqueue.end(); iter++) {
Thread *thread = *iter; Thread *thread = *iter;
if (thread->isProcessingCallbacks && __KernelCheckThreadCallbacks(thread)) { if (__KernelCheckThreadCallbacks(thread, false)) {
processed = true; processed = true;
} }
} }
// } while (processed && currentThread == __KernelGetCurThread()); // } while (processed && currentThread == __KernelGetCurThread());
if (processed)
return __KernelExecutePendingMipsCalls(true);
return processed; return processed;
} }
@ -1869,30 +1874,24 @@ bool __KernelForceCallbacks()
{ {
Thread *curThread = __GetCurrentThread(); Thread *curThread = __GetCurrentThread();
// This thread can now process callbacks. bool callbacksProcessed = __KernelCheckThreadCallbacks(curThread, true);
curThread->isProcessingCallbacks = true; if (callbacksProcessed)
__KernelExecutePendingMipsCalls(false);
bool callbacksProcessed = __KernelCheckThreadCallbacks(curThread);
// Note - same thread as above - checking callbacks may switch threads.
curThread->isProcessingCallbacks = false;
return callbacksProcessed; return callbacksProcessed;
} }
void sceKernelCheckCallback() { void sceKernelCheckCallback()
Thread *curThread = __GetCurrentThread(); {
// Start with yes.
RETURN(1);
bool callbacksProcessed = __KernelForceCallbacks(); bool callbacksProcessed = __KernelForceCallbacks();
if (callbacksProcessed) { if (callbacksProcessed) {
curThread->setReturnValue(1);
ERROR_LOG(HLE,"sceKernelCheckCallback() - processed a callback."); ERROR_LOG(HLE,"sceKernelCheckCallback() - processed a callback.");
__KernelExecutePendingMipsCalls();
} else { } else {
RETURN(0); 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; u32 error;
@ -1937,7 +1936,7 @@ void __KernelNotifyCallback(RegisteredCallbackType type, SceUID threadId, SceUID
cb->nc.notifyCount++; cb->nc.notifyCount++;
cb->nc.notifyArg = notifyArg; cb->nc.notifyArg = notifyArg;
Thread *t = kernelObjects.Get<Thread>(threadId, error); Thread *t = kernelObjects.Get<Thread>(cb->nc.threadId, error);
t->readyCallbacks[type].remove(cbId); t->readyCallbacks[type].remove(cbId);
t->readyCallbacks[type].push_back(cbId); t->readyCallbacks[type].push_back(cbId);
} }
@ -1949,7 +1948,7 @@ u32 __KernelNotifyCallbackType(RegisteredCallbackType type, SceUID cbId, int not
Thread *t = *iter; Thread *t = *iter;
for (std::set<SceUID>::iterator citer = t->registeredCallbacks[type].begin(); citer != t->registeredCallbacks[type].end(); citer++) { for (std::set<SceUID>::iterator citer = t->registeredCallbacks[type].begin(); citer != t->registeredCallbacks[type].end(); citer++) {
if (cbId == -1 || cbId == *citer) { if (cbId == -1 || cbId == *citer) {
__KernelNotifyCallback(type, t->GetUID(), *citer, notifyArg); __KernelNotifyCallback(type, *citer, notifyArg);
} }
} }
} }

View file

@ -26,16 +26,16 @@
void sceKernelChangeThreadPriority(); void sceKernelChangeThreadPriority();
void sceKernelCreateThread(); int sceKernelCreateThread(const char *threadName, u32 entry, u32 prio, int stacksize, u32 attr, u32 optionAddr);
void sceKernelDelayThread(); void sceKernelDelayThread();
void sceKernelDelayThreadCB(); void sceKernelDelayThreadCB();
void sceKernelDeleteThread(); int sceKernelDeleteThread(int threadHandle);
void sceKernelExitDeleteThread(); void sceKernelExitDeleteThread();
void sceKernelExitThread(); void sceKernelExitThread();
void _sceKernelExitThread(); void _sceKernelExitThread();
void sceKernelGetThreadId(); void sceKernelGetThreadId();
void sceKernelGetThreadCurrentPriority(); void sceKernelGetThreadCurrentPriority();
void sceKernelStartThread(SceUID threadToStartID, u32 argSize, u32 argBlockPtr); int sceKernelStartThread(SceUID threadToStartID, u32 argSize, u32 argBlockPtr);
u32 sceKernelSuspendDispatchThread(); u32 sceKernelSuspendDispatchThread();
u32 sceKernelResumeDispatchThread(u32 suspended); u32 sceKernelResumeDispatchThread(u32 suspended);
void sceKernelWaitThreadEnd(); void sceKernelWaitThreadEnd();
@ -47,8 +47,8 @@ void sceKernelSuspendThread();
void sceKernelResumeThread(); void sceKernelResumeThread();
void sceKernelWakeupThread(); void sceKernelWakeupThread();
void sceKernelCancelWakeupThread(); void sceKernelCancelWakeupThread();
void sceKernelTerminateDeleteThread(); int sceKernelTerminateDeleteThread(int threadno);
void sceKernelTerminateThread(u32 threadID); int sceKernelTerminateThread(u32 threadID);
void sceKernelWaitThreadEndCB(); void sceKernelWaitThreadEndCB();
void sceKernelGetThreadExitStatus(); void sceKernelGetThreadExitStatus();
void sceKernelGetThreadmanIdType(); void sceKernelGetThreadmanIdType();
@ -169,8 +169,8 @@ bool __KernelCheckCallbacks();
bool __KernelForceCallbacks(); bool __KernelForceCallbacks();
class Thread; class Thread;
void __KernelSwitchContext(Thread *target, const char *reason); void __KernelSwitchContext(Thread *target, const char *reason);
bool __KernelExecutePendingMipsCalls(); bool __KernelExecutePendingMipsCalls(bool reschedAfter);
void __KernelNotifyCallback(RegisteredCallbackType type, SceUID threadId, SceUID cbId, int notifyArg); void __KernelNotifyCallback(RegisteredCallbackType type, SceUID cbId, int notifyArg);
// A call into game code. These can be pending on a thread. // A call into game code. These can be pending on a thread.
// Similar to Callback-s (NOT CallbackInfos) in JPCSP. // Similar to Callback-s (NOT CallbackInfos) in JPCSP.
@ -188,6 +188,8 @@ struct MipsCall {
u32 savedV1; u32 savedV1;
bool returnVoid; bool returnVoid;
const char *tag; const char *tag;
u32 savedId;
bool reschedAfter;
}; };
enum ThreadStatus enum ThreadStatus
{ {

View file

@ -34,133 +34,102 @@ void __PowerInit() {
memset(powerCbSlots, 0, sizeof(powerCbSlots)); memset(powerCbSlots, 0, sizeof(powerCbSlots));
} }
int scePowerGetBatteryLifePercent() int scePowerGetBatteryLifePercent() {
{
DEBUG_LOG(HLE, "100=scePowerGetBatteryLifePercent"); DEBUG_LOG(HLE, "100=scePowerGetBatteryLifePercent");
return 100; return 100;
} }
int scePowerIsPowerOnline() int scePowerIsPowerOnline() {
{
DEBUG_LOG(HLE, "1=scePowerIsPowerOnline"); DEBUG_LOG(HLE, "1=scePowerIsPowerOnline");
return 1; return 1;
} }
int scePowerIsBatteryExist() int scePowerIsBatteryExist() {
{
DEBUG_LOG(HLE, "1=scePowerIsBatteryExist"); DEBUG_LOG(HLE, "1=scePowerIsBatteryExist");
return 1; return 1;
} }
int scePowerIsBatteryCharging() int scePowerIsBatteryCharging() {
{
DEBUG_LOG(HLE, "0=scePowerIsBatteryCharging"); DEBUG_LOG(HLE, "0=scePowerIsBatteryCharging");
return 0; return 0;
} }
int scePowerGetBatteryChargingStatus() int scePowerGetBatteryChargingStatus() {
{
DEBUG_LOG(HLE, "0=scePowerGetBatteryChargingStatus"); DEBUG_LOG(HLE, "0=scePowerGetBatteryChargingStatus");
return 0; return 0;
} }
int scePowerIsLowBattery() int scePowerIsLowBattery() {
{
DEBUG_LOG(HLE, "0=scePowerIsLowBattery"); DEBUG_LOG(HLE, "0=scePowerIsLowBattery");
return 0; return 0;
} }
int scePowerRegisterCallback(int slot, int cbId) int scePowerRegisterCallback(int slot, int cbId) {
{
DEBUG_LOG(HLE,"0=scePowerRegisterCallback(%i, %i)", slot, cbId); DEBUG_LOG(HLE,"0=scePowerRegisterCallback(%i, %i)", slot, cbId);
int foundSlot = -1; int foundSlot = -1;
if (slot == POWER_CB_AUTO) // -1 signifies auto select of bank if (slot == POWER_CB_AUTO) { // -1 signifies auto select of bank
{ for (int i=0; i < numberOfCBPowerSlots; i++) {
for(int i=0; i < numberOfCBPowerSlots; i++) if ((powerCbSlots[i]==0) && (foundSlot == POWER_CB_AUTO)) { // found an empty slot
{
if ((powerCbSlots[i]==0) && (foundSlot == POWER_CB_AUTO)) // found an empty slot
{
powerCbSlots[i] = cbId; powerCbSlots[i] = cbId;
foundSlot = i; foundSlot = i;
} }
} }
} } else {
else if (powerCbSlots[slot] == 0) {
{
if (powerCbSlots[slot] == 0)
{
powerCbSlots[slot] = cbId; powerCbSlots[slot] = cbId;
foundSlot = 0; foundSlot = 0;
} } else {
else
{
// slot already in use! // slot already in use!
foundSlot = POWER_CB_AUTO; foundSlot = POWER_CB_AUTO;
} }
} }
if (foundSlot>=0) if (foundSlot>=0) {
{
__KernelRegisterCallback(THREAD_CALLBACK_POWER, cbId); __KernelRegisterCallback(THREAD_CALLBACK_POWER, cbId);
__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
// 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
} }
return foundSlot; return foundSlot;
} }
int scePowerUnregisterCallback(int slotId) int scePowerUnregisterCallback(int slotId) {
{ if (slotId < 0 || slotId >= numberOfCBPowerSlots) {
if (slotId < 0 || slotId >= numberOfCBPowerSlots)
{
return -1; return -1;
} }
if (powerCbSlots[slotId] != 0) if (powerCbSlots[slotId] != 0) {
{
int cbId = powerCbSlots[slotId]; int cbId = powerCbSlots[slotId];
DEBUG_LOG(HLE,"0=scePowerUnregisterCallback(%i) (cbid = %i)", slotId, cbId); DEBUG_LOG(HLE,"0=scePowerUnregisterCallback(%i) (cbid = %i)", slotId, cbId);
__KernelUnregisterCallback(THREAD_CALLBACK_POWER, cbId); __KernelUnregisterCallback(THREAD_CALLBACK_POWER, cbId);
powerCbSlots[slotId] = 0; powerCbSlots[slotId] = 0;
} } else {
else
{
return 0x80000025; // TODO: docs say a value less than 0, test checks for this specifically. why?? return 0x80000025; // TODO: docs say a value less than 0, test checks for this specifically. why??
} }
return 0; return 0;
} }
int sceKernelPowerLock(int lockType) int sceKernelPowerLock(int lockType) {
{
DEBUG_LOG(HLE,"0=sceKernelPowerLock(%i)", lockType); DEBUG_LOG(HLE,"0=sceKernelPowerLock(%i)", lockType);
return 0; return 0;
} }
int sceKernelPowerUnlock(int lockType)
{ int sceKernelPowerUnlock(int lockType) {
DEBUG_LOG(HLE,"0=sceKernelPowerUnlock(%i)", lockType); DEBUG_LOG(HLE,"0=sceKernelPowerUnlock(%i)", lockType);
return 0; return 0;
} }
int sceKernelPowerTick(int flag)
{ int sceKernelPowerTick(int flag) {
DEBUG_LOG(HLE,"UNIMPL 0=sceKernelPowerTick(%i)", flag); DEBUG_LOG(HLE,"UNIMPL 0=sceKernelPowerTick(%i)", flag);
return 0; return 0;
} }
#define ERROR_POWER_VMEM_IN_USE 0x802b0200 #define ERROR_POWER_VMEM_IN_USE 0x802b0200
int sceKernelVolatileMemTryLock(int type, int paddr, int psize) int sceKernelVolatileMemTryLock(int type, int paddr, int psize) {
{ if (!volatileMemLocked) {
if (!volatileMemLocked)
{
INFO_LOG(HLE,"sceKernelVolatileMemTryLock(%i, %08x, %i) - success", type, paddr, psize); INFO_LOG(HLE,"sceKernelVolatileMemTryLock(%i, %08x, %i) - success", type, paddr, psize);
volatileMemLocked = true; volatileMemLocked = true;
} } else {
else
{
ERROR_LOG(HLE, "sceKernelVolatileMemTryLock(%i, %08x, %i) - already locked!", type, paddr, psize); ERROR_LOG(HLE, "sceKernelVolatileMemTryLock(%i, %08x, %i) - already locked!", type, paddr, psize);
return ERROR_POWER_VMEM_IN_USE; return ERROR_POWER_VMEM_IN_USE;
} }
@ -174,47 +143,45 @@ int sceKernelVolatileMemTryLock(int type, int paddr, int psize)
return 0; return 0;
} }
int sceKernelVolatileMemUnlock(int type) int sceKernelVolatileMemUnlock(int type) {
{ if (volatileMemLocked) {
INFO_LOG(HLE,"sceKernelVolatileMemUnlock(%i)", type); INFO_LOG(HLE,"sceKernelVolatileMemUnlock(%i)", type);
// TODO: sanity check volatileMemLocked = false;
volatileMemLocked = false; } else {
ERROR_LOG(HLE, "sceKernelVolatileMemUnlock(%i) FAILED - not locked", type);
}
return 0; return 0;
} }
int sceKernelVolatileMemLock(int type, int paddr, int psize) int sceKernelVolatileMemLock(int type, int paddr, int psize) {
{
return sceKernelVolatileMemTryLock(type, paddr, 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); CoreTiming::SetClockFrequencyMHz(cpufreq);
INFO_LOG(HLE,"scePowerSetClockFrequency(%i,%i,%i)", cpufreq, busfreq, gpufreq); INFO_LOG(HLE,"scePowerSetClockFrequency(%i,%i,%i)", cpufreq, busfreq, gpufreq);
} }
void scePowerGetCpuClockFrequencyInt() { u32 scePowerGetCpuClockFrequencyInt() {
int freq = CoreTiming::GetClockFrequencyMHz(); int freq = CoreTiming::GetClockFrequencyMHz();
INFO_LOG(HLE,"%i=scePowerGetCpuClockFrequencyInt()", freq); INFO_LOG(HLE,"%i=scePowerGetCpuClockFrequencyInt()", freq);
RETURN(freq); return freq;
} }
void scePowerGetPllClockFrequencyInt() { u32 scePowerGetPllClockFrequencyInt() {
int freq = CoreTiming::GetClockFrequencyMHz() / 2; int freq = CoreTiming::GetClockFrequencyMHz() / 2;
INFO_LOG(HLE,"%i=scePowerGetPllClockFrequencyInt()", freq); INFO_LOG(HLE,"%i=scePowerGetPllClockFrequencyInt()", freq);
RETURN(freq); return freq;
} }
void scePowerGetBusClockFrequencyInt() { u32 scePowerGetBusClockFrequencyInt() {
int freq = CoreTiming::GetClockFrequencyMHz() / 2; int freq = CoreTiming::GetClockFrequencyMHz() / 2;
INFO_LOG(HLE,"%i=scePowerGetBusClockFrequencyInt()", freq); INFO_LOG(HLE,"%i=scePowerGetBusClockFrequencyInt()", freq);
RETURN(freq); return freq;
} }
static const HLEFunction scePower[] = static const HLEFunction scePower[] = {
{
{0x04B7766E,&WrapI_II<scePowerRegisterCallback>,"scePowerRegisterCallback"}, {0x04B7766E,&WrapI_II<scePowerRegisterCallback>,"scePowerRegisterCallback"},
{0x2B51FE2F,0,"scePower_2B51FE2F"}, {0x2B51FE2F,0,"scePower_2B51FE2F"},
{0x442BFBAC,0,"scePowerGetBacklightMaximum"}, {0x442BFBAC,0,"scePowerGetBacklightMaximum"},
@ -249,27 +216,26 @@ static const HLEFunction scePower[] =
{0xAC32C9CC,0,"scePowerRequestSuspend"}, {0xAC32C9CC,0,"scePowerRequestSuspend"},
{0x2875994B,0,"scePower_2875994B"}, {0x2875994B,0,"scePower_2875994B"},
{0x0074EF9B,0,"scePowerGetResumeCount"}, {0x0074EF9B,0,"scePowerGetResumeCount"},
{0xDFA8BAF8,&WrapI_I<scePowerUnregisterCallback>,"scePowerUnregisterCallback"}, {0xDFA8BAF8,WrapI_I<scePowerUnregisterCallback>,"scePowerUnregisterCallback"},
{0xDB9D28DD,&WrapI_I<scePowerUnregisterCallback>,"scePowerUnregitserCallback"}, //haha {0xDB9D28DD,WrapI_I<scePowerUnregisterCallback>,"scePowerUnregitserCallback"}, //haha
{0x843FBF43,0,"scePowerSetCpuClockFrequency"}, {0x843FBF43,0,"scePowerSetCpuClockFrequency"},
{0xB8D7B3FB,0,"scePowerSetBusClockFrequency"}, {0xB8D7B3FB,0,"scePowerSetBusClockFrequency"},
{0xFEE03A2F,0,"scePowerGetCpuClockFrequency"}, {0xFEE03A2F,0,"scePowerGetCpuClockFrequency"},
{0x478FE6F5,0,"scePowerGetBusClockFrequency"}, {0x478FE6F5,0,"scePowerGetBusClockFrequency"},
{0xFDB5BFE9,scePowerGetCpuClockFrequencyInt,"scePowerGetCpuClockFrequencyInt"}, {0xFDB5BFE9,WrapU_V<scePowerGetCpuClockFrequencyInt>,"scePowerGetCpuClockFrequencyInt"},
{0xBD681969,scePowerGetBusClockFrequencyInt,"scePowerGetBusClockFrequencyInt"}, {0xBD681969,WrapU_V<scePowerGetBusClockFrequencyInt>,"scePowerGetBusClockFrequencyInt"},
{0xB1A52C83,0,"scePowerGetCpuClockFrequencyFloat"}, {0xB1A52C83,0,"scePowerGetCpuClockFrequencyFloat"},
{0x9BADB3EB,0,"scePowerGetBusClockFrequencyFloat"}, {0x9BADB3EB,0,"scePowerGetBusClockFrequencyFloat"},
{0x737486F2,&WrapV_UUU<scePowerSetClockFrequency>,"scePowerSetClockFrequency"}, {0x737486F2,WrapV_UUU<scePowerSetClockFrequency>,"scePowerSetClockFrequency"},
{0x34f9c463,scePowerGetPllClockFrequencyInt,"scePowerGetPllClockFrequencyInt"}, {0x34f9c463,WrapU_V<scePowerGetPllClockFrequencyInt>,"scePowerGetPllClockFrequencyInt"},
{0xea382a27,0,"scePowerGetPllClockFrequencyFloat"}, {0xea382a27,0,"scePowerGetPllClockFrequencyFloat"},
{0xebd177d6,&WrapV_UUU<scePowerSetClockFrequency>,"scePower_driver_EBD177D6"}, //TODO: used in a few places, jpcsp says is the same as scePowerSetClockFrequency {0xebd177d6,WrapV_UUU<scePowerSetClockFrequency>,"scePower_driver_EBD177D6"}, //TODO: used in a few places, jpcsp says is the same as scePowerSetClockFrequency
{0x469989ad,0,"scePower_469989ad"}, {0x469989ad,0,"scePower_469989ad"},
{0xa85880d0,0,"scePower_a85880d0"}, {0xa85880d0,0,"scePower_a85880d0"},
}; };
//890129c in tyshooter looks bogus //890129c in tyshooter looks bogus
const HLEFunction sceSuspendForUser[] = const HLEFunction sceSuspendForUser[] = {
{
{0xEADB1BD7,&WrapI_I<sceKernelPowerLock>,"sceKernelPowerLock"}, //(int param) set param to 0 {0xEADB1BD7,&WrapI_I<sceKernelPowerLock>,"sceKernelPowerLock"}, //(int param) set param to 0
{0x3AEE7261,&WrapI_I<sceKernelPowerUnlock>,"sceKernelPowerUnlock"},//(int param) set param to 0 {0x3AEE7261,&WrapI_I<sceKernelPowerUnlock>,"sceKernelPowerUnlock"},//(int param) set param to 0
{0x090ccb3f,&WrapI_I<sceKernelPowerTick>,"sceKernelPowerTick"}, {0x090ccb3f,&WrapI_I<sceKernelPowerTick>,"sceKernelPowerTick"},

View file

@ -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_SUSTAIN=4;
static const int PSP_SAS_ADSR_RELEASE=8; 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] = static const double f[5][2] =
{ { 0.0, 0.0 }, { { 0.0, 0.0 },
{ 60.0 / 64.0, 0.0 }, { 60.0 / 64.0, 0.0 },
@ -133,6 +145,7 @@ bool VagDecoder::Decode()
struct Voice struct Voice
{ {
u32 vagAddr; u32 vagAddr;
u32 pcmAddr;
int samplePos; int samplePos;
int size; int size;
int loop; int loop;
@ -151,8 +164,8 @@ struct Voice
int sustainLevel; int sustainLevel;
int releaseType; int releaseType;
int pitch; int pitch;
bool endFlag; int setPaused;
bool PauseFlag; int height;
bool playing; bool playing;
VagDecoder vag; VagDecoder vag;
@ -163,9 +176,12 @@ class SasInstance
public: public:
enum { NUM_VOICES = 32 }; enum { NUM_VOICES = 32 };
Voice voices[NUM_VOICES]; Voice voices[NUM_VOICES];
WaveformEffect waveformEffect;
int grainSize; int grainSize;
int maxVoices; int maxVoices;
int sampleRate; int sampleRate;
int outputMode;
int length;
void mix(u32 outAddr); void mix(u32 outAddr);
}; };
@ -186,7 +202,7 @@ void SasInstance::mix(u32 outAddr)
if (voice.playing && voice.vagAddr != 0) 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(); int sample = voice.vag.GetSample();
voice.samplePos++; voice.samplePos++;
@ -195,7 +211,8 @@ void SasInstance::mix(u32 outAddr)
voice.playing = false; voice.playing = false;
break; 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 // TODO: should mix into a temporary 32-bit buffer and then clip down
out[i * 2] += l; 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()"); DEBUG_LOG(HLE,"0=sceSasInit()");
memset(&sas, 0, sizeof(sas)); memset(&sas, 0, sizeof(sas));
sas.grainSize = grainSize; sas.grainSize = grainSize;
sas.maxVoices = maxVoices; sas.maxVoices = maxVoices;
sas.sampleRate = sampleRate; sas.sampleRate = sampleRate;
sas.outputMode = outputMode;
for (int i = 0; i < 32; i++) { for (int i = 0; i < 32; i++) {
sas.voices[i].playing = false; sas.voices[i].playing = false;
} }
return 0; return 0;
} }
u32 sceSasGetEndFlag() u32 sceSasGetEndFlag(u32 core)
{ {
u32 endFlag = 0; u32 endFlag = 0;
for (int i = 0; i < sas.maxVoices; i++) { 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); 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) 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]; Voice &v = sas.voices[voiceNum];
v.volumeLeft = l; v.volumeLeft = l;
v.volumeRight = r; v.volumeRight = r;
@ -273,13 +302,13 @@ void sceSasSetPitch(u32 core, int voiceNum, int pitch)
{ {
Voice &v = sas.voices[voiceNum]; Voice &v = sas.voices[voiceNum];
v.pitch = pitch; 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); RETURN(0);
} }
void sceSasSetKeyOn(u32 core, int voiceNum) 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]; Voice &v = sas.voices[voiceNum];
v.vag.Start(Memory::GetPointer(v.vagAddr)); v.vag.Start(Memory::GetPointer(v.vagAddr));
v.playing = true; 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! // sceSasSetKeyOff can be used to start sounds, that just sound during the Release phase!
void sceSasSetKeyOff(u32 core, int voiceNum) 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]; Voice &v = sas.voices[voiceNum];
v.playing = false; // not right! Should directly enter Release envelope stage instead! v.playing = false; // not right! Should directly enter Release envelope stage instead!
RETURN(0); RETURN(0);
@ -298,18 +327,18 @@ void sceSasSetKeyOff(u32 core, int voiceNum)
u32 sceSasSetNoise(u32 core, int voiceNum, int freq) 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]; Voice &v = sas.voices[voiceNum];
v.freq = freq; v.freq = freq;
return(0); return 0;
} }
u32 sceSasSetSL(u32 core, int voiceNum, int level) 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]; Voice &v = sas.voices[voiceNum];
v.sustainLevel = level; v.sustainLevel = level;
return(0); return 0;
} }
u32 sceSasSetADSR(u32 core, int voiceNum,int flag ,int a, int d, int s, int r) 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 & 0x2) != 0) v.decayType = d;
if ((flag & 0x4) != 0) v.sustainType = s; if ((flag & 0x4) != 0) v.sustainType = s;
if ((flag & 0x8) != 0) v.releaseType = r; 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 // 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 2: return PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE;
case 4: return PSP_SAS_ADSR_CURVE_MODE_LINEAR_BENT; case 4: return PSP_SAS_ADSR_CURVE_MODE_LINEAR_BENT;
case 6: return PSP_SAS_ADSR_CURVE_MODE_EXPONENT_DECREASE; 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) { int releaseType(int bitfield2) {
@ -385,7 +414,7 @@ int releaseRate(int bitfield2) {
return 0; return 0;
} }
if (releaseType(bitfield2) == PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE) { if (releaseType(bitfield2) == PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE) {
return (0x40000000 >> (n + 2)); return (0x40000000 >> (n + 2));
} }
return (0x8000000 >> n); return (0x8000000 >> n);
} }
@ -426,17 +455,22 @@ u32 sceSasGetEnvelopeHeight(u32 core, u32 voiceNum)
void sceSasRevType(u32 core, int type) 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); 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); RETURN(0);
} }
u32 sceSasGetPauseFlag() u32 sceSasGetPauseFlag(u32 core)
{ {
u32 PauseFlag = 0; u32 PauseFlag = 0;
for (int i = 0; i < sas.maxVoices; i++) { for (int i = 0; i < sas.maxVoices; i++) {
@ -447,33 +481,80 @@ u32 sceSasGetPauseFlag()
return PauseFlag; return PauseFlag;
} }
void sceSasRevEVOL(u32 core, int lv, int rv)
void sceSasRevEVOL(u32 core, int param1, int param2)
{ {
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); 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); 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); 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[] = const HLEFunction sceSasCore[] =
{ {
{0x42778a9f, WrapU_UUUUU<sceSasInit>, "__sceSasInit"}, // (SceUID * sasCore, int grain, int maxVoices, int outputMode, int sampleRate) {0x42778a9f, WrapU_UUUUU<sceSasInit>, "__sceSasInit"}, // (SceUID * sasCore, int grain, int maxVoices, int outputMode, int sampleRate)
{0xa3589d81, WrapV_UU<_sceSasCore>, "__sceSasCore"}, {0xa3589d81, WrapV_UU<_sceSasCore>, "__sceSasCore"},
{0x50a14dfc, WrapV_UU<_sceSasCoreWithMix>, "__sceSasCoreWithMix"}, // Process and mix into buffer (int sasCore, int sasInOut, int leftVolume, int rightVolume) {0x50a14dfc, WrapV_UU<_sceSasCoreWithMix>, "__sceSasCoreWithMix"}, // Process and mix into buffer (int sasCore, int sasInOut, int leftVolume, int rightVolume)
{0x68a46b95, WrapU_V<sceSasGetEndFlag>, "__sceSasGetEndFlag"}, // int sasCore {0x68a46b95, WrapU_U<sceSasGetEndFlag>, "__sceSasGetEndFlag"}, // int sasCore
{0x440ca7d8, WrapV_UIIIII<sceSasSetVolume>, "__sceSasSetVolume"}, {0x440ca7d8, WrapV_UIIIII<sceSasSetVolume>, "__sceSasSetVolume"},
{0xad84d37f, WrapV_UII<sceSasSetPitch>, "__sceSasSetPitch"}, {0xad84d37f, WrapV_UII<sceSasSetPitch>, "__sceSasSetPitch"},
{0x99944089, WrapV_UIUII<sceSasSetVoice>, "__sceSasSetVoice"}, // (int sasCore, int voice, int vagAddr, int size, int loopmode) {0x99944089, WrapV_UIUII<sceSasSetVoice>, "__sceSasSetVoice"}, // (int sasCore, int voice, int vagAddr, int size, int loopmode)
@ -489,16 +570,16 @@ const HLEFunction sceSasCore[] =
{0xd5a229c9, WrapV_UII<sceSasRevEVOL>, "__sceSasRevEVOL"}, // (int sasCore, int leftVol, int rightVol) // effect volume {0xd5a229c9, WrapV_UII<sceSasRevEVOL>, "__sceSasRevEVOL"}, // (int sasCore, int leftVol, int rightVol) // effect volume
{0x33d4ab37, WrapV_UI<sceSasRevType>, "__sceSasRevType"}, // (int sasCore, int type) {0x33d4ab37, WrapV_UI<sceSasRevType>, "__sceSasRevType"}, // (int sasCore, int type)
{0x267a6dd2, WrapV_UII<sceSasRevParam>, "__sceSasRevParam"}, // (int sasCore, int delay, int feedback) {0x267a6dd2, WrapV_UII<sceSasRevParam>, "__sceSasRevParam"}, // (int sasCore, int delay, int feedback)
{0x2c8e6ab3, WrapU_V<sceSasGetPauseFlag>, "__sceSasGetPauseFlag"}, // int sasCore {0x2c8e6ab3, WrapU_U<sceSasGetPauseFlag>, "__sceSasGetPauseFlag"}, // int sasCore
{0x787d04d5, 0, "__sceSasSetPause"}, {0x787d04d5, WrapU_UII<sceSasSetPause>, "__sceSasSetPause"},
{0xa232cbe6, 0, "__sceSasSetTriangularWave"}, // (int sasCore, int voice, int unknown) {0xa232cbe6, 0, "__sceSasSetTriangularWave"}, // (int sasCore, int voice, int unknown)
{0xd5ebbbcd, 0, "__sceSasSetSteepWave"}, // (int sasCore, int voice, int unknown) // square wave? {0xd5ebbbcd, 0, "__sceSasSetSteepWave"}, // (int sasCore, int voice, int unknown) // square wave?
{0xBD11B7C2, 0, "__sceSasGetGrain"}, {0xBD11B7C2, WrapU_U<sceSasGetGrain>, "__sceSasGetGrain"},
{0xd1e0a01e, 0, "__sceSasSetGrain"}, {0xd1e0a01e, WrapU_UI<sceSasSetGrain>, "__sceSasSetGrain"},
{0xe175ef66, WrapV_UII<sceSasGetOutputMode>, "__sceSasGetOutputmode"}, {0xe175ef66, WrapU_U<sceSasGetOutputMode>, "__sceSasGetOutputmode"},
{0xe855bf76, 0, "__sceSasSetOutputmode"}, {0xe855bf76, WrapU_UU<sceSasSetOutputMode>, "__sceSasSetOutputmode"},
{0x07f58c24, 0, "__sceSasGetAllEnvelopeHeights"}, // (int sasCore, int heightAddr) 32-bit heights, 0-0x40000000 {0x07f58c24, WrapU_UU<sceSasGetAllEnvelopeHeights>, "__sceSasGetAllEnvelopeHeights"}, // (int sasCore, int heightAddr) 32-bit heights, 0-0x40000000
{0xE1CD9561, 0, "__sceSasSetVoicePCM"}, {0xE1CD9561, WrapV_UIUII<sceSasSetVoicePCM>, "__sceSasSetVoicePCM"},
}; };
void Register_sceSasCore() void Register_sceSasCore()

View file

@ -107,13 +107,10 @@ u32 sceUmdGetDiscInfo(u32 infoAddr)
return PSP_ERROR_UMD_INVALID_PARAM; 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) if (unknown < 1 || unknown > 2)
{ return PSP_ERROR_UMD_INVALID_PARAM;
RETURN(PSP_ERROR_UMD_INVALID_PARAM);
return;
}
bool changed = umdActivated == 0; bool changed = umdActivated == 0;
__KernelUmdActivate(); __KernelUmdActivate();
@ -129,20 +126,18 @@ void sceUmdActivate(u32 unknown, const char *name)
u32 notifyArg = UMD_PRESENT | UMD_READABLE; u32 notifyArg = UMD_PRESENT | UMD_READABLE;
__KernelNotifyCallbackType(THREAD_CALLBACK_UMD, -1, notifyArg); __KernelNotifyCallbackType(THREAD_CALLBACK_UMD, -1, notifyArg);
RETURN(0);
if (changed) 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. // Why 18? No idea.
if (unknown < 0 || unknown > 18) if (unknown < 0 || unknown > 18)
{ return PSP_ERROR_UMD_INVALID_PARAM;
RETURN(PSP_ERROR_UMD_INVALID_PARAM);
return;
}
bool changed = umdActivated != 0; bool changed = umdActivated != 0;
__KernelUmdDeactivate(); __KernelUmdDeactivate();
@ -158,10 +153,11 @@ void sceUmdDeactivate(u32 unknown, const char *name)
u32 notifyArg = UMD_PRESENT | UMD_READY; u32 notifyArg = UMD_PRESENT | UMD_READY;
__KernelNotifyCallbackType(THREAD_CALLBACK_UMD, -1, notifyArg); __KernelNotifyCallbackType(THREAD_CALLBACK_UMD, -1, notifyArg);
RETURN(0);
if (changed) if (changed)
__KernelReSchedule("umd deactivated"); hleReSchedule("umd deactivated");
return 0;
} }
u32 sceUmdRegisterUMDCallBack(u32 cbId) 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) if (driveCBId != -1)
{ {
DEBUG_LOG(HLE,"0=sceUmdWaitDriveStatCB(stat = %08x, timeout = %d)", stat, timeout); DEBUG_LOG(HLE,"0=sceUmdWaitDriveStatCB(stat = %08x, timeout = %d)", stat, timeout);
bool callbacksProcessed = __KernelForceCallbacks(); hleCheckCurrentCallbacks();
if (callbacksProcessed)
__KernelExecutePendingMipsCalls();
} }
else else
{ {
@ -284,8 +276,11 @@ void sceUmdWaitDriveStatCB(u32 stat, u32 timeout)
__UmdWaitStat(timeout); __UmdWaitStat(timeout);
__KernelWaitCurThread(WAITTYPE_UMD, 1, stat, 0, true); __KernelWaitCurThread(WAITTYPE_UMD, 1, stat, 0, true);
__KernelCheckCallbacks();
} }
else if (driveCBId != -1)
hleReSchedule("umd stat waited");
return 0;
} }
void sceUmdCancelWaitDriveStat() void sceUmdCancelWaitDriveStat()
@ -307,13 +302,13 @@ u32 sceUmdGetErrorStat()
const HLEFunction sceUmdUser[] = const HLEFunction sceUmdUser[] =
{ {
{0xC6183D47,WrapV_UC<sceUmdActivate>,"sceUmdActivate"}, {0xC6183D47,WrapI_UC<sceUmdActivate>,"sceUmdActivate"},
{0x6B4A146C,&WrapU_V<sceUmdGetDriveStat>,"sceUmdGetDriveStat"}, {0x6B4A146C,&WrapU_V<sceUmdGetDriveStat>,"sceUmdGetDriveStat"},
{0x46EBB729,WrapI_V<sceUmdCheckMedium>,"sceUmdCheckMedium"}, {0x46EBB729,WrapI_V<sceUmdCheckMedium>,"sceUmdCheckMedium"},
{0xE83742BA,WrapV_UC<sceUmdDeactivate>,"sceUmdDeactivate"}, {0xE83742BA,WrapI_UC<sceUmdDeactivate>,"sceUmdDeactivate"},
{0x8EF08FCE,WrapV_U<sceUmdWaitDriveStat>,"sceUmdWaitDriveStat"}, {0x8EF08FCE,WrapV_U<sceUmdWaitDriveStat>,"sceUmdWaitDriveStat"},
{0x56202973,WrapV_UU<sceUmdWaitDriveStatWithTimer>,"sceUmdWaitDriveStatWithTimer"}, {0x56202973,WrapV_UU<sceUmdWaitDriveStatWithTimer>,"sceUmdWaitDriveStatWithTimer"},
{0x4A9E5E29,WrapV_UU<sceUmdWaitDriveStatCB>,"sceUmdWaitDriveStatCB"}, {0x4A9E5E29,WrapI_UU<sceUmdWaitDriveStatCB>,"sceUmdWaitDriveStatCB"},
{0x6af9b50a,sceUmdCancelWaitDriveStat,"sceUmdCancelWaitDriveStat"}, {0x6af9b50a,sceUmdCancelWaitDriveStat,"sceUmdCancelWaitDriveStat"},
{0x6B4A146C,&WrapU_V<sceUmdGetDriveStat>,"sceUmdGetDriveStat"}, {0x6B4A146C,&WrapU_V<sceUmdGetDriveStat>,"sceUmdGetDriveStat"},
{0x20628E6F,&WrapU_V<sceUmdGetErrorStat>,"sceUmdGetErrorStat"}, {0x20628E6F,&WrapU_V<sceUmdGetErrorStat>,"sceUmdGetErrorStat"},

View file

@ -16,17 +16,30 @@
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "HLE.h" #include "HLE.h"
#include "FunctionWrappers.h"
#include "sceVaudio.h" #include "sceVaudio.h"
const HLEFunction sceVaudio[] = u32 sceVaudioOutputBlocking() {
{ ERROR_LOG(HLE, "UNIMPL sceVaudioOutputBlocking(...)");
{0x03b6807d, 0, "sceVaudio_0x03b6807d"}, return 0;
{0x67585dfd, 0, "sceVaudio_0x67585dfd"}, }
{0x8986295e, 0, "sceVaudio_0x8986295e"},
u32 sceVaudioChReserve() {
ERROR_LOG(HLE, "UNIMPL sceVaudioChReserve(...)");
return 0;
}
u32 sceVaudioChRelease() {
ERROR_LOG(HLE, "UNIMPL sceVaudioChRelease(...)");
return 0;
}
const HLEFunction sceVaudio[] = {
{0x03b6807d, WrapU_V<sceVaudioOutputBlocking>, "sceVaudioOutputBlockingFunction"},
{0x67585dfd, WrapU_V<sceVaudioChReserve>, "sceVaudioChReserveFunction"},
{0x8986295e, WrapU_V<sceVaudioChRelease>, "sceVaudioChReleaseFunction"},
}; };
void Register_sceVaudio() void Register_sceVaudio() {
{
RegisterModule("sceVaudio",ARRAY_SIZE(sceVaudio), sceVaudio ); RegisterModule("sceVaudio",ARRAY_SIZE(sceVaudio), sceVaudio );
} }

@ -1 +1 @@
Subproject commit 099ac403ddb436f94e7b2227e5c491027641e556 Subproject commit e9b4496e32bb592dfff14b93abf284ff20783d3c

View file

@ -60,13 +60,16 @@ tests_good = [
"threads/lwmutex/create/create", "threads/lwmutex/create/create",
"threads/lwmutex/delete/delete", "threads/lwmutex/delete/delete",
"threads/lwmutex/lock/lock", "threads/lwmutex/lock/lock",
"threads/lwmutex/priority/priority",
"threads/lwmutex/try/try", "threads/lwmutex/try/try",
"threads/lwmutex/try600/try600", "threads/lwmutex/try600/try600",
"threads/lwmutex/unlock/unlock", "threads/lwmutex/unlock/unlock",
"threads/mbx/mbx", "threads/mbx/mbx",
"threads/mutex/mutex",
"threads/mutex/create/create", "threads/mutex/create/create",
"threads/mutex/delete/delete", "threads/mutex/delete/delete",
"threads/mutex/lock/lock", "threads/mutex/lock/lock",
"threads/mutex/priority/priority",
"threads/mutex/try/try", "threads/mutex/try/try",
"threads/mutex/unlock/unlock", "threads/mutex/unlock/unlock",
"threads/semaphores/semaphores", "threads/semaphores/semaphores",
@ -74,6 +77,7 @@ tests_good = [
"threads/semaphores/create/create", "threads/semaphores/create/create",
"threads/semaphores/delete/delete", "threads/semaphores/delete/delete",
"threads/semaphores/poll/poll", "threads/semaphores/poll/poll",
"threads/semaphores/priority/priority",
"threads/semaphores/refer/refer", "threads/semaphores/refer/refer",
"threads/semaphores/signal/signal", "threads/semaphores/signal/signal",
"threads/semaphores/wait/wait", "threads/semaphores/wait/wait",
@ -89,10 +93,7 @@ tests_next = [
"threads/fpl/fpl", "threads/fpl/fpl",
"threads/k0/k0", "threads/k0/k0",
"threads/msgpipe/msgpipe", "threads/msgpipe/msgpipe",
"threads/mutex/mutex",
"threads/mutex/priority/priority",
"threads/scheduling/scheduling", "threads/scheduling/scheduling",
"threads/semaphores/priority/priority",
"threads/threads/threads", "threads/threads/threads",
"threads/vpl/vpl", "threads/vpl/vpl",
"threads/vtimers/vtimer", "threads/vtimers/vtimer",