diff --git a/Common/ABI.cpp b/Common/ABI.cpp index f0489e346d..3d0d792984 100644 --- a/Common/ABI.cpp +++ b/Common/ABI.cpp @@ -178,6 +178,15 @@ void XEmitter::ABI_CallFunctionA(void *func, const Gen::OpArg &arg1) ABI_RestoreStack(1 * 4); } +void XEmitter::ABI_CallFunctionAA(void *func, const Gen::OpArg &arg1, const Gen::OpArg &arg2) +{ + ABI_AlignStack(2 * 4); + PUSH(32, arg2); + PUSH(32, arg1); + CALL(func); + ABI_RestoreStack(2 * 4); +} + void XEmitter::ABI_PushAllCalleeSavedRegsAndAdjustStack() { // Note: 4 * 4 = 16 bytes, so alignment is preserved. PUSH(EBP); @@ -445,6 +454,23 @@ void XEmitter::ABI_CallFunctionA(void *func, const Gen::OpArg &arg1) } } +void XEmitter::ABI_CallFunctionAA(void *func, const Gen::OpArg &arg1, const Gen::OpArg &arg2) +{ + if (!arg1.IsSimpleReg(ABI_PARAM1)) + MOV(32, R(ABI_PARAM1), arg1); + if (!arg2.IsSimpleReg(ABI_PARAM2)) + MOV(32, R(ABI_PARAM2), arg2); + 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); + } +} + unsigned int XEmitter::ABI_GetAlignedFrameSize(unsigned int frameSize) { return frameSize; } diff --git a/Common/x64Emitter.h b/Common/x64Emitter.h index e0b85e6b85..cb690593a3 100644 --- a/Common/x64Emitter.h +++ b/Common/x64Emitter.h @@ -658,6 +658,7 @@ public: 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); + void ABI_CallFunctionAA(void *func, const Gen::OpArg &arg1, const Gen::OpArg &arg2); // Pass a register as a paremeter. void ABI_CallFunctionR(void *func, Gen::X64Reg reg1); diff --git a/Core/MIPS/x86/CompLoadStore.cpp b/Core/MIPS/x86/CompLoadStore.cpp index f53338823a..d6889ba92d 100644 --- a/Core/MIPS/x86/CompLoadStore.cpp +++ b/Core/MIPS/x86/CompLoadStore.cpp @@ -41,28 +41,148 @@ namespace MIPSComp { - static void ReadMemSafe32(u32 addr, int preg, u32 offset) + void Jit::CompITypeMemRead(u32 op, u32 bits, void (XEmitter::*mov)(int, int, X64Reg, OpArg), void *safeFunc) { - currentMIPS->r[preg] = Memory::Read_U32(addr + offset); + CONDITIONAL_DISABLE; + int offset = (signed short)(op&0xFFFF); + int rt = _RT; + int rs = _RS; + + gpr.Lock(rt, rs); + gpr.BindToRegister(rt, rt == rs, true); + + if (gpr.R(rs).IsImm()) + { + void *data = Memory::GetPointer(gpr.R(rs).GetImmValue() + offset); + if (data) + { +#ifdef _M_IX86 + (this->*mov)(32, bits, gpr.RX(rt), M(data)); +#else + (this->*mov)(32, bits, gpr.RX(rt), MDisp(RBX, gpr.R(rs).GetImmValue() + offset)); +#endif + } + else + MOV(32, gpr.R(rt), Imm32(0)); + } + else if (!g_Config.bFastMemory) + { + MOV(32, R(EAX), gpr.R(rs)); + // Is it in physical ram? + CMP(32, R(EAX), Imm32(0x08000000)); + FixupBranch tooLow = J_CC(CC_L); + CMP(32, R(EAX), Imm32(0x0A000000)); + FixupBranch tooHigh = J_CC(CC_GE); + + const u8* safe = GetCodePtr(); +#ifdef _M_IX86 + (this->*mov)(32, bits, gpr.RX(rt), MDisp(EAX, (u32)Memory::base + offset)); +#else + (this->*mov)(32, bits, gpr.RX(rt), MComplex(RBX, EAX, SCALE_1, offset)); +#endif + + FixupBranch skip = J(); + SetJumpTarget(tooLow); + SetJumpTarget(tooHigh); + + // Might also be the scratchpad. + CMP(32, R(EAX), Imm32(0x00010000)); + FixupBranch tooLow2 = J_CC(CC_L); + CMP(32, R(EAX), Imm32(0x00014000)); + J_CC(CC_L, safe); + SetJumpTarget(tooLow2); + + ADD(32, R(EAX), Imm32(offset)); + ABI_CallFunctionA(thunks.ProtectFunction(safeFunc, 1), R(EAX)); + (this->*mov)(32, bits, gpr.RX(rt), R(EAX)); + + SetJumpTarget(skip); + } + else + { + MOV(32, R(EAX), gpr.R(rs)); +#ifdef _M_IX86 + AND(32, R(EAX), Imm32(Memory::MEMVIEW32_MASK)); + (this->*mov)(32, bits, gpr.RX(rt), MDisp(EAX, (u32)Memory::base + offset)); +#else + (this->*mov)(32, bits, gpr.RX(rt), MComplex(RBX, EAX, SCALE_1, offset)); +#endif + } + + gpr.UnlockAll(); } - static void ReadMemSafe16(u32 addr, int preg, u32 offset) + void Jit::CompITypeMemWrite(u32 op, u32 bits, void *safeFunc) { - currentMIPS->r[preg] = Memory::Read_U16(addr + offset); - } + CONDITIONAL_DISABLE; + int offset = (signed short)(op&0xFFFF); + int rt = _RT; + int rs = _RS; - static void WriteMemSafe32(u32 addr, int preg, u32 offset) - { - Memory::Write_U32(currentMIPS->r[preg], addr + offset); - } + gpr.Lock(rt, rs); + gpr.BindToRegister(rt, true, false); - static void WriteMemSafe16(u32 addr, int preg, u32 offset) - { - Memory::Write_U16(currentMIPS->r[preg], addr + offset); + if (gpr.R(rs).IsImm()) + { + void *data = Memory::GetPointer(gpr.R(rs).GetImmValue() + offset); + if (data) + { +#ifdef _M_IX86 + MOV(bits, M(data), gpr.R(rt)); +#else + MOV(bits, MDisp(RBX, gpr.R(rs).GetImmValue() + offset), gpr.R(rt)); +#endif + } + } + else if (!g_Config.bFastMemory) + { + MOV(32, R(EAX), gpr.R(rs)); + // Is it in physical ram? + CMP(32, R(EAX), Imm32(0x08000000)); + FixupBranch tooLow = J_CC(CC_L); + CMP(32, R(EAX), Imm32(0x0A000000)); + FixupBranch tooHigh = J_CC(CC_GE); + + const u8* safe = GetCodePtr(); +#ifdef _M_IX86 + MOV(bits, MDisp(EAX, (u32)Memory::base + offset), gpr.R(rt)); +#else + MOV(bits, MComplex(RBX, EAX, SCALE_1, offset), gpr.R(rt)); +#endif + + FixupBranch skip = J(); + SetJumpTarget(tooLow); + SetJumpTarget(tooHigh); + + // Might also be the scratchpad. + CMP(32, R(EAX), Imm32(0x00010000)); + FixupBranch tooLow2 = J_CC(CC_L); + CMP(32, R(EAX), Imm32(0x00014000)); + J_CC(CC_L, safe); + SetJumpTarget(tooLow2); + + ADD(32, R(EAX), Imm32(offset)); + ABI_CallFunctionAA(thunks.ProtectFunction(safeFunc, 2), gpr.R(rt), R(EAX)); + + SetJumpTarget(skip); + } + else + { + MOV(32, R(EAX), gpr.R(rs)); +#ifdef _M_IX86 + AND(32, R(EAX), Imm32(Memory::MEMVIEW32_MASK)); + MOV(bits, MDisp(EAX, (u32)Memory::base + offset), gpr.R(rt)); +#else + MOV(bits, MComplex(RBX, EAX, SCALE_1, offset), gpr.R(rt)); +#endif + } + + gpr.UnlockAll(); } void Jit::Comp_ITypeMem(u32 op) { + CONDITIONAL_DISABLE; int offset = (signed short)(op&0xFFFF); int rt = _RT; int rs = _RS; @@ -75,186 +195,35 @@ namespace MIPSComp switch (o) { case 37: //R(rt) = ReadMem16(addr); break; //lhu - if (!g_Config.bFastMemory) - { - FlushAll(); - - gpr.Lock(rt, rs); - gpr.BindToRegister(rt, rt == rs, true); - - MOV(32, R(EAX), gpr.R(rs)); - CMP(32, R(EAX), Imm32(0x08000000)); - FixupBranch tooLow = J_CC(CC_L); - CMP(32, R(EAX), Imm32(0x0A000000)); - FixupBranch tooHigh = J_CC(CC_GE); -#ifdef _M_IX86 - MOVZX(32, 16, gpr.RX(rt), MDisp(EAX, (u32)Memory::base + offset)); -#else - MOVZX(32, 16, gpr.RX(rt), MComplex(RBX, EAX, SCALE_1, offset)); -#endif - gpr.UnlockAll(); - FlushAll(); - - FixupBranch skip = J(); - SetJumpTarget(tooLow); - SetJumpTarget(tooHigh); - ABI_CallFunctionACC((void *) &ReadMemSafe16, gpr.R(rs), rt, offset); - SetJumpTarget(skip); - } - else - { - gpr.Lock(rt, rs); - gpr.BindToRegister(rt, rt == rs, true); -#ifdef _M_IX86 - MOV(32, R(EAX), gpr.R(rs)); - AND(32, R(EAX), Imm32(Memory::MEMVIEW32_MASK)); - MOVZX(32, 16, gpr.RX(rt), MDisp(EAX, (u32)Memory::base + offset)); -#else - MOV(32, R(EAX), gpr.R(rs)); - MOVZX(32, 16, gpr.RX(rt), MComplex(RBX, EAX, SCALE_1, offset)); -#endif - gpr.UnlockAll(); - } + CompITypeMemRead(op, 16, &XEmitter::MOVZX, (void *) &Memory::Read_U16); break; case 36: //R(rt) = ReadMem8 (addr); break; //lbu - Comp_Generic(op); - return; - - case 35: //R(rt) = ReadMem32(addr); break; //lw - if (!g_Config.bFastMemory) - { - FlushAll(); - - gpr.Lock(rt, rs); - gpr.BindToRegister(rt, rt == rs, true); - - MOV(32, R(EAX), gpr.R(rs)); - CMP(32, R(EAX), Imm32(0x08000000)); - FixupBranch tooLow = J_CC(CC_L); - CMP(32, R(EAX), Imm32(0x0A000000)); - FixupBranch tooHigh = J_CC(CC_GE); -#ifdef _M_IX86 - MOV(32, gpr.R(rt), MDisp(EAX, (u32)Memory::base + offset)); -#else - MOV(32, gpr.R(rt), MComplex(RBX, EAX, SCALE_1, offset)); -#endif - gpr.UnlockAll(); - FlushAll(); - - FixupBranch skip = J(); - SetJumpTarget(tooLow); - SetJumpTarget(tooHigh); - ABI_CallFunctionACC((void *) &ReadMemSafe32, gpr.R(rs), rt, offset); - SetJumpTarget(skip); - } - else - { - gpr.Lock(rt, rs); - gpr.BindToRegister(rt, rt == rs, true); -#ifdef _M_IX86 - MOV(32, R(EAX), gpr.R(rs)); - AND(32, R(EAX), Imm32(Memory::MEMVIEW32_MASK)); - MOV(32, gpr.R(rt), MDisp(EAX, (u32)Memory::base + offset)); -#else - MOV(32, R(EAX), gpr.R(rs)); - MOV(32, gpr.R(rt), MComplex(RBX, EAX, SCALE_1, offset)); -#endif - gpr.UnlockAll(); - } + CompITypeMemRead(op, 8, &XEmitter::MOVZX, (void *) &Memory::Read_U8); + break; + + case 35: //R(rt) = ReadMem32(addr); break; //lw + CompITypeMemRead(op, 32, &XEmitter::MOVZX, (void *) &Memory::Read_U16); + break; + + case 32: //R(rt) = (u32)(s32)(s8) ReadMem8 (addr); break; //lb + CompITypeMemRead(op, 8, &XEmitter::MOVSX, (void *) &Memory::Read_U8); + break; + + case 33: //R(rt) = (u32)(s32)(s16)ReadMem16(addr); break; //lh + CompITypeMemRead(op, 16, &XEmitter::MOVSX, (void *) &Memory::Read_U16); break; - case 132: //R(rt) = (u32)(s32)(s8) ReadMem8 (addr); break; //lb - case 133: //R(rt) = (u32)(s32)(s16)ReadMem16(addr); break; //lh - case 136: //R(rt) = ReadMem8 (addr); break; //lbu case 140: //WriteMem8 (addr, R(rt)); break; //sb Comp_Generic(op); return; case 41: //WriteMem16(addr, R(rt)); break; //sh - if (!g_Config.bFastMemory) - { - FlushAll(); - - gpr.Lock(rt, rs); - gpr.BindToRegister(rt, true, true); - - MOV(32, R(EAX), gpr.R(rs)); - CMP(32, R(EAX), Imm32(0x08000000)); - FixupBranch tooLow = J_CC(CC_L); - CMP(32, R(EAX), Imm32(0x0A000000)); - FixupBranch tooHigh = J_CC(CC_GE); -#ifdef _M_IX86 - MOV(16, MDisp(EAX, (u32)Memory::base + offset), gpr.R(rt)); -#else - MOV(16, MComplex(RBX, EAX, SCALE_1, offset), gpr.R(rt)); -#endif - gpr.UnlockAll(); - FlushAll(); - - FixupBranch skip = J(); - SetJumpTarget(tooLow); - SetJumpTarget(tooHigh); - ABI_CallFunctionACC((void *) &WriteMemSafe16, gpr.R(rs), rt, offset); - SetJumpTarget(skip); - } - else - { - gpr.Lock(rt, rs); - gpr.BindToRegister(rt, true, false); -#ifdef _M_IX86 - MOV(32, R(EAX), gpr.R(rs)); - AND(32, R(EAX), Imm32(Memory::MEMVIEW32_MASK)); - MOV(16, MDisp(EAX, (u32)Memory::base + offset), gpr.R(rt)); -#else - MOV(32, R(EAX), gpr.R(rs)); - MOV(16, MComplex(RBX, EAX, SCALE_1, offset), gpr.R(rt)); -#endif - gpr.UnlockAll(); - } + CompITypeMemWrite(op, 16, (void *) &Memory::Write_U16); break; case 43: //WriteMem32(addr, R(rt)); break; //sw - if (!g_Config.bFastMemory) - { - FlushAll(); - - gpr.Lock(rt, rs); - gpr.BindToRegister(rt, true, true); - - MOV(32, R(EAX), gpr.R(rs)); - CMP(32, R(EAX), Imm32(0x08000000)); - FixupBranch tooLow = J_CC(CC_L); - CMP(32, R(EAX), Imm32(0x0A000000)); - FixupBranch tooHigh = J_CC(CC_GE); -#ifdef _M_IX86 - MOV(32, MDisp(EAX, (u32)Memory::base + offset), gpr.R(rt)); -#else - MOV(32, MComplex(RBX, EAX, SCALE_1, offset), gpr.R(rt)); -#endif - gpr.UnlockAll(); - FlushAll(); - - FixupBranch skip = J(); - SetJumpTarget(tooLow); - SetJumpTarget(tooHigh); - ABI_CallFunctionACC((void *) &WriteMemSafe32, gpr.R(rs), rt, offset); - SetJumpTarget(skip); - } - else - { - gpr.Lock(rt, rs); - gpr.BindToRegister(rt, true, false); -#ifdef _M_IX86 - MOV(32, R(EAX), gpr.R(rs)); - AND(32, R(EAX), Imm32(Memory::MEMVIEW32_MASK)); - MOV(32, MDisp(EAX, (u32)Memory::base + offset), gpr.R(rt)); -#else - MOV(32, R(EAX), gpr.R(rs)); - MOV(32, MComplex(RBX, EAX, SCALE_1, offset), gpr.R(rt)); -#endif - gpr.UnlockAll(); - } + CompITypeMemWrite(op, 32, (void *) &Memory::Write_U32); break; case 134: //lwl diff --git a/Core/MIPS/x86/Jit.h b/Core/MIPS/x86/Jit.h index 6d895b697c..27c094a9ef 100644 --- a/Core/MIPS/x86/Jit.h +++ b/Core/MIPS/x86/Jit.h @@ -18,6 +18,7 @@ #pragma once #include "../../../Globals.h" +#include "../../../Common/Thunk.h" #include "Asm.h" #if defined(ARM) @@ -120,6 +121,8 @@ private: void CompTriArith(u32 op, void (XEmitter::*arith)(int, const OpArg &, const OpArg &)); void CompShiftImm(u32 op, void (XEmitter::*shift)(int, OpArg, OpArg)); void CompShiftVar(u32 op, void (XEmitter::*shift)(int, OpArg, OpArg)); + void CompITypeMemRead(u32 op, u32 bits, void (XEmitter::*mov)(int, int, X64Reg, OpArg), void *safeFunc); + void CompITypeMemWrite(u32 op, u32 bits, void *safeFunc); void CompFPTriArith(u32 op, void (XEmitter::*arith)(X64Reg reg, OpArg), bool orderMatters); @@ -131,6 +134,7 @@ private: FPURegCache fpr; AsmRoutineManager asm_; + ThunkManager thunks; MIPSState *mips_; };