mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Merge branch 'master' of https://github.com/hrydgard/ppsspp
This commit is contained in:
commit
4fce289c02
21 changed files with 895 additions and 794 deletions
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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"},
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"},
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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"},
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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"},
|
||||
|
|
|
@ -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
|
7
test.py
7
test.py
|
@ -60,13 +60,16 @@ tests_good = [
|
|||
"threads/lwmutex/create/create",
|
||||
"threads/lwmutex/delete/delete",
|
||||
"threads/lwmutex/lock/lock",
|
||||
"threads/lwmutex/priority/priority",
|
||||
"threads/lwmutex/try/try",
|
||||
"threads/lwmutex/try600/try600",
|
||||
"threads/lwmutex/unlock/unlock",
|
||||
"threads/mbx/mbx",
|
||||
"threads/mutex/mutex",
|
||||
"threads/mutex/create/create",
|
||||
"threads/mutex/delete/delete",
|
||||
"threads/mutex/lock/lock",
|
||||
"threads/mutex/priority/priority",
|
||||
"threads/mutex/try/try",
|
||||
"threads/mutex/unlock/unlock",
|
||||
"threads/semaphores/semaphores",
|
||||
|
@ -74,6 +77,7 @@ tests_good = [
|
|||
"threads/semaphores/create/create",
|
||||
"threads/semaphores/delete/delete",
|
||||
"threads/semaphores/poll/poll",
|
||||
"threads/semaphores/priority/priority",
|
||||
"threads/semaphores/refer/refer",
|
||||
"threads/semaphores/signal/signal",
|
||||
"threads/semaphores/wait/wait",
|
||||
|
@ -89,10 +93,7 @@ tests_next = [
|
|||
"threads/fpl/fpl",
|
||||
"threads/k0/k0",
|
||||
"threads/msgpipe/msgpipe",
|
||||
"threads/mutex/mutex",
|
||||
"threads/mutex/priority/priority",
|
||||
"threads/scheduling/scheduling",
|
||||
"threads/semaphores/priority/priority",
|
||||
"threads/threads/threads",
|
||||
"threads/vpl/vpl",
|
||||
"threads/vtimers/vtimer",
|
||||
|
|
Loading…
Add table
Reference in a new issue