Merge pull request #924 from unknownbrackets/hle-delay

Add dedicated HLE delay/eat cycle funcs
This commit is contained in:
Henrik Rydgård 2013-03-09 14:17:56 -08:00
commit 5048829f61
8 changed files with 65 additions and 33 deletions

View file

@ -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)

View file

@ -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();

View file

@ -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;
}

View file

@ -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)

View file

@ -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)

View file

@ -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;
}

View file

@ -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__)

View file

@ -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",