mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Merge pull request #924 from unknownbrackets/hle-delay
Add dedicated HLE delay/eat cycle funcs
This commit is contained in:
commit
5048829f61
8 changed files with 65 additions and 33 deletions
|
@ -21,6 +21,7 @@
|
|||
#include <vector>
|
||||
#include "../MemMap.h"
|
||||
#include "../Config.h"
|
||||
#include "Core/CoreTiming.h"
|
||||
#include "Core/Reporting.h"
|
||||
|
||||
#include "HLETables.h"
|
||||
|
@ -55,12 +56,27 @@ enum
|
|||
static std::vector<HLEModule> moduleDB;
|
||||
static std::vector<Syscall> unresolvedSyscalls;
|
||||
static std::vector<Syscall> exportedCalls;
|
||||
static int delayedResultEvent = -1;
|
||||
static int hleAfterSyscall = HLE_AFTER_NOTHING;
|
||||
static const char *hleAfterSyscallReschedReason;
|
||||
|
||||
void hleDelayResultFinish(u64 userdata, int cycleslate)
|
||||
{
|
||||
u32 error;
|
||||
SceUID threadID = (SceUID) userdata;
|
||||
SceUID verify = __KernelGetWaitID(threadID, WAITTYPE_DELAY, error);
|
||||
SceUID result = __KernelGetWaitValue(threadID, error);
|
||||
|
||||
if (error == 0 && verify == 1)
|
||||
__KernelResumeThreadFromWait(threadID, result);
|
||||
else
|
||||
WARN_LOG(HLE, "Someone else woke up HLE-blocked thread?");
|
||||
}
|
||||
|
||||
void HLEInit()
|
||||
{
|
||||
RegisterAllModules();
|
||||
delayedResultEvent = CoreTiming::RegisterEvent("HLEDelayedResult", hleDelayResultFinish);
|
||||
}
|
||||
|
||||
void HLEDoState(PointerWrap &p)
|
||||
|
@ -68,6 +84,8 @@ void HLEDoState(PointerWrap &p)
|
|||
Syscall sc = {""};
|
||||
p.Do(unresolvedSyscalls, sc);
|
||||
p.Do(exportedCalls, sc);
|
||||
p.Do(delayedResultEvent);
|
||||
CoreTiming::RestoreRegisterEvent(delayedResultEvent, "HLEDelayedResult", hleDelayResultFinish);
|
||||
p.DoMarker("HLE");
|
||||
}
|
||||
|
||||
|
@ -310,6 +328,19 @@ bool hleExecuteDebugBreak(const HLEFunction &func)
|
|||
return true;
|
||||
}
|
||||
|
||||
u32 hleDelayResult(u32 result, const char *reason, int usec)
|
||||
{
|
||||
CoreTiming::ScheduleEvent(usToCycles(usec), delayedResultEvent, __KernelGetCurThread());
|
||||
__KernelWaitCurThread(WAITTYPE_DELAY, 1, result, 0, false, reason);
|
||||
return result;
|
||||
}
|
||||
|
||||
void hleEatMicro(int usec)
|
||||
{
|
||||
// Maybe this should Idle, at least for larger delays? Could that cause issues?
|
||||
currentMIPS->downcount -= (int) usToCycles(usec);
|
||||
}
|
||||
|
||||
inline void hleFinishSyscall(int modulenum, int funcnum)
|
||||
{
|
||||
if ((hleAfterSyscall & HLE_AFTER_CURRENT_CALLBACKS) != 0)
|
||||
|
|
|
@ -87,6 +87,10 @@ void hleRunInterrupts();
|
|||
// Pause emulation after the syscall finishes.
|
||||
void hleDebugBreak();
|
||||
|
||||
// Delays the result for usec microseconds, allowing other threads to run during this time.
|
||||
u32 hleDelayResult(u32 result, const char *reason, int usec);
|
||||
void hleEatMicro(int usec);
|
||||
|
||||
void HLEInit();
|
||||
void HLEDoState(PointerWrap &p);
|
||||
void HLEShutdown();
|
||||
|
|
|
@ -543,6 +543,7 @@ u32 sceDisplayWaitVblank() {
|
|||
return 0;
|
||||
} else {
|
||||
DEBUG_LOG(HLE,"sceDisplayWaitVblank() - not waiting since in vBlank");
|
||||
hleEatMicro(5);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -562,6 +563,7 @@ u32 sceDisplayWaitVblankCB() {
|
|||
return 0;
|
||||
} else {
|
||||
DEBUG_LOG(HLE,"sceDisplayWaitVblank() - not waiting since in vBlank");
|
||||
hleEatMicro(5);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -584,12 +586,7 @@ u32 sceDisplayGetVcount() {
|
|||
// Too spammy
|
||||
// DEBUG_LOG(HLE,"%i=sceDisplayGetVcount()", vCount);
|
||||
|
||||
// Puyo Puyo Fever polls this as a substitute for waiting for vblank.
|
||||
// As a result, the game never gets to reschedule so it doesn't mix audio and things break.
|
||||
// Need to find a better hack as this breaks games like Project Diva.
|
||||
// hleReSchedule("sceDisplayGetVcount hack"); // Puyo puyo hack?
|
||||
|
||||
CoreTiming::Idle(1000000);
|
||||
hleEatMicro(2);
|
||||
return vCount;
|
||||
}
|
||||
|
||||
|
|
|
@ -230,24 +230,13 @@ struct SceKernelSMOption {
|
|||
//////////////////////////////////////////////////////////////////////////
|
||||
// STATE BEGIN
|
||||
static int actionAfterModule;
|
||||
static int eventLoadModule = -1;
|
||||
static SceUID mainModuleID; // hack
|
||||
// STATE END
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void __KernelModuleLoaded(u64 userdata, int cycleslate)
|
||||
{
|
||||
u32 error;
|
||||
SceUID threadID = userdata & 0xFFFFFFFF;
|
||||
SceUID moduleID = __KernelGetWaitValue(threadID, error);
|
||||
if (error == 0 && moduleID != 0)
|
||||
__KernelResumeThreadFromWait(threadID, moduleID);
|
||||
}
|
||||
|
||||
void __KernelModuleInit()
|
||||
{
|
||||
actionAfterModule = __KernelRegisterActionType(AfterModuleEntryCall::Create);
|
||||
eventLoadModule = CoreTiming::RegisterEvent("LoadModule", __KernelModuleLoaded);
|
||||
}
|
||||
|
||||
void __KernelModuleDoState(PointerWrap &p)
|
||||
|
@ -255,8 +244,6 @@ void __KernelModuleDoState(PointerWrap &p)
|
|||
p.Do(mainModuleID);
|
||||
p.Do(actionAfterModule);
|
||||
__KernelRestoreActionType(actionAfterModule, AfterModuleEntryCall::Create);
|
||||
p.Do(eventLoadModule);
|
||||
CoreTiming::RestoreRegisterEvent(eventLoadModule, "LoadModule", __KernelModuleLoaded);
|
||||
p.DoMarker("sceKernelModule");
|
||||
}
|
||||
|
||||
|
@ -827,9 +814,7 @@ u32 sceKernelLoadModule(const char *name, u32 flags, u32 optionAddr)
|
|||
}
|
||||
|
||||
// TODO: This is not the right timing and probably not the right wait type, just an approximation.
|
||||
CoreTiming::ScheduleEvent(usToCycles(500), eventLoadModule, __KernelGetCurThread());
|
||||
__KernelWaitCurThread(WAITTYPE_SEMA, -1, module->GetUID(), 0, false, "module loaded");
|
||||
return module->GetUID();
|
||||
return hleDelayResult(module->GetUID(), "module loaded", 500);
|
||||
}
|
||||
|
||||
void sceKernelStartModule(u32 moduleId, u32 argsize, u32 argAddr, u32 returnValueAddr, u32 optionAddr)
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "HLE.h"
|
||||
#include "../MIPS/MIPS.h"
|
||||
#include "Core/Reporting.h"
|
||||
|
||||
#include "sceKernel.h"
|
||||
#include "sceKernelThread.h"
|
||||
|
@ -30,6 +31,7 @@
|
|||
#include "../Dialog/PSPOskDialog.h"
|
||||
|
||||
const int SCE_ERROR_MODULE_BAD_ID = 0x80111101;
|
||||
const int SCE_ERROR_AV_MODULE_BAD_ID = 0x80110F01;
|
||||
|
||||
PSPSaveDialog saveDialog;
|
||||
PSPMsgDialog msgDialog;
|
||||
|
@ -92,16 +94,21 @@ int sceUtilitySavedataUpdate(int animSpeed)
|
|||
|
||||
u32 sceUtilityLoadAvModule(u32 module)
|
||||
{
|
||||
if (module > 7)
|
||||
{
|
||||
ERROR_LOG(HLE, "sceUtilityLoadAvModule(%i): invalid module id", module);
|
||||
Reporting::ReportMessage("sceUtilityLoadAvModule(%i): invalid module id", module);
|
||||
return SCE_ERROR_AV_MODULE_BAD_ID;
|
||||
}
|
||||
|
||||
DEBUG_LOG(HLE,"sceUtilityLoadAvModule(%i)", module);
|
||||
hleReSchedule("utilityloadavmodule");
|
||||
return 0;
|
||||
return hleDelayResult(0, "utility av module loaded", 25000);
|
||||
}
|
||||
|
||||
u32 sceUtilityUnloadAvModule(u32 module)
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceUtilityUnloadAvModule(%i)", module);
|
||||
hleReSchedule("utilityunloadavmodule");
|
||||
return 0;
|
||||
return hleDelayResult(0, "utility av module unloaded", 800);
|
||||
}
|
||||
|
||||
u32 sceUtilityLoadModule(u32 module)
|
||||
|
@ -110,6 +117,7 @@ u32 sceUtilityLoadModule(u32 module)
|
|||
if (module < 0x100 || module > 0x601)
|
||||
{
|
||||
ERROR_LOG(HLE, "sceUtilityLoadModule(%i): invalid module id", module);
|
||||
Reporting::ReportMessage("sceUtilityLoadModule(%i): invalid module id", module);
|
||||
return SCE_ERROR_MODULE_BAD_ID;
|
||||
}
|
||||
|
||||
|
@ -117,10 +125,9 @@ u32 sceUtilityLoadModule(u32 module)
|
|||
// TODO: Each module has its own timing, technically, but this is a low-end.
|
||||
// Note: Some modules have dependencies, but they still resched.
|
||||
if (module == 0x3FF)
|
||||
sceKernelDelayThread(130);
|
||||
return hleDelayResult(0, "utility module loaded", 130);
|
||||
else
|
||||
sceKernelDelayThread(25000);
|
||||
return 0;
|
||||
return hleDelayResult(0, "utility module loaded", 25000);
|
||||
}
|
||||
|
||||
u32 sceUtilityUnloadModule(u32 module)
|
||||
|
@ -129,6 +136,7 @@ u32 sceUtilityUnloadModule(u32 module)
|
|||
if (module < 0x100 || module > 0x601)
|
||||
{
|
||||
ERROR_LOG(HLE, "sceUtilityUnloadModule(%i): invalid module id", module);
|
||||
Reporting::ReportMessage("sceUtilityUnloadModule(%i): invalid module id", module);
|
||||
return SCE_ERROR_MODULE_BAD_ID;
|
||||
}
|
||||
|
||||
|
@ -136,10 +144,9 @@ u32 sceUtilityUnloadModule(u32 module)
|
|||
// TODO: Each module has its own timing, technically, but this is a low-end.
|
||||
// Note: If not loaded, it should not reschedule actually...
|
||||
if (module == 0x3FF)
|
||||
sceKernelDelayThread(110);
|
||||
return hleDelayResult(0, "utility module unloaded", 110);
|
||||
else
|
||||
sceKernelDelayThread(400);
|
||||
return 0;
|
||||
return hleDelayResult(0, "utility module unloaded", 400);
|
||||
}
|
||||
|
||||
int sceUtilityMsgDialogInitStart(u32 structAddr)
|
||||
|
|
|
@ -71,6 +71,10 @@ void RunTests()
|
|||
coreParam.useMediaEngine = false;
|
||||
coreParam.collectEmuLog = &output;
|
||||
|
||||
// Never report from tests.
|
||||
std::string savedReportHost = g_Config.sReportHost;
|
||||
g_Config.sReportHost = "";
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(testsToRun); i++) {
|
||||
const char *testName = testsToRun[i];
|
||||
coreParam.fileToStart = g_Config.memCardDirectory + "pspautotests/tests/" + testName + ".prx";
|
||||
|
@ -136,4 +140,6 @@ void RunTests()
|
|||
}
|
||||
glstate.Restore();
|
||||
glstate.viewport.set(0,0,pixel_xres,pixel_yres);
|
||||
|
||||
g_Config.sReportHost = savedReportHost;
|
||||
}
|
|
@ -166,6 +166,8 @@ int main(int argc, const char* argv[])
|
|||
g_Config.bEnableSound = false;
|
||||
g_Config.bFirstRun = false;
|
||||
g_Config.bIgnoreBadMemAccess = true;
|
||||
// Never report from tests.
|
||||
g_Config.sReportHost = "";
|
||||
|
||||
#if defined(ANDROID)
|
||||
#elif defined(BLACKBERRY) || defined(__SYMBIAN32__)
|
||||
|
|
2
test.py
2
test.py
|
@ -53,6 +53,7 @@ tests_good = [
|
|||
"ctrl/sampling/sampling",
|
||||
"ctrl/sampling2/sampling2",
|
||||
"display/display",
|
||||
"display/vblankmulti",
|
||||
"dmac/dmactest",
|
||||
"loader/bss/bss",
|
||||
"intr/intr",
|
||||
|
@ -134,7 +135,6 @@ tests_next = [
|
|||
"audio/atrac/atractest",
|
||||
"audio/mp3/mp3test",
|
||||
"audio/sascore/sascore",
|
||||
"display/vblankmulti",
|
||||
"malloc/malloc",
|
||||
"threads/fpl/fpl",
|
||||
"threads/k0/k0",
|
||||
|
|
Loading…
Add table
Reference in a new issue