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);
}
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() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
RETURN(retval);
@ -103,6 +108,8 @@ template<u32 func(int)> void WrapU_I() {
RETURN(retval);
}
template<int func(int)> void WrapI_I() {
int retval = func(PARAM(0));
RETURN(retval);
@ -128,6 +135,11 @@ template<void func(u32, const char *)> void WrapV_UC() {
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() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6));
RETURN(retval);
@ -220,6 +232,12 @@ template<int func(const char *, u32, u32, u32)> void WrapI_CUUU() {
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() {
u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1));
RETURN((u32) retval);
@ -262,6 +280,11 @@ template<void func(u32, int, u32)> void WrapV_UIU() {
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() {
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));
}
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() {
func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3),
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() {
func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3),
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() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
RETURN(retval);

View file

@ -25,10 +25,27 @@
#include "sceIo.h"
#include "sceAudio.h"
#include "sceKernelMemory.h"
#include "sceKernelThread.h"
#include "../MIPS/MIPSCodeUtils.h"
enum
{
// Do nothing after the syscall.
HLE_AFTER_NOTHING = 0x00,
// Reschedule immediately after the syscall.
HLE_AFTER_RESCHED = 0x01,
// Call current thread's callbacks after the syscall.
HLE_AFTER_CURRENT_CALLBACKS = 0x02,
// Check all threads' callbacks after the syscall.
HLE_AFTER_ALL_CALLBACKS = 0x04,
// Reschedule and process current thread's callbacks after the syscall.
HLE_AFTER_RESCHED_CALLBACKS = 0x08,
};
static std::vector<HLEModule> moduleDB;
static std::vector<Syscall> unresolvedSyscalls;
static int hleAfterSyscall = HLE_AFTER_NOTHING;
static const char *hleAfterSyscallReschedReason = NULL;
void HLEInit()
{
@ -177,6 +194,47 @@ const char *GetFuncName(int moduleIndex, int func)
return "[unknown]";
}
void hleCheckAllCallbacks()
{
hleAfterSyscall |= HLE_AFTER_ALL_CALLBACKS;
}
void hleCheckCurrentCallbacks()
{
hleAfterSyscall |= HLE_AFTER_CURRENT_CALLBACKS;
}
void hleReSchedule(const char *reason)
{
_dbg_assert_msg_(HLE, reason != 0, "hleReSchedule: Expecting a valid reason.");
hleAfterSyscall |= HLE_AFTER_RESCHED;
hleAfterSyscallReschedReason = reason;
}
void hleReSchedule(bool callbacks, const char *reason)
{
hleReSchedule(reason);
hleAfterSyscall |= HLE_AFTER_RESCHED_CALLBACKS;
}
inline void hleFinishSyscall()
{
if ((hleAfterSyscall & HLE_AFTER_CURRENT_CALLBACKS) != 0)
__KernelForceCallbacks();
// Rescheduling will also do HLE_AFTER_ALL_CALLBACKS.
if ((hleAfterSyscall & HLE_AFTER_RESCHED_CALLBACKS) != 0)
__KernelReSchedule(true, hleAfterSyscallReschedReason);
else if ((hleAfterSyscall & HLE_AFTER_RESCHED) != 0)
__KernelReSchedule(hleAfterSyscallReschedReason);
else if ((hleAfterSyscall & HLE_AFTER_ALL_CALLBACKS) != 0)
__KernelCheckCallbacks();
hleAfterSyscall = HLE_AFTER_NOTHING;
hleAfterSyscallReschedReason = NULL;
}
void CallSyscall(u32 op)
{
u32 callno = (op >> 6) & 0xFFFFF; //20 bits
@ -192,6 +250,9 @@ void CallSyscall(u32 op)
if (func)
{
func();
if (hleAfterSyscall != HLE_AFTER_NOTHING)
hleFinishSyscall();
}
else
{

View file

@ -73,6 +73,14 @@ int GetModuleIndex(const char *modulename);
void RegisterModule(const char *name, int numFunctions, const HLEFunction *funcTable);
// Run the current thread's callbacks after the syscall finishes.
void hleCheckCurrentCallbacks();
// Check and potentially run all thread's callbacks after the syscall finishes.
void hleCheckAllCallbacks();
// Reschedule after the syscall finishes.
void hleReSchedule(const char *reason);
// Reschedule and go into a callback processing state after the syscall finishes.
void hleReSchedule(bool callbacks, const char *reason);
void HLEInit();
void HLEShutdown();

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -70,59 +70,87 @@ void __KernelSemaInit()
semaInitComplete = true;
}
// Returns whether the thread should be removed.
bool __KernelUnlockSemaForThread(Semaphore *s, SceUID threadID, u32 &error, int result, bool &wokeThreads)
{
SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_SEMA, error);
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
// The waitID may be different after a timeout.
if (waitID != s->GetUID())
return true;
// If result is an error code, we're just letting it go.
if (result == 0)
{
int wVal = (int) __KernelGetWaitValue(threadID, error);
if (wVal > s->ns.currentCount)
return false;
s->ns.currentCount -= wVal;
s->ns.numWaitThreads--;
}
if (timeoutPtr != 0 && semaWaitTimer != 0)
{
// Remove any event for this thread.
u64 cyclesLeft = CoreTiming::UnscheduleEvent(semaWaitTimer, threadID);
Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr);
}
__KernelResumeThreadFromWait(threadID, result);
wokeThreads = true;
return true;
}
// Resume all waiting threads (for delete / cancel.)
// Returns true if it woke any threads.
bool __KernelClearSemaThreads(Semaphore *s, int reason)
{
u32 error;
bool wokeThreads = false;
// TODO: PSP_SEMA_ATTR_PRIORITY
std::vector<SceUID>::iterator iter;
for (iter = s->waitingThreads.begin(); iter != s->waitingThreads.end(); ++iter)
{
u32 error;
SceUID threadID = *iter;
SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_SEMA, error);
// The waitID may be different after a timeout.
if (waitID != s->GetUID())
continue;
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
if (timeoutPtr != 0 && semaWaitTimer != 0)
{
// Remove any event for this thread.
u64 cyclesLeft = CoreTiming::UnscheduleEvent(semaWaitTimer, threadID);
Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr);
}
__KernelResumeThreadFromWait(threadID, reason);
wokeThreads = true;
}
std::vector<SceUID>::iterator iter, end;
for (iter = s->waitingThreads.begin(), end = s->waitingThreads.end(); iter != end; ++iter)
__KernelUnlockSemaForThread(s, *iter, error, reason, wokeThreads);
s->waitingThreads.clear();
return wokeThreads;
}
// int sceKernelCancelSema(SceUID id, int newCount, int *numWaitThreads);
// void because it changes threads.
void sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr)
std::vector<SceUID>::iterator __KernelSemaFindPriority(std::vector<SceUID> &waiting, std::vector<SceUID>::iterator begin)
{
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;
Semaphore *s = kernelObjects.Get<Semaphore>(id, error);
if (s)
{
if (newCount > s->ns.maxCount)
{
RETURN(SCE_KERNEL_ERROR_ILLEGAL_COUNT);
return;
}
return SCE_KERNEL_ERROR_ILLEGAL_COUNT;
if (numWaitThreadsPtr)
{
Memory::Write_U32(s->ns.numWaitThreads, numWaitThreadsPtr);
}
if (newCount < 0)
s->ns.currentCount = s->ns.initCount;
@ -130,31 +158,26 @@ void sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr)
s->ns.currentCount = newCount;
s->ns.numWaitThreads = 0;
// We need to set the return value BEFORE rescheduling threads.
RETURN(0);
if (__KernelClearSemaThreads(s, SCE_KERNEL_ERROR_WAIT_CANCEL))
__KernelReSchedule("semaphore canceled");
hleReSchedule("semaphore canceled");
return 0;
}
else
{
ERROR_LOG(HLE, "sceKernelCancelSema : Trying to cancel invalid semaphore %i", id);
RETURN(error);
return error;
}
}
//SceUID sceKernelCreateSema(const char *name, SceUInt attr, int initVal, int maxVal, SceKernelSemaOptParam *option);
// void because it changes threads.
void sceKernelCreateSema(const char* name, u32 attr, int initVal, int maxVal, u32 optionPtr)
int sceKernelCreateSema(const char* name, u32 attr, int initVal, int maxVal, u32 optionPtr)
{
if (!semaInitComplete)
__KernelSemaInit();
if (!name)
{
RETURN(SCE_KERNEL_ERROR_ERROR);
return;
}
return SCE_KERNEL_ERROR_ERROR;
Semaphore *s = new Semaphore;
SceUID id = kernelObjects.Create(s);
@ -168,121 +191,94 @@ void sceKernelCreateSema(const char* name, u32 attr, int initVal, int maxVal, u3
s->ns.maxCount = maxVal;
s->ns.numWaitThreads = 0;
DEBUG_LOG(HLE,"%i=sceKernelCreateSema(%s, %08x, %i, %i, %08x)", id, s->ns.name, s->ns.attr, s->ns.initCount, s->ns.maxCount, optionPtr);
DEBUG_LOG(HLE, "%i=sceKernelCreateSema(%s, %08x, %i, %i, %08x)", id, s->ns.name, s->ns.attr, s->ns.initCount, s->ns.maxCount, optionPtr);
if (optionPtr != 0)
WARN_LOG(HLE,"sceKernelCreateSema(%s) unsupported options parameter.", name);
WARN_LOG(HLE, "sceKernelCreateSema(%s) unsupported options parameter.", name);
RETURN(id);
return id;
}
//int sceKernelDeleteSema(SceUID semaid);
// void because it changes threads.
void sceKernelDeleteSema(SceUID id)
int sceKernelDeleteSema(SceUID id)
{
DEBUG_LOG(HLE,"sceKernelDeleteSema(%i)", id);
DEBUG_LOG(HLE, "sceKernelDeleteSema(%i)", id);
u32 error;
Semaphore *s = kernelObjects.Get<Semaphore>(id, error);
if (s)
{
bool wokeThreads = __KernelClearSemaThreads(s, SCE_KERNEL_ERROR_WAIT_DELETE);
RETURN(kernelObjects.Destroy<Semaphore>(id));
if (wokeThreads)
__KernelReSchedule("semaphore deleted");
hleReSchedule("semaphore deleted");
return kernelObjects.Destroy<Semaphore>(id);
}
else
{
ERROR_LOG(HLE, "sceKernelDeleteSema : Trying to delete invalid semaphore %i", id);
RETURN(error);
return error;
}
}
//int sceKernelDeleteSema(SceUID semaid, SceKernelSemaInfo *info);
// void because it changes threads.
void sceKernelReferSemaStatus(SceUID id, u32 infoPtr)
int sceKernelReferSemaStatus(SceUID id, u32 infoPtr)
{
u32 error;
Semaphore *s = kernelObjects.Get<Semaphore>(id, error);
if (s)
{
DEBUG_LOG(HLE,"sceKernelReferSemaStatus(%i, %08x)", id, infoPtr);
DEBUG_LOG(HLE, "sceKernelReferSemaStatus(%i, %08x)", id, infoPtr);
Memory::WriteStruct(infoPtr, &s->ns);
RETURN(0);
return 0;
}
else
{
ERROR_LOG(HLE,"Error %08x", error);
RETURN(error);
ERROR_LOG(HLE, "sceKernelReferSemaStatus: error %08x", error);
return error;
}
}
//int sceKernelSignalSema(SceUID semaid, int signal);
// void because it changes threads.
void sceKernelSignalSema(SceUID id, int signal)
int sceKernelSignalSema(SceUID id, int signal)
{
u32 error;
Semaphore *s = kernelObjects.Get<Semaphore>(id, error);
if (s)
{
if (s->ns.currentCount + signal - s->ns.numWaitThreads > s->ns.maxCount)
{
RETURN(SCE_KERNEL_ERROR_SEMA_OVF);
return;
}
return SCE_KERNEL_ERROR_SEMA_OVF;
int oldval = s->ns.currentCount;
s->ns.currentCount += signal;
DEBUG_LOG(HLE,"sceKernelSignalSema(%i, %i) (old: %i, new: %i)", id, signal, oldval, s->ns.currentCount);
DEBUG_LOG(HLE, "sceKernelSignalSema(%i, %i) (old: %i, new: %i)", id, signal, oldval, s->ns.currentCount);
// We need to set the return value BEFORE processing other threads.
RETURN(0);
// TODO: PSP_SEMA_ATTR_PRIORITY
bool wokeThreads = false;
std::vector<SceUID>::iterator iter;
std::vector<SceUID>::iterator iter, end, best;
retry:
for (iter = s->waitingThreads.begin(); iter != s->waitingThreads.end(); ++iter)
for (iter = s->waitingThreads.begin(), end = s->waitingThreads.end(); iter != end; ++iter)
{
SceUID threadID = *iter;
SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_SEMA, error);
// The waitID may be different after a timeout.
if (waitID != s->GetUID())
if ((s->ns.attr & PSP_SEMA_ATTR_PRIORITY) != 0)
best = __KernelSemaFindPriority(s->waitingThreads, iter);
else
best = iter;
if (__KernelUnlockSemaForThread(s, *best, error, 0, wokeThreads))
{
s->waitingThreads.erase(iter);
goto retry;
}
int wVal = (int)__KernelGetWaitValue(threadID, error);
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
if (wVal <= s->ns.currentCount)
{
s->ns.currentCount -= wVal;
s->ns.numWaitThreads--;
if (timeoutPtr != 0 && semaWaitTimer != 0)
{
// Remove any event for this thread.
u64 cyclesLeft = CoreTiming::UnscheduleEvent(semaWaitTimer, threadID);
Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr);
}
__KernelResumeThreadFromWait(threadID, 0);
s->waitingThreads.erase(iter);
wokeThreads = true;
s->waitingThreads.erase(best);
goto retry;
}
}
if (wokeThreads)
__KernelReSchedule("semaphore signaled");
hleReSchedule("semaphore signaled");
return 0;
}
else
{
ERROR_LOG(HLE, "sceKernelSignalSema : Trying to signal invalid semaphore %i", id);
RETURN(error;)
return error;
}
}
@ -323,68 +319,61 @@ void __KernelSetSemaTimeout(Semaphore *s, u32 timeoutPtr)
CoreTiming::ScheduleEvent(usToCycles(micro), semaWaitTimer, __KernelGetCurThread());
}
void __KernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr, const char *badSemaMessage, bool processCallbacks)
int __KernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr, const char *badSemaMessage, bool processCallbacks)
{
u32 error;
Semaphore *s = kernelObjects.Get<Semaphore>(id, error);
if (s)
{
if (wantedCount > s->ns.maxCount || wantedCount <= 0)
{
RETURN(SCE_KERNEL_ERROR_ILLEGAL_COUNT);
return;
}
// We need to set the return value BEFORE processing callbacks / etc.
RETURN(0);
return SCE_KERNEL_ERROR_ILLEGAL_COUNT;
if (s->ns.currentCount >= wantedCount)
{
s->ns.currentCount -= wantedCount;
if (processCallbacks)
hleCheckCurrentCallbacks();
}
else
{
s->ns.numWaitThreads++;
s->waitingThreads.push_back(__KernelGetCurThread());
__KernelSetSemaTimeout(s, timeoutPtr);
__KernelWaitCurThread(WAITTYPE_SEMA, id, wantedCount, timeoutPtr, processCallbacks);
if (processCallbacks)
__KernelCheckCallbacks();
}
return 0;
}
else
{
ERROR_LOG(HLE, badSemaMessage, id);
RETURN(error);
return error;
}
}
//int sceKernelWaitSema(SceUID semaid, int signal, SceUInt *timeout);
// void because it changes threads.
void sceKernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr)
int sceKernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr)
{
DEBUG_LOG(HLE,"sceKernelWaitSema(%i, %i, %i)", id, wantedCount, timeoutPtr);
DEBUG_LOG(HLE, "sceKernelWaitSema(%i, %i, %i)", id, wantedCount, timeoutPtr);
__KernelWaitSema(id, wantedCount, timeoutPtr, "sceKernelWaitSema: Trying to wait for invalid semaphore %i", false);
return __KernelWaitSema(id, wantedCount, timeoutPtr, "sceKernelWaitSema: Trying to wait for invalid semaphore %i", false);
}
//int sceKernelWaitSemaCB(SceUID semaid, int signal, SceUInt *timeout);
// void because it changes threads.
void sceKernelWaitSemaCB(SceUID id, int wantedCount, u32 timeoutPtr)
int sceKernelWaitSemaCB(SceUID id, int wantedCount, u32 timeoutPtr)
{
DEBUG_LOG(HLE,"sceKernelWaitSemaCB(%i, %i, %i)", id, wantedCount, timeoutPtr);
DEBUG_LOG(HLE, "sceKernelWaitSemaCB(%i, %i, %i)", id, wantedCount, timeoutPtr);
__KernelWaitSema(id, wantedCount, timeoutPtr, "sceKernelWaitSemaCB: Trying to wait for invalid semaphore %i", true);
return __KernelWaitSema(id, wantedCount, timeoutPtr, "sceKernelWaitSemaCB: Trying to wait for invalid semaphore %i", true);
}
// Should be same as WaitSema but without the wait, instead returning SCE_KERNEL_ERROR_SEMA_ZERO
void sceKernelPollSema(SceUID id, int wantedCount)
int sceKernelPollSema(SceUID id, int wantedCount)
{
DEBUG_LOG(HLE,"sceKernelPollSema(%i, %i)", id, wantedCount);
DEBUG_LOG(HLE, "sceKernelPollSema(%i, %i)", id, wantedCount);
if (wantedCount <= 0)
{
RETURN(SCE_KERNEL_ERROR_ILLEGAL_COUNT);
return;
}
return SCE_KERNEL_ERROR_ILLEGAL_COUNT;
u32 error;
Semaphore *s = kernelObjects.Get<Semaphore>(id, error);
@ -393,15 +382,15 @@ void sceKernelPollSema(SceUID id, int wantedCount)
if (s->ns.currentCount >= wantedCount)
{
s->ns.currentCount -= wantedCount;
RETURN(0);
return 0;
}
else
RETURN(SCE_KERNEL_ERROR_SEMA_ZERO);
return SCE_KERNEL_ERROR_SEMA_ZERO;
}
else
{
ERROR_LOG(HLE, "sceKernelPollSema: Trying to poll invalid semaphore %i", id);
RETURN(error);
return error;
}
}

