diff --git a/Common/ABI.cpp b/Common/ABI.cpp index 3bf8dc41c7..f0489e346d 100644 --- a/Common/ABI.cpp +++ b/Common/ABI.cpp @@ -160,6 +160,16 @@ void XEmitter::ABI_CallFunctionAC(void *func, const Gen::OpArg &arg1, u32 param2 ABI_RestoreStack(2 * 4); } +void XEmitter::ABI_CallFunctionACC(void *func, const Gen::OpArg &arg1, u32 param2, u32 param3) +{ + ABI_AlignStack(3 * 4); + PUSH(32, Imm32(param3)); + PUSH(32, Imm32(param2)); + PUSH(32, arg1); + CALL(func); + ABI_RestoreStack(3 * 4); +} + void XEmitter::ABI_CallFunctionA(void *func, const Gen::OpArg &arg1) { ABI_AlignStack(1 * 4); @@ -404,6 +414,22 @@ void XEmitter::ABI_CallFunctionAC(void *func, const Gen::OpArg &arg1, u32 param2 } } +void XEmitter::ABI_CallFunctionACC(void *func, const Gen::OpArg &arg1, u32 param2, u32 param3) +{ + MOV(32, R(ABI_PARAM1), arg1); + MOV(32, R(ABI_PARAM2), Imm32(param2)); + MOV(64, R(ABI_PARAM3), Imm64(param3)); + 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_CallFunctionA(void *func, const Gen::OpArg &arg1) { if (!arg1.IsSimpleReg(ABI_PARAM1)) diff --git a/Common/x64Emitter.h b/Common/x64Emitter.h index 21a1deaeae..e0b85e6b85 100644 --- a/Common/x64Emitter.h +++ b/Common/x64Emitter.h @@ -656,6 +656,7 @@ public: 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_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); // Pass a register as a paremeter. diff --git a/Core/MIPS/x86/CompLoadStore.cpp b/Core/MIPS/x86/CompLoadStore.cpp index b262b11699..f53338823a 100644 --- a/Core/MIPS/x86/CompLoadStore.cpp +++ b/Core/MIPS/x86/CompLoadStore.cpp @@ -41,13 +41,28 @@ namespace MIPSComp { + static void ReadMemSafe32(u32 addr, int preg, u32 offset) + { + currentMIPS->r[preg] = Memory::Read_U32(addr + offset); + } + + static void ReadMemSafe16(u32 addr, int preg, u32 offset) + { + currentMIPS->r[preg] = Memory::Read_U16(addr + offset); + } + + static void WriteMemSafe32(u32 addr, int preg, u32 offset) + { + Memory::Write_U32(currentMIPS->r[preg], addr + offset); + } + + static void WriteMemSafe16(u32 addr, int preg, u32 offset) + { + Memory::Write_U16(currentMIPS->r[preg], addr + offset); + } + void Jit::Comp_ITypeMem(u32 op) { - if (!g_Config.bFastMemory) - { - DISABLE; - } - int offset = (signed short)(op&0xFFFF); int rt = _RT; int rs = _RS; @@ -60,35 +75,173 @@ 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(); + } + break; + case 36: //R(rt) = ReadMem8 (addr); break; //lbu Comp_Generic(op); return; case 35: //R(rt) = ReadMem32(addr); break; //lw - gpr.Lock(rt, rs); - gpr.BindToRegister(rt, rt == rs, true); + 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, R(EAX), gpr.R(rs)); - AND(32, R(EAX), Imm32(Memory::MEMVIEW32_MASK)); - MOV(32, gpr.R(rt), MDisp(EAX, (u32)Memory::base + offset)); + 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)); + MOV(32, gpr.R(rt), MComplex(RBX, EAX, SCALE_1, offset)); #endif - gpr.UnlockAll(); + 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(); + } 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 - - case 40: - case 41: //WriteMem16(addr, R(rt)); break; //sh 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(); + } + 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);