diff --git a/Common/ABI.cpp b/Common/ABI.cpp index ad1fe2c94e..eab9b80c1a 100644 --- a/Common/ABI.cpp +++ b/Common/ABI.cpp @@ -123,7 +123,14 @@ void XEmitter::ABI_CallFunctionCCCP(void *func, u32 param1, u32 param2,u32 param ABI_RestoreStack(4 * 4); } -void XEmitter::ABI_CallFunctionPPC(void *func, void *param1, void *param2,u32 param3) { +void XEmitter::ABI_CallFunctionP(void *func, void *param1) { + ABI_AlignStack(1 * 4); + PUSH(32, Imm32((u32)param1)); + CALL(func); + ABI_RestoreStack(1 * 4); +} + +void XEmitter::ABI_CallFunctionPPC(void *func, void *param1, void *param2, u32 param3) { ABI_AlignStack(3 * 4); PUSH(32, Imm32(param3)); PUSH(32, Imm32((u32)param2)); @@ -352,6 +359,19 @@ void XEmitter::ABI_CallFunctionCCCP(void *func, u32 param1, u32 param2, u32 para } } +void XEmitter::ABI_CallFunctionP(void *func, void *param1) { + MOV(64, R(ABI_PARAM1), Imm64((u64)param1)); + u64 distance = u64(func) - (u64(code) + 5); + if (distance >= 0x0000000080000000ULL + && distance < 0xFFFFFFFF80000000ULL) { + // Far call + MOV(64, R(RAX), Imm64((u64)func)); + CALLptr(R(RAX)); + } else { + CALL(func); + } +} + void XEmitter::ABI_CallFunctionPPC(void *func, void *param1, void *param2, u32 param3) { MOV(64, R(ABI_PARAM1), Imm64((u64)param1)); MOV(64, R(ABI_PARAM2), Imm64((u64)param2)); diff --git a/Common/x64Emitter.h b/Common/x64Emitter.h index 524a492035..ba7c8d0fa1 100644 --- a/Common/x64Emitter.h +++ b/Common/x64Emitter.h @@ -677,8 +677,9 @@ public: void ABI_CallFunctionCC(void *func, u32 param1, u32 param2); void ABI_CallFunctionCCC(void *func, u32 param1, u32 param2, u32 param3); void ABI_CallFunctionCCP(void *func, u32 param1, u32 param2, void *param3); - void ABI_CallFunctionCCCP(void *func, u32 param1, u32 param2,u32 param3, void *param4); - void ABI_CallFunctionPPC(void *func, void *param1, void *param2,u32 param3); + void ABI_CallFunctionCCCP(void *func, u32 param1, u32 param2, u32 param3, void *param4); + void ABI_CallFunctionP(void *func, void *param1); + void ABI_CallFunctionPPC(void *func, void *param1, void *param2, u32 param3); void ABI_CallFunctionAC(void *func, const Gen::OpArg &arg1, u32 param2); void ABI_CallFunctionACC(void *func, const Gen::OpArg &arg1, u32 param2, u32 param3); void ABI_CallFunctionA(void *func, const Gen::OpArg &arg1); diff --git a/Core/HLE/HLE.cpp b/Core/HLE/HLE.cpp index b840a37b0f..a4ab699ef2 100644 --- a/Core/HLE/HLE.cpp +++ b/Core/HLE/HLE.cpp @@ -365,7 +365,7 @@ inline static void SetDeadbeefRegs() currentMIPS->hi = 0xDEADBEEF; } -inline void hleFinishSyscall(int modulenum, int funcnum) +inline void hleFinishSyscall(const HLEFunction &info) { if ((hleAfterSyscall & HLE_AFTER_SKIP_DEADBEEF) == 0) SetDeadbeefRegs(); @@ -386,7 +386,7 @@ inline void hleFinishSyscall(int modulenum, int funcnum) if ((hleAfterSyscall & HLE_AFTER_DEBUG_BREAK) != 0) { - if (!hleExecuteDebugBreak(moduleDB[modulenum].funcTable[funcnum])) + if (!hleExecuteDebugBreak(info)) { // We'll do it next syscall. hleAfterSyscall = HLE_AFTER_DEBUG_BREAK; @@ -435,6 +435,69 @@ inline void updateSyscallStats(int modulenum, int funcnum, double total) } } +inline void CallSyscallWithFlags(const HLEFunction *info) +{ + const u32 flags = info->flags; + if ((flags & HLE_NOT_DISPATCH_SUSPENDED) && !__KernelIsDispatchEnabled()) + { + DEBUG_LOG(HLE, "%s: dispatch suspended", info->name); + RETURN(SCE_KERNEL_ERROR_CAN_NOT_WAIT); + } + else if ((flags & HLE_NOT_IN_INTERRUPT) && __IsInInterrupt()) + { + DEBUG_LOG(HLE, "%s: in interrupt", info->name); + RETURN(SCE_KERNEL_ERROR_ILLEGAL_CONTEXT); + } + else + info->func(); + + if (hleAfterSyscall != HLE_AFTER_NOTHING) + hleFinishSyscall(*info); + else + SetDeadbeefRegs(); +} + +inline void CallSyscallWithoutFlags(const HLEFunction *info) +{ + info->func(); + + if (hleAfterSyscall != HLE_AFTER_NOTHING) + hleFinishSyscall(*info); + else + SetDeadbeefRegs(); +} + +const HLEFunction *GetSyscallInfo(MIPSOpcode op) +{ + u32 callno = (op >> 6) & 0xFFFFF; //20 bits + int funcnum = callno & 0xFFF; + int modulenum = (callno & 0xFF000) >> 12; + if (funcnum == 0xfff) + { + ERROR_LOG(HLE,"Unknown syscall: Module: %s", modulenum > (int) moduleDB.size() ? "(unknown)" : moduleDB[modulenum].name); + return NULL; + } + return &moduleDB[modulenum].funcTable[funcnum]; +} + +void *GetQuickSyscallFunc(MIPSOpcode op) +{ + // TODO: Clear jit cache on g_Config.bShowDebugStats change? + if (g_Config.bShowDebugStats) + return NULL; + + const HLEFunction *info = GetSyscallInfo(op); + if (!info || !info->func) + return NULL; + + // TODO: Do this with a flag? + if (op == GetSyscallOp("FakeSysCalls", NID_IDLE)) + return (void *)info->func; + if (info->flags != 0) + return (void *)&CallSyscallWithFlags; + return (void *)&CallSyscallWithoutFlags; +} + void CallSyscall(MIPSOpcode op) { double start = 0.0; // need to initialize to fix the race condition where g_Config.bShowDebugStats is enabled in the middle of this func. @@ -443,49 +506,27 @@ void CallSyscall(MIPSOpcode op) time_update(); start = time_now_d(); } - u32 callno = (op >> 6) & 0xFFFFF; //20 bits - int funcnum = callno & 0xFFF; - int modulenum = (callno & 0xFF000) >> 12; - if (funcnum == 0xfff) + const HLEFunction *info = GetSyscallInfo(op); + if (info) { - ERROR_LOG(HLE,"Unknown syscall: Module: %s", modulenum > (int) moduleDB.size() ? "(unknown)" : moduleDB[modulenum].name); - return; - } - HLEFunc func = moduleDB[modulenum].funcTable[funcnum].func; - if (func) - { - // TODO: Move to jit/interp. - u32 flags = moduleDB[modulenum].funcTable[funcnum].flags; - if (flags != 0) + if (info->func) { - if ((flags & HLE_NOT_DISPATCH_SUSPENDED) && !__KernelIsDispatchEnabled()) - { - DEBUG_LOG(HLE, "%s: dispatch suspended", moduleDB[modulenum].funcTable[funcnum].name); - RETURN(SCE_KERNEL_ERROR_CAN_NOT_WAIT); - } - else if ((flags & HLE_NOT_IN_INTERRUPT) && __IsInInterrupt()) - { - DEBUG_LOG(HLE, "%s: in interrupt", moduleDB[modulenum].funcTable[funcnum].name); - RETURN(SCE_KERNEL_ERROR_ILLEGAL_CONTEXT); - } + if (op == GetSyscallOp("FakeSysCalls", NID_IDLE)) + info->func(); + else if (info->flags != 0) + CallSyscallWithFlags(info); else - func(); + CallSyscallWithoutFlags(info); } else - func(); - - if (hleAfterSyscall != HLE_AFTER_NOTHING) - hleFinishSyscall(modulenum, funcnum); - else - SetDeadbeefRegs(); - } - else - { - ERROR_LOG_REPORT(HLE, "Unimplemented HLE function %s", moduleDB[modulenum].funcTable[funcnum].name); + ERROR_LOG_REPORT(HLE, "Unimplemented HLE function %s", info->name); } if (g_Config.bShowDebugStats) { time_update(); + u32 callno = (op >> 6) & 0xFFFFF; //20 bits + int funcnum = callno & 0xFFF; + int modulenum = (callno & 0xFF000) >> 12; updateSyscallStats(modulenum, funcnum, time_now_d() - start); } } diff --git a/Core/HLE/HLE.h b/Core/HLE/HLE.h index 5650022168..e9b5e49a9c 100644 --- a/Core/HLE/HLE.h +++ b/Core/HLE/HLE.h @@ -120,3 +120,8 @@ bool WriteSyscall(const char *module, u32 nib, u32 address); void CallSyscall(MIPSOpcode op); void WriteFuncStub(u32 stubAddr, u32 symAddr); void WriteFuncMissingStub(u32 stubAddr, u32 nid); + +const HLEFunction *GetSyscallInfo(MIPSOpcode op); +// For jit, takes arg: const HLEFunction * +void *GetQuickSyscallFunc(MIPSOpcode op); + diff --git a/Core/MIPS/ARM/ArmCompBranch.cpp b/Core/MIPS/ARM/ArmCompBranch.cpp index 86abee87ed..7597151557 100644 --- a/Core/MIPS/ARM/ArmCompBranch.cpp +++ b/Core/MIPS/ARM/ArmCompBranch.cpp @@ -425,9 +425,13 @@ void Jit::Comp_Syscall(MIPSOpcode op) js.downcountAmount = -offset; SaveDowncount(); - // Skip the CallSyscall overhead for __KernelIdle, which is called a lot. - if (op == GetSyscallOp("FakeSysCalls", NID_IDLE)) - QuickCallFunction(R1, (void *)GetFunc("FakeSysCalls", NID_IDLE)->func); + // Skip the CallSyscall where possible. + void *quickFunc = GetQuickSyscallFunc(op); + if (quickFunc) + { + MOVI2R(R0, (u32)(intptr_t)GetSyscallInfo(op)); + QuickCallFunction(R1, quickFunc); + } else { MOVI2R(R0, op.encoding); diff --git a/Core/MIPS/MIPSInt.cpp b/Core/MIPS/MIPSInt.cpp index f6c8c900e7..e504cbfd6a 100644 --- a/Core/MIPS/MIPSInt.cpp +++ b/Core/MIPS/MIPSInt.cpp @@ -159,10 +159,7 @@ namespace MIPSInt mipsr4k.pc += 4; } mipsr4k.inDelaySlot = false; - if (op == GetSyscallOp("FakeSysCalls", NID_IDLE)) - GetFunc("FakeSysCalls", NID_IDLE)->func(); - else - CallSyscall(op); + CallSyscall(op); } void Int_Sync(MIPSOpcode op) diff --git a/Core/MIPS/x86/CompBranch.cpp b/Core/MIPS/x86/CompBranch.cpp index 3d63d07f65..75368a74d2 100644 --- a/Core/MIPS/x86/CompBranch.cpp +++ b/Core/MIPS/x86/CompBranch.cpp @@ -634,9 +634,10 @@ void Jit::Comp_Syscall(MIPSOpcode op) WriteDowncount(offset); js.downcountAmount = -offset; - // Skip the CallSyscall overhead for __KernelIdle, which is called a lot. - if (op == GetSyscallOp("FakeSysCalls", NID_IDLE)) - ABI_CallFunction((void *)GetFunc("FakeSysCalls", NID_IDLE)->func); + // Skip the CallSyscall where possible. + void *quickFunc = GetQuickSyscallFunc(op); + if (quickFunc) + ABI_CallFunctionP(quickFunc, (void *)GetSyscallInfo(op)); else ABI_CallFunctionC((void *)&CallSyscall, op.encoding);