View file

@ -17,13 +17,13 @@
#pragma once
void sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr);
void sceKernelCreateSema(const char* name, u32 attr, int initVal, int maxVal, u32 optionPtr);
void sceKernelDeleteSema(SceUID id);
void sceKernelPollSema(SceUID id, int wantedCount);
void sceKernelReferSemaStatus(SceUID id, u32 infoPtr);
void sceKernelSignalSema(SceUID id, int signal);
void sceKernelWaitSema(SceUID semaid, int signal, u32 timeoutPtr);
void sceKernelWaitSemaCB(SceUID semaid, int signal, u32 timeoutPtr);
int sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr);
int sceKernelCreateSema(const char* name, u32 attr, int initVal, int maxVal, u32 optionPtr);
int sceKernelDeleteSema(SceUID id);
int sceKernelPollSema(SceUID id, int wantedCount);
int sceKernelReferSemaStatus(SceUID id, u32 infoPtr);
int sceKernelSignalSema(SceUID id, int signal);
int sceKernelWaitSema(SceUID semaid, int signal, u32 timeoutPtr);
int sceKernelWaitSemaCB(SceUID semaid, int signal, u32 timeoutPtr);
void __KernelSemaTimeout(u64 userdata, int cycleslate);

View file

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

View file

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

View file

@ -34,133 +34,102 @@ void __PowerInit() {
memset(powerCbSlots, 0, sizeof(powerCbSlots));
}
int scePowerGetBatteryLifePercent()
{
int scePowerGetBatteryLifePercent() {
DEBUG_LOG(HLE, "100=scePowerGetBatteryLifePercent");
return 100;
}
int scePowerIsPowerOnline()
{
int scePowerIsPowerOnline() {
DEBUG_LOG(HLE, "1=scePowerIsPowerOnline");
return 1;
}
int scePowerIsBatteryExist()
{
int scePowerIsBatteryExist() {
DEBUG_LOG(HLE, "1=scePowerIsBatteryExist");
return 1;
}
int scePowerIsBatteryCharging()
{
int scePowerIsBatteryCharging() {
DEBUG_LOG(HLE, "0=scePowerIsBatteryCharging");
return 0;
}
int scePowerGetBatteryChargingStatus()
{
int scePowerGetBatteryChargingStatus() {
DEBUG_LOG(HLE, "0=scePowerGetBatteryChargingStatus");
return 0;
}
int scePowerIsLowBattery()
{
int scePowerIsLowBattery() {
DEBUG_LOG(HLE, "0=scePowerIsLowBattery");
return 0;
}
int scePowerRegisterCallback(int slot, int cbId)
{
int scePowerRegisterCallback(int slot, int cbId) {
DEBUG_LOG(HLE,"0=scePowerRegisterCallback(%i, %i)", slot, cbId);
int foundSlot = -1;
if (slot == POWER_CB_AUTO) // -1 signifies auto select of bank
{
for(int i=0; i < numberOfCBPowerSlots; i++)
{
if ((powerCbSlots[i]==0) && (foundSlot == POWER_CB_AUTO)) // found an empty slot
{
if (slot == POWER_CB_AUTO) { // -1 signifies auto select of bank
for (int i=0; i < numberOfCBPowerSlots; i++) {
if ((powerCbSlots[i]==0) && (foundSlot == POWER_CB_AUTO)) { // found an empty slot
powerCbSlots[i] = cbId;
foundSlot = i;
}
}
}
else
{
if (powerCbSlots[slot] == 0)
{
} else {
if (powerCbSlots[slot] == 0) {
powerCbSlots[slot] = cbId;
foundSlot = 0;
}
else
{
} else {
// slot already in use!
foundSlot = POWER_CB_AUTO;
}
}
if (foundSlot>=0)
{
if (foundSlot>=0) {
__KernelRegisterCallback(THREAD_CALLBACK_POWER, cbId);
// Immediately notify
RETURN(0);
__KernelNotifyCallbackType(THREAD_CALLBACK_POWER, cbId, 0x185); // TODO: I have no idea what the 0x185 is from the flags, but its needed for the test to pass. Need another example of it being called
__KernelNotifyCallbackType(THREAD_CALLBACK_POWER, cbId, 0x185); // TODO: I have no idea what the 0x185 is from the flags, but its needed for the test to pass. Need another example of it being called
}
return foundSlot;
}
int scePowerUnregisterCallback(int slotId)
{
if (slotId < 0 || slotId >= numberOfCBPowerSlots)
{
int scePowerUnregisterCallback(int slotId) {
if (slotId < 0 || slotId >= numberOfCBPowerSlots) {
return -1;
}
if (powerCbSlots[slotId] != 0)
{
if (powerCbSlots[slotId] != 0) {
int cbId = powerCbSlots[slotId];
DEBUG_LOG(HLE,"0=scePowerUnregisterCallback(%i) (cbid = %i)", slotId, cbId);
__KernelUnregisterCallback(THREAD_CALLBACK_POWER, cbId);
powerCbSlots[slotId] = 0;
}
else
{
} else {
return 0x80000025; // TODO: docs say a value less than 0, test checks for this specifically. why??
}
return 0;
}
int sceKernelPowerLock(int lockType)
{
int sceKernelPowerLock(int lockType) {
DEBUG_LOG(HLE,"0=sceKernelPowerLock(%i)", lockType);
return 0;
}
int sceKernelPowerUnlock(int lockType)
{
int sceKernelPowerUnlock(int lockType) {
DEBUG_LOG(HLE,"0=sceKernelPowerUnlock(%i)", lockType);
return 0;
}
int sceKernelPowerTick(int flag)
{
int sceKernelPowerTick(int flag) {
DEBUG_LOG(HLE,"UNIMPL 0=sceKernelPowerTick(%i)", flag);
return 0;
}
#define ERROR_POWER_VMEM_IN_USE 0x802b0200
int sceKernelVolatileMemTryLock(int type, int paddr, int psize)
{
if (!volatileMemLocked)
{
int sceKernelVolatileMemTryLock(int type, int paddr, int psize) {
if (!volatileMemLocked) {
INFO_LOG(HLE,"sceKernelVolatileMemTryLock(%i, %08x, %i) - success", type, paddr, psize);
volatileMemLocked = true;
}
else
{
} else {
ERROR_LOG(HLE, "sceKernelVolatileMemTryLock(%i, %08x, %i) - already locked!", type, paddr, psize);
return ERROR_POWER_VMEM_IN_USE;
}
@ -174,47 +143,45 @@ int sceKernelVolatileMemTryLock(int type, int paddr, int psize)
return 0;
}
int sceKernelVolatileMemUnlock(int type)
{
INFO_LOG(HLE,"sceKernelVolatileMemUnlock(%i)", type);
// TODO: sanity check
volatileMemLocked = false;
int sceKernelVolatileMemUnlock(int type) {
if (volatileMemLocked) {
INFO_LOG(HLE,"sceKernelVolatileMemUnlock(%i)", type);
volatileMemLocked = false;
} else {
ERROR_LOG(HLE, "sceKernelVolatileMemUnlock(%i) FAILED - not locked", type);
}
return 0;
}
int sceKernelVolatileMemLock(int type, int paddr, int psize)
{
int sceKernelVolatileMemLock(int type, int paddr, int psize) {
return sceKernelVolatileMemTryLock(type, paddr, psize);
}
void scePowerSetClockFrequency(u32 cpufreq, u32 busfreq, u32 gpufreq)
{
void scePowerSetClockFrequency(u32 cpufreq, u32 busfreq, u32 gpufreq) {
CoreTiming::SetClockFrequencyMHz(cpufreq);
INFO_LOG(HLE,"scePowerSetClockFrequency(%i,%i,%i)", cpufreq, busfreq, gpufreq);
}
void scePowerGetCpuClockFrequencyInt() {
u32 scePowerGetCpuClockFrequencyInt() {
int freq = CoreTiming::GetClockFrequencyMHz();
INFO_LOG(HLE,"%i=scePowerGetCpuClockFrequencyInt()", freq);
RETURN(freq);
return freq;
}
void scePowerGetPllClockFrequencyInt() {
u32 scePowerGetPllClockFrequencyInt() {
int freq = CoreTiming::GetClockFrequencyMHz() / 2;
INFO_LOG(HLE,"%i=scePowerGetPllClockFrequencyInt()", freq);
RETURN(freq);
return freq;
}
void scePowerGetBusClockFrequencyInt() {
u32 scePowerGetBusClockFrequencyInt() {
int freq = CoreTiming::GetClockFrequencyMHz() / 2;
INFO_LOG(HLE,"%i=scePowerGetBusClockFrequencyInt()", freq);
RETURN(freq);
return freq;
}
static const HLEFunction scePower[] =
{
static const HLEFunction scePower[] = {
{0x04B7766E,&WrapI_II<scePowerRegisterCallback>,"scePowerRegisterCallback"},
{0x2B51FE2F,0,"scePower_2B51FE2F"},
{0x442BFBAC,0,"scePowerGetBacklightMaximum"},
@ -249,27 +216,26 @@ static const HLEFunction scePower[] =
{0xAC32C9CC,0,"scePowerRequestSuspend"},
{0x2875994B,0,"scePower_2875994B"},
{0x0074EF9B,0,"scePowerGetResumeCount"},
{0xDFA8BAF8,&WrapI_I<scePowerUnregisterCallback>,"scePowerUnregisterCallback"},
{0xDB9D28DD,&WrapI_I<scePowerUnregisterCallback>,"scePowerUnregitserCallback"}, //haha
{0xDFA8BAF8,WrapI_I<scePowerUnregisterCallback>,"scePowerUnregisterCallback"},
{0xDB9D28DD,WrapI_I<scePowerUnregisterCallback>,"scePowerUnregitserCallback"}, //haha
{0x843FBF43,0,"scePowerSetCpuClockFrequency"},
{0xB8D7B3FB,0,"scePowerSetBusClockFrequency"},
{0xFEE03A2F,0,"scePowerGetCpuClockFrequency"},
{0x478FE6F5,0,"scePowerGetBusClockFrequency"},
{0xFDB5BFE9,scePowerGetCpuClockFrequencyInt,"scePowerGetCpuClockFrequencyInt"},
{0xBD681969,scePowerGetBusClockFrequencyInt,"scePowerGetBusClockFrequencyInt"},
{0xFDB5BFE9,WrapU_V<scePowerGetCpuClockFrequencyInt>,"scePowerGetCpuClockFrequencyInt"},
{0xBD681969,WrapU_V<scePowerGetBusClockFrequencyInt>,"scePowerGetBusClockFrequencyInt"},
{0xB1A52C83,0,"scePowerGetCpuClockFrequencyFloat"},
{0x9BADB3EB,0,"scePowerGetBusClockFrequencyFloat"},
{0x737486F2,&WrapV_UUU<scePowerSetClockFrequency>,"scePowerSetClockFrequency"},
{0x34f9c463,scePowerGetPllClockFrequencyInt,"scePowerGetPllClockFrequencyInt"},
{0x737486F2,WrapV_UUU<scePowerSetClockFrequency>,"scePowerSetClockFrequency"},
{0x34f9c463,WrapU_V<scePowerGetPllClockFrequencyInt>,"scePowerGetPllClockFrequencyInt"},
{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"},
{0xa85880d0,0,"scePower_a85880d0"},
};
//890129c in tyshooter looks bogus
const HLEFunction sceSuspendForUser[] =
{
const HLEFunction sceSuspendForUser[] = {
{0xEADB1BD7,&WrapI_I<sceKernelPowerLock>,"sceKernelPowerLock"}, //(int param) set param to 0
{0x3AEE7261,&WrapI_I<sceKernelPowerUnlock>,"sceKernelPowerUnlock"},//(int param) set param to 0
{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_RELEASE=8;
struct WaveformEffect
{
int type;
int delay;
int feedback ;
int leftVol;
int rightVol;
int isDryOn;
int isWetOn;
};
static const double f[5][2] =
{ { 0.0, 0.0 },
{ 60.0 / 64.0, 0.0 },
@ -133,6 +145,7 @@ bool VagDecoder::Decode()
struct Voice
{
u32 vagAddr;
u32 pcmAddr;
int samplePos;
int size;
int loop;
@ -151,8 +164,8 @@ struct Voice
int sustainLevel;
int releaseType;
int pitch;
bool endFlag;
bool PauseFlag;
int setPaused;
int height;
bool playing;
VagDecoder vag;
@ -163,9 +176,12 @@ class SasInstance
public:
enum { NUM_VOICES = 32 };
Voice voices[NUM_VOICES];
WaveformEffect waveformEffect;
int grainSize;
int maxVoices;
int sampleRate;
int outputMode;
int length;
void mix(u32 outAddr);
};
@ -186,7 +202,7 @@ void SasInstance::mix(u32 outAddr)
if (voice.playing && voice.vagAddr != 0)
{
for (int i = 0; i < grainSize; i++)
for (int i = 0; i < sas.grainSize; i++)
{
int sample = voice.vag.GetSample();
voice.samplePos++;
@ -195,7 +211,8 @@ void SasInstance::mix(u32 outAddr)
voice.playing = false;
break;
}
int l = sample; int r = sample; //* (voice.volumeLeft >> 16), r = sample * (voice.volumeRight >> 16);
int l = sample;
int r = sample; //* (voice.volumeLeft >> 16), r = sample * (voice.volumeRight >> 16);
// TODO: should mix into a temporary 32-bit buffer and then clip down
out[i * 2] += l;
@ -205,20 +222,21 @@ void SasInstance::mix(u32 outAddr)
}
}
u32 sceSasInit(u32 core, u32 grainSize, u32 maxVoices, u32 unknown, u32 sampleRate)
u32 sceSasInit(u32 core, u32 grainSize, u32 maxVoices, u32 outputMode, u32 sampleRate)
{
DEBUG_LOG(HLE,"0=sceSasInit()");
memset(&sas, 0, sizeof(sas));
sas.grainSize = grainSize;
sas.maxVoices = maxVoices;
sas.sampleRate = sampleRate;
sas.outputMode = outputMode;
for (int i = 0; i < 32; i++) {
sas.voices[i].playing = false;
}
return 0;
}
u32 sceSasGetEndFlag()
u32 sceSasGetEndFlag(u32 core)
{
u32 endFlag = 0;
for (int i = 0; i < sas.maxVoices; i++) {
@ -260,9 +278,20 @@ void sceSasSetVoice(u32 core, int voiceNum, u32 vagAddr, int size, int loop)
RETURN(0);
}
u32 sceSasSetPause(u32 core, int voicebit, int pause)
{
DEBUG_LOG(HLE,"0=sceSasSetPause(core=%08x, voicebit=%i, pause=%i)", core, voicebit, pause);
for (int i = 0; voicebit != 0; i++, voicebit >>= 1) {
if ((voicebit & 1) != 0) {
sas.voices[i].setPaused=pause;
}
}
return 0;
}
void sceSasSetVolume(u32 core, int voiceNum, int l, int r, int el, int er)
{
DEBUG_LOG(HLE,"UNIMPL 0=sceSasSetVolume(core=%08x, voicenum=%i, l=%i, r=%i, el=%i, er=%i", core, voiceNum, l, r, el, er);
DEBUG_LOG(HLE,"0=sceSasSetVolume(core=%08x, voiceNum=%i, l=%i, r=%i, el=%i, er=%i", core, voiceNum, l, r, el, er);
Voice &v = sas.voices[voiceNum];
v.volumeLeft = l;
v.volumeRight = r;
@ -273,13 +302,13 @@ void sceSasSetPitch(u32 core, int voiceNum, int pitch)
{
Voice &v = sas.voices[voiceNum];
v.pitch = pitch;
DEBUG_LOG(HLE,"UNIMPL 0=sceSasSetPitch(core=%08x, voicenum=%i, pitch=%i)", core, voiceNum, pitch);
DEBUG_LOG(HLE,"0=sceSasSetPitch(core=%08x, voiceNum=%i, pitch=%i)", core, voiceNum, pitch);
RETURN(0);
}
void sceSasSetKeyOn(u32 core, int voiceNum)
{
DEBUG_LOG(HLE,"0=sceSasSetKeyOff(core=%08x, voicenum=%i)", core, voiceNum);
DEBUG_LOG(HLE,"0=sceSasSetKeyOn(core=%08x, voiceNum=%i)", core, voiceNum);
Voice &v = sas.voices[voiceNum];
v.vag.Start(Memory::GetPointer(v.vagAddr));
v.playing = true;
@ -290,7 +319,7 @@ void sceSasSetKeyOn(u32 core, int voiceNum)
// sceSasSetKeyOff can be used to start sounds, that just sound during the Release phase!
void sceSasSetKeyOff(u32 core, int voiceNum)
{
DEBUG_LOG(HLE,"0=sceSasSetKeyOff(core=%08x, voicenum=%i)", core, voiceNum);
DEBUG_LOG(HLE,"0=sceSasSetKeyOff(core=%08x, voiceNum=%i)", core, voiceNum);
Voice &v = sas.voices[voiceNum];
v.playing = false; // not right! Should directly enter Release envelope stage instead!
RETURN(0);
@ -298,18 +327,18 @@ void sceSasSetKeyOff(u32 core, int voiceNum)
u32 sceSasSetNoise(u32 core, int voiceNum, int freq)
{
DEBUG_LOG(HLE,"0=sceSasSetVoice(core=%08x, voiceNum=%i, freq=%i)", core, voiceNum, freq);
DEBUG_LOG(HLE,"0=sceSasSetNoise(core=%08x, voiceNum=%i, freq=%i)", core, voiceNum, freq);
Voice &v = sas.voices[voiceNum];
v.freq = freq;
return(0);
return 0;
}
u32 sceSasSetSL(u32 core, int voiceNum, int level)
{
DEBUG_LOG(HLE,"0=sceSasSetSL(core=%08x, voicenum=%i, level=%i)", core, voiceNum, level);
DEBUG_LOG(HLE,"0=sceSasSetSL(core=%08x, voiceNum=%i, level=%i)", core, voiceNum, level);
Voice &v = sas.voices[voiceNum];
v.sustainLevel = level;
return(0);
return 0;
}
u32 sceSasSetADSR(u32 core, int voiceNum,int flag ,int a, int d, int s, int r)
@ -331,7 +360,7 @@ u32 sceSasSetADSRMode(u32 core, int voiceNum,int flag ,int a, int d, int s, int
if ((flag & 0x2) != 0) v.decayType = d;
if ((flag & 0x4) != 0) v.sustainType = s;
if ((flag & 0x8) != 0) v.releaseType = r;
return 0;
return 0 ;
}
// http://code.google.com/p/jpcsp/source/browse/trunk/src/jpcsp/HLE/modules150/sceSasCore.java
@ -370,9 +399,9 @@ int sustainType(int bitfield2) {
case 2: return PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE;
case 4: return PSP_SAS_ADSR_CURVE_MODE_LINEAR_BENT;
case 6: return PSP_SAS_ADSR_CURVE_MODE_EXPONENT_DECREASE;
}
DEBUG_LOG(HLE,"sasSetSimpleADSR,ERROR_SAS_INVALID_ADSR_CURVE_MODE");
}
ERROR_LOG(HLE,"sasSetSimpleADSR,ERROR_SAS_INVALID_ADSR_CURVE_MODE");
return 0;
}
int releaseType(int bitfield2) {
@ -385,7 +414,7 @@ int releaseRate(int bitfield2) {
return 0;
}
if (releaseType(bitfield2) == PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE) {
return (0x40000000 >> (n + 2));
return (0x40000000 >> (n + 2));
}
return (0x8000000 >> n);
}
@ -426,17 +455,22 @@ u32 sceSasGetEnvelopeHeight(u32 core, u32 voiceNum)
void sceSasRevType(u32 core, int type)
{
DEBUG_LOG(HLE,"UNIMPL 0=sceSasRevType(core=%08x, type=%i)", core, type);
DEBUG_LOG(HLE,"0=sceSasRevType(core=%08x, type=%i)", core, type);
sas.waveformEffect.type=type;
RETURN(0);
}
void sceSasRevParam(u32 core, int param1, int param2)
void sceSasRevParam(u32 core, int delay, int feedback)
{
DEBUG_LOG(HLE,"UNIMPL 0=sceSasRevParam(core=%08x, param1=%i, param2=%i)", core, param1, param2);
DEBUG_LOG(HLE,"0=sceSasRevParam(core=%08x, delay=%i, feedback=%i)", core, delay, feedback);
sas.waveformEffect.delay = delay;
sas.waveformEffect.feedback = feedback;
RETURN(0);
}
u32 sceSasGetPauseFlag()
u32 sceSasGetPauseFlag(u32 core)
{
u32 PauseFlag = 0;
for (int i = 0; i < sas.maxVoices; i++) {
@ -447,33 +481,80 @@ u32 sceSasGetPauseFlag()
return PauseFlag;
}
void sceSasRevEVOL(u32 core, int param1, int param2)
void sceSasRevEVOL(u32 core, int lv, int rv)
{
DEBUG_LOG(HLE,"UNIMPL 0=sceSasRevEVOL(core=%08x, param1=%i, param2=%i)", core, param1, param2);
DEBUG_LOG(HLE,"0=sceSasRevEVOL(core=%08x, leftVolume=%i, rightVolume=%i)", core, lv, rv);
sas.waveformEffect.leftVol = lv;
sas.waveformEffect.rightVol = rv;
RETURN(0);
}
void sceSasRevVON(u32 core, int param1, int param2)
void sceSasRevVON(u32 core, int dry, int wet)
{
DEBUG_LOG(HLE,"UNIMPL 0=sceSasRevEVOL(core=%08x, param1=%i, param2=%i)", core, param1, param2);
DEBUG_LOG(HLE,"0=sceSasRevVON(core=%08x, dry=%i, wet=%i)", core, dry, wet);
sas.waveformEffect.isDryOn = (dry > 0);
sas.waveformEffect.isWetOn = (wet > 0);
RETURN(0);
}
void sceSasGetOutputMode(u32 core, int param1, int param2)
u32 sceSasGetGrain(u32 core)
{
DEBUG_LOG(HLE,"UNIMPL 0=sceSasGetOutputMode(core=%08x, param1=%i, param2=%i)", core, param1, param2);
DEBUG_LOG(HLE,"0=sceSasGetGrain(core=%08x)", core);
return sas.grainSize;
}
u32 sceSasSetGrain(u32 core, int grain)
{
DEBUG_LOG(HLE,"0=sceSasSetGrain(core=%08x, grain=%i)", core, grain);
sas.grainSize = grain;
return 0;
}
u32 sceSasGetOutputMode(u32 core)
{
DEBUG_LOG(HLE,"0=sceSasGetOutputMode(core=%08x)", core);
return sas.outputMode;
}
u32 sceSasSetOutputMode(u32 core, u32 outputMode)
{
DEBUG_LOG(HLE,"0=sceSasSetOutputMode(core=%08x, outputMode=%i)", core, outputMode);
sas.outputMode = outputMode;
return 0;
}
void sceSasSetVoicePCM(u32 core, int voiceNum, u32 pcmAddr, int size, int loop)
{
DEBUG_LOG(HLE,"0=sceSasSetVoicePCM(core=%08x, voicenum=%i, pcmAddr=%08x, size=%i, loop=%i)",core, voiceNum, pcmAddr, size, loop);
Voice &v = sas.voices[voiceNum];
v.pcmAddr = pcmAddr;
v.size = size;
v.loop = loop;
v.playing = true;
RETURN(0);
}
u32 sceSasGetAllEnvelopeHeights(u32 core, u32 heightsAddr)
{
DEBUG_LOG(HLE,"0=sceSasGetAllEnvelopeHeights(core=%08x, heightsAddr=%i)", core, heightsAddr);
if (Memory::IsValidAddress(heightsAddr)) {
for (int i = 0; i < sas.length; i++) {
int voiceHeight = sas.voices[i].height;
Memory::Write_U32(voiceHeight, heightsAddr + i * 4);
}
}
return 0;
}
const HLEFunction sceSasCore[] =
{
{0x42778a9f, WrapU_UUUUU<sceSasInit>, "__sceSasInit"}, // (SceUID * sasCore, int grain, int maxVoices, int outputMode, int sampleRate)
{0xa3589d81, WrapV_UU<_sceSasCore>, "__sceSasCore"},
{0x50a14dfc, WrapV_UU<_sceSasCoreWithMix>, "__sceSasCoreWithMix"}, // Process and mix into buffer (int sasCore, int sasInOut, int leftVolume, int rightVolume)
{0x68a46b95, WrapU_V<sceSasGetEndFlag>, "__sceSasGetEndFlag"}, // int sasCore
{0x68a46b95, WrapU_U<sceSasGetEndFlag>, "__sceSasGetEndFlag"}, // int sasCore
{0x440ca7d8, WrapV_UIIIII<sceSasSetVolume>, "__sceSasSetVolume"},
{0xad84d37f, WrapV_UII<sceSasSetPitch>, "__sceSasSetPitch"},
{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
{0x33d4ab37, WrapV_UI<sceSasRevType>, "__sceSasRevType"}, // (int sasCore, int type)
{0x267a6dd2, WrapV_UII<sceSasRevParam>, "__sceSasRevParam"}, // (int sasCore, int delay, int feedback)
{0x2c8e6ab3, WrapU_V<sceSasGetPauseFlag>, "__sceSasGetPauseFlag"}, // int sasCore
{0x787d04d5, 0, "__sceSasSetPause"},
{0x2c8e6ab3, WrapU_U<sceSasGetPauseFlag>, "__sceSasGetPauseFlag"}, // int sasCore
{0x787d04d5, WrapU_UII<sceSasSetPause>, "__sceSasSetPause"},
{0xa232cbe6, 0, "__sceSasSetTriangularWave"}, // (int sasCore, int voice, int unknown)
{0xd5ebbbcd, 0, "__sceSasSetSteepWave"}, // (int sasCore, int voice, int unknown) // square wave?
{0xBD11B7C2, 0, "__sceSasGetGrain"},
{0xd1e0a01e, 0, "__sceSasSetGrain"},
{0xe175ef66, WrapV_UII<sceSasGetOutputMode>, "__sceSasGetOutputmode"},
{0xe855bf76, 0, "__sceSasSetOutputmode"},
{0x07f58c24, 0, "__sceSasGetAllEnvelopeHeights"}, // (int sasCore, int heightAddr) 32-bit heights, 0-0x40000000
{0xE1CD9561, 0, "__sceSasSetVoicePCM"},
{0xBD11B7C2, WrapU_U<sceSasGetGrain>, "__sceSasGetGrain"},
{0xd1e0a01e, WrapU_UI<sceSasSetGrain>, "__sceSasSetGrain"},
{0xe175ef66, WrapU_U<sceSasGetOutputMode>, "__sceSasGetOutputmode"},
{0xe855bf76, WrapU_UU<sceSasSetOutputMode>, "__sceSasSetOutputmode"},
{0x07f58c24, WrapU_UU<sceSasGetAllEnvelopeHeights>, "__sceSasGetAllEnvelopeHeights"}, // (int sasCore, int heightAddr) 32-bit heights, 0-0x40000000
{0xE1CD9561, WrapV_UIUII<sceSasSetVoicePCM>, "__sceSasSetVoicePCM"},
};
void Register_sceSasCore()

View file

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

View file

@ -16,17 +16,30 @@
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "HLE.h"
#include "FunctionWrappers.h"
#include "sceVaudio.h"
const HLEFunction sceVaudio[] =
{
{0x03b6807d, 0, "sceVaudio_0x03b6807d"},
{0x67585dfd, 0, "sceVaudio_0x67585dfd"},
{0x8986295e, 0, "sceVaudio_0x8986295e"},
u32 sceVaudioOutputBlocking() {
ERROR_LOG(HLE, "UNIMPL sceVaudioOutputBlocking(...)");
return 0;
}
u32 sceVaudioChReserve() {
ERROR_LOG(HLE, "UNIMPL sceVaudioChReserve(...)");
return 0;
}
u32 sceVaudioChRelease() {
ERROR_LOG(HLE, "UNIMPL sceVaudioChRelease(...)");
return 0;
}
const HLEFunction sceVaudio[] = {
{0x03b6807d, WrapU_V<sceVaudioOutputBlocking>, "sceVaudioOutputBlockingFunction"},
{0x67585dfd, WrapU_V<sceVaudioChReserve>, "sceVaudioChReserveFunction"},
{0x8986295e, WrapU_V<sceVaudioChRelease>, "sceVaudioChReleaseFunction"},
};
void Register_sceVaudio()
{
void Register_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/delete/delete",
"threads/lwmutex/lock/lock",
"threads/lwmutex/priority/priority",
"threads/lwmutex/try/try",
"threads/lwmutex/try600/try600",
"threads/lwmutex/unlock/unlock",
"threads/mbx/mbx",
"threads/mutex/mutex",
"threads/mutex/create/create",
"threads/mutex/delete/delete",
"threads/mutex/lock/lock",
"threads/mutex/priority/priority",
"threads/mutex/try/try",
"threads/mutex/unlock/unlock",
"threads/semaphores/semaphores",
@ -74,6 +77,7 @@ tests_good = [
"threads/semaphores/create/create",
"threads/semaphores/delete/delete",
"threads/semaphores/poll/poll",
"threads/semaphores/priority/priority",
"threads/semaphores/refer/refer",
"threads/semaphores/signal/signal",
"threads/semaphores/wait/wait",
@ -89,10 +93,7 @@ tests_next = [
"threads/fpl/fpl",
"threads/k0/k0",
"threads/msgpipe/msgpipe",
"threads/mutex/mutex",
"threads/mutex/priority/priority",
"threads/scheduling/scheduling",
"threads/semaphores/priority/priority",
"threads/threads/threads",
"threads/vpl/vpl",
"threads/vtimers/vtimer",