mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-27 15:30:35 +00:00
Refactor jit safe memory reads without dup code.
But, maybe too automagical...
This commit is contained in:
parent
b7ef3e7bef
commit
3e419f513a
@ -96,222 +96,46 @@ void Jit::Comp_FPULS(u32 op)
|
||||
switch(op >> 26)
|
||||
{
|
||||
case 49: //FI(ft) = Memory::Read_U32(addr); break; //lwc1
|
||||
gpr.Lock(rs);
|
||||
fpr.SpillLock(ft);
|
||||
fpr.BindToRegister(ft, false, true);
|
||||
|
||||
if (gpr.R(rs).IsImm())
|
||||
{
|
||||
void *data = Memory::GetPointer(gpr.R(rs).GetImmValue() + offset);
|
||||
if (data)
|
||||
gpr.Lock(rs);
|
||||
fpr.SpillLock(ft);
|
||||
fpr.BindToRegister(ft, false, true);
|
||||
|
||||
JitSafeMem safe(this, rs, offset);
|
||||
OpArg src;
|
||||
if (safe.PrepareRead(src, (void *) &Memory::Read_U32))
|
||||
MOVSS(fpr.RX(ft), src);
|
||||
if (safe.PrepareSlowRead((void *) &Memory::Read_U32))
|
||||
{
|
||||
#ifdef _M_IX86
|
||||
MOVSS(fpr.RX(ft), M(data));
|
||||
#else
|
||||
MOVSS(fpr.RX(ft), MDisp(RBX, gpr.R(rs).GetImmValue() + offset));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
MOV(32, R(EAX), Imm32(gpr.R(rs).GetImmValue() + offset));
|
||||
ABI_CallFunctionA(thunks.ProtectFunction((void *) &Memory::Read_U32, 1), R(EAX));
|
||||
MOV(32, M((void *)&ssLoadStoreTemp), R(EAX));
|
||||
MOVSS(fpr.RX(ft), M((void *)&ssLoadStoreTemp));
|
||||
|
||||
// Should we check the core state?
|
||||
if (!g_Config.bIgnoreBadMemAccess)
|
||||
{
|
||||
CMP(32, M((void*)&coreState), Imm32(0));
|
||||
FixupBranch skip2 = J_CC(CC_E);
|
||||
MOV(32, M(¤tMIPS->pc), Imm32(js.compilerPC + 4));
|
||||
WriteSyscallExit();
|
||||
SetJumpTarget(skip2);
|
||||
}
|
||||
}
|
||||
safe.WriteFinish();
|
||||
|
||||
gpr.UnlockAll();
|
||||
fpr.ReleaseSpillLocks();
|
||||
}
|
||||
else
|
||||
{
|
||||
// We may not even need to move into EAX as a temporary.
|
||||
X64Reg addr;
|
||||
if (gpr.R(rs).IsSimpleReg())
|
||||
{
|
||||
// TODO: Maybe just add a check if it's away, don't mind copying to EAX instead...
|
||||
gpr.BindToRegister(rs, true, false);
|
||||
addr = gpr.RX(rs);
|
||||
}
|
||||
else
|
||||
{
|
||||
MOV(32, R(EAX), gpr.R(rs));
|
||||
addr = EAX;
|
||||
}
|
||||
|
||||
if (!g_Config.bFastMemory)
|
||||
{
|
||||
// Is it in physical ram?
|
||||
CMP(32, R(addr), Imm32(0x08000000));
|
||||
FixupBranch tooLow = J_CC(CC_L);
|
||||
CMP(32, R(addr), Imm32(0x0A000000));
|
||||
FixupBranch tooHigh = J_CC(CC_GE);
|
||||
|
||||
const u8* safe = GetCodePtr();
|
||||
#ifdef _M_IX86
|
||||
MOVSS(fpr.RX(ft), MDisp(addr, (u32)Memory::base + offset));
|
||||
#else
|
||||
MOVSS(fpr.RX(ft), MComplex(RBX, addr, SCALE_1, offset));
|
||||
#endif
|
||||
|
||||
FixupBranch skip = J();
|
||||
SetJumpTarget(tooLow);
|
||||
SetJumpTarget(tooHigh);
|
||||
|
||||
// Might also be the scratchpad.
|
||||
CMP(32, R(addr), Imm32(0x00010000));
|
||||
FixupBranch tooLow2 = J_CC(CC_L);
|
||||
CMP(32, R(addr), Imm32(0x00014000));
|
||||
J_CC(CC_L, safe);
|
||||
SetJumpTarget(tooLow2);
|
||||
|
||||
LEA(32, EAX, MDisp(addr, offset));
|
||||
ABI_CallFunctionA(thunks.ProtectFunction((void *) &Memory::Read_U32, 1), R(EAX));
|
||||
MOV(32, M((void *)&ssLoadStoreTemp), R(EAX));
|
||||
MOVSS(fpr.RX(ft), M((void *)&ssLoadStoreTemp));
|
||||
|
||||
// Should we check the core state?
|
||||
if (!g_Config.bIgnoreBadMemAccess)
|
||||
{
|
||||
CMP(32, M((void*)&coreState), Imm32(0));
|
||||
FixupBranch skip2 = J_CC(CC_E);
|
||||
MOV(32, M(¤tMIPS->pc), Imm32(js.compilerPC + 4));
|
||||
WriteSyscallExit();
|
||||
SetJumpTarget(skip2);
|
||||
}
|
||||
|
||||
SetJumpTarget(skip);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _M_IX86
|
||||
// Need to modify it, too bad.
|
||||
if (addr != EAX)
|
||||
MOV(32, R(EAX), gpr.R(rs));
|
||||
AND(32, R(EAX), Imm32(Memory::MEMVIEW32_MASK));
|
||||
MOVSS(fpr.RX(ft), MDisp(EAX, (u32)Memory::base + offset));
|
||||
#else
|
||||
MOVSS(fpr.RX(ft), MComplex(RBX, addr, SCALE_1, offset));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
gpr.UnlockAll();
|
||||
fpr.ReleaseSpillLocks();
|
||||
break;
|
||||
case 57: //Memory::Write_U32(FI(ft), addr); break; //swc1
|
||||
gpr.Lock(rs);
|
||||
fpr.SpillLock(ft);
|
||||
fpr.BindToRegister(ft, true, false);
|
||||
|
||||
if (gpr.R(rs).IsImm())
|
||||
{
|
||||
void *data = Memory::GetPointer(gpr.R(rs).GetImmValue() + offset);
|
||||
if (data)
|
||||
gpr.Lock(rs);
|
||||
fpr.SpillLock(ft);
|
||||
fpr.BindToRegister(ft, true, false);
|
||||
|
||||
JitSafeMem safe(this, rs, offset);
|
||||
OpArg dest;
|
||||
if (safe.PrepareWrite(dest))
|
||||
MOVSS(dest, fpr.RX(ft));
|
||||
if (safe.PrepareSlowWrite())
|
||||
{
|
||||
#ifdef _M_IX86
|
||||
MOVSS(M(data), fpr.RX(ft));
|
||||
#else
|
||||
MOVSS(MDisp(RBX, gpr.R(rs).GetImmValue() + offset), fpr.RX(ft));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
MOV(32, R(EAX), Imm32(gpr.R(rs).GetImmValue() + offset));
|
||||
MOVSS(M((void *)&ssLoadStoreTemp), fpr.RX(ft));
|
||||
ABI_CallFunctionAA(thunks.ProtectFunction((void *) &Memory::Write_U32, 2), M((void *)&ssLoadStoreTemp), R(EAX));
|
||||
|
||||
// Should we check the core state?
|
||||
if (!g_Config.bIgnoreBadMemAccess)
|
||||
{
|
||||
CMP(32, M((void*)&coreState), Imm32(0));
|
||||
FixupBranch skip2 = J_CC(CC_E);
|
||||
MOV(32, M(¤tMIPS->pc), Imm32(js.compilerPC + 4));
|
||||
WriteSyscallExit();
|
||||
SetJumpTarget(skip2);
|
||||
}
|
||||
safe.DoSlowWrite((void *) &Memory::Write_U32, M((void *)&ssLoadStoreTemp));
|
||||
}
|
||||
safe.WriteFinish();
|
||||
|
||||
gpr.UnlockAll();
|
||||
fpr.ReleaseSpillLocks();
|
||||
}
|
||||
else
|
||||
{
|
||||
// We may not even need to move into EAX as a temporary.
|
||||
X64Reg addr;
|
||||
if (gpr.R(rs).IsSimpleReg())
|
||||
{
|
||||
// TODO: Maybe just add a check if it's away, don't mind copying to EAX instead...
|
||||
gpr.BindToRegister(rs, true, false);
|
||||
addr = gpr.RX(rs);
|
||||
}
|
||||
else
|
||||
{
|
||||
MOV(32, R(EAX), gpr.R(rs));
|
||||
addr = EAX;
|
||||
}
|
||||
|
||||
if (!g_Config.bFastMemory)
|
||||
{
|
||||
// Is it in physical ram?
|
||||
CMP(32, R(addr), Imm32(0x08000000));
|
||||
FixupBranch tooLow = J_CC(CC_L);
|
||||
CMP(32, R(addr), Imm32(0x0A000000));
|
||||
FixupBranch tooHigh = J_CC(CC_GE);
|
||||
|
||||
const u8* safe = GetCodePtr();
|
||||
#ifdef _M_IX86
|
||||
MOVSS(MDisp(addr, (u32)Memory::base + offset), fpr.RX(ft));
|
||||
#else
|
||||
MOVSS(MComplex(RBX, addr, SCALE_1, offset), fpr.RX(ft));
|
||||
#endif
|
||||
|
||||
FixupBranch skip = J();
|
||||
SetJumpTarget(tooLow);
|
||||
SetJumpTarget(tooHigh);
|
||||
|
||||
// Might also be the scratchpad.
|
||||
CMP(32, R(addr), Imm32(0x00010000));
|
||||
FixupBranch tooLow2 = J_CC(CC_L);
|
||||
CMP(32, R(addr), Imm32(0x00014000));
|
||||
J_CC(CC_L, safe);
|
||||
SetJumpTarget(tooLow2);
|
||||
|
||||
LEA(32, EAX, MDisp(addr, offset));
|
||||
MOVSS(M((void *)&ssLoadStoreTemp), fpr.RX(ft));
|
||||
ABI_CallFunctionAA(thunks.ProtectFunction((void *) &Memory::Write_U32, 2), M((void *)&ssLoadStoreTemp), R(EAX));
|
||||
|
||||
// Should we check the core state?
|
||||
if (!g_Config.bIgnoreBadMemAccess)
|
||||
{
|
||||
CMP(32, M((void*)&coreState), Imm32(0));
|
||||
FixupBranch skip2 = J_CC(CC_E);
|
||||
MOV(32, M(¤tMIPS->pc), Imm32(js.compilerPC + 4));
|
||||
WriteSyscallExit();
|
||||
SetJumpTarget(skip2);
|
||||
}
|
||||
|
||||
SetJumpTarget(skip);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _M_IX86
|
||||
// Need to modify it, too bad.
|
||||
if (addr != EAX)
|
||||
MOV(32, R(EAX), gpr.R(rs));
|
||||
AND(32, R(EAX), Imm32(Memory::MEMVIEW32_MASK));
|
||||
MOVSS(MDisp(EAX, (u32)Memory::base + offset), fpr.RX(ft));
|
||||
#else
|
||||
MOVSS(MComplex(RBX, addr, SCALE_1, offset), fpr.RX(ft));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
gpr.UnlockAll();
|
||||
fpr.ReleaseSpillLocks();
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -51,106 +51,13 @@ namespace MIPSComp
|
||||
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, R(EAX), Imm32(gpr.R(rs).GetImmValue() + offset));
|
||||
ABI_CallFunctionA(thunks.ProtectFunction(safeFunc, 1), R(EAX));
|
||||
(this->*mov)(32, bits, gpr.RX(rt), R(EAX));
|
||||
|
||||
// Should we check the core state?
|
||||
if (!g_Config.bIgnoreBadMemAccess)
|
||||
{
|
||||
CMP(32, M((void*)&coreState), Imm32(0));
|
||||
FixupBranch skip2 = J_CC(CC_E);
|
||||
MOV(32, M(¤tMIPS->pc), Imm32(js.compilerPC + 4));
|
||||
WriteSyscallExit();
|
||||
SetJumpTarget(skip2);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// We may not even need to move into EAX as a temporary.
|
||||
X64Reg addr;
|
||||
if (gpr.R(rs).IsSimpleReg())
|
||||
{
|
||||
// TODO: Maybe just add a check if it's away, don't mind copying to EAX instead...
|
||||
if (rs != rt)
|
||||
gpr.BindToRegister(rs, true, false);
|
||||
addr = gpr.RX(rs);
|
||||
}
|
||||
else
|
||||
{
|
||||
MOV(32, R(EAX), gpr.R(rs));
|
||||
addr = EAX;
|
||||
}
|
||||
|
||||
if (!g_Config.bFastMemory)
|
||||
{
|
||||
// Is it in physical ram?
|
||||
CMP(32, R(addr), Imm32(0x08000000));
|
||||
FixupBranch tooLow = J_CC(CC_L);
|
||||
CMP(32, R(addr), Imm32(0x0A000000));
|
||||
FixupBranch tooHigh = J_CC(CC_GE);
|
||||
|
||||
const u8* safe = GetCodePtr();
|
||||
#ifdef _M_IX86
|
||||
(this->*mov)(32, bits, gpr.RX(rt), MDisp(addr, (u32)Memory::base + offset));
|
||||
#else
|
||||
(this->*mov)(32, bits, gpr.RX(rt), MComplex(RBX, addr, SCALE_1, offset));
|
||||
#endif
|
||||
|
||||
FixupBranch skip = J();
|
||||
SetJumpTarget(tooLow);
|
||||
SetJumpTarget(tooHigh);
|
||||
|
||||
// Might also be the scratchpad.
|
||||
CMP(32, R(addr), Imm32(0x00010000));
|
||||
FixupBranch tooLow2 = J_CC(CC_L);
|
||||
CMP(32, R(addr), Imm32(0x00014000));
|
||||
J_CC(CC_L, safe);
|
||||
SetJumpTarget(tooLow2);
|
||||
|
||||
LEA(32, EAX, MDisp(addr, offset));
|
||||
ABI_CallFunctionA(thunks.ProtectFunction(safeFunc, 1), R(EAX));
|
||||
(this->*mov)(32, bits, gpr.RX(rt), R(EAX));
|
||||
|
||||
// Should we check the core state?
|
||||
if (!g_Config.bIgnoreBadMemAccess)
|
||||
{
|
||||
CMP(32, M((void*)&coreState), Imm32(0));
|
||||
FixupBranch skip2 = J_CC(CC_E);
|
||||
MOV(32, M(¤tMIPS->pc), Imm32(js.compilerPC + 4));
|
||||
WriteSyscallExit();
|
||||
SetJumpTarget(skip2);
|
||||
}
|
||||
|
||||
SetJumpTarget(skip);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _M_IX86
|
||||
// Need to modify it, too bad.
|
||||
if (addr != EAX)
|
||||
MOV(32, R(EAX), gpr.R(rs));
|
||||
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, addr, SCALE_1, offset));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
JitSafeMem safe(this, rs, offset);
|
||||
OpArg src;
|
||||
if (safe.PrepareRead(src, safeFunc))
|
||||
(this->*mov)(32, bits, gpr.RX(rt), src);
|
||||
if (safe.PrepareSlowRead(safeFunc))
|
||||
(this->*mov)(32, bits, gpr.RX(rt), R(EAX));
|
||||
safe.WriteFinish();
|
||||
|
||||
gpr.UnlockAll();
|
||||
}
|
||||
@ -170,129 +77,28 @@ namespace MIPSComp
|
||||
const bool needSwap = bits == 8 && !gpr.R(rt).IsSimpleReg(EDX) && !gpr.R(rt).IsSimpleReg(ECX);
|
||||
if (needSwap)
|
||||
gpr.FlushLockX(EDX);
|
||||
#else
|
||||
const bool needSwap = false;
|
||||
#endif
|
||||
|
||||
if (gpr.R(rs).IsImm())
|
||||
JitSafeMem safe(this, rs, offset);
|
||||
OpArg dest;
|
||||
if (safe.PrepareWrite(dest))
|
||||
{
|
||||
void *data = Memory::GetPointer(gpr.R(rs).GetImmValue() + offset);
|
||||
if (data)
|
||||
if (needSwap)
|
||||
{
|
||||
#ifdef _M_IX86
|
||||
if (needSwap)
|
||||
{
|
||||
MOV(32, R(EDX), gpr.R(rt));
|
||||
MOV(bits, M(data), R(EDX));
|
||||
}
|
||||
else
|
||||
MOV(bits, M(data), gpr.R(rt));
|
||||
#else
|
||||
MOV(bits, MDisp(RBX, gpr.R(rs).GetImmValue() + offset), gpr.R(rt));
|
||||
#endif
|
||||
MOV(32, R(EDX), gpr.R(rt));
|
||||
MOV(bits, dest, R(EDX));
|
||||
}
|
||||
else
|
||||
{
|
||||
MOV(32, R(EAX), Imm32(gpr.R(rs).GetImmValue() + offset));
|
||||
ABI_CallFunctionAA(thunks.ProtectFunction(safeFunc, 2), gpr.R(rt), R(EAX));
|
||||
|
||||
// Should we check the core state?
|
||||
if (!g_Config.bIgnoreBadMemAccess)
|
||||
{
|
||||
CMP(32, M((void*)&coreState), Imm32(0));
|
||||
FixupBranch skip2 = J_CC(CC_E);
|
||||
MOV(32, M(¤tMIPS->pc), Imm32(js.compilerPC + 4));
|
||||
WriteSyscallExit();
|
||||
SetJumpTarget(skip2);
|
||||
}
|
||||
}
|
||||
MOV(bits, dest, gpr.R(rt));
|
||||
}
|
||||
else
|
||||
{
|
||||
// We may not even need to move into EAX as a temporary.
|
||||
X64Reg addr;
|
||||
if (gpr.R(rs).IsSimpleReg())
|
||||
{
|
||||
// TODO: Maybe just add a check if it's away, don't mind copying to EAX instead...
|
||||
if (rs != rt)
|
||||
gpr.BindToRegister(rs, true, false);
|
||||
addr = gpr.RX(rs);
|
||||
}
|
||||
else
|
||||
{
|
||||
MOV(32, R(EAX), gpr.R(rs));
|
||||
addr = EAX;
|
||||
}
|
||||
if (safe.PrepareSlowWrite())
|
||||
safe.DoSlowWrite(safeFunc, gpr.R(rt));
|
||||
safe.WriteFinish();
|
||||
|
||||
if (!g_Config.bFastMemory)
|
||||
{
|
||||
// Is it in physical ram?
|
||||
CMP(32, R(addr), Imm32(0x08000000));
|
||||
FixupBranch tooLow = J_CC(CC_L);
|
||||
CMP(32, R(addr), Imm32(0x0A000000));
|
||||
FixupBranch tooHigh = J_CC(CC_GE);
|
||||
|
||||
const u8* safe = GetCodePtr();
|
||||
#ifdef _M_IX86
|
||||
if (needSwap)
|
||||
{
|
||||
MOV(32, R(EDX), gpr.R(rt));
|
||||
MOV(bits, MDisp(addr, (u32)Memory::base + offset), R(EDX));
|
||||
}
|
||||
else
|
||||
MOV(bits, MDisp(addr, (u32)Memory::base + offset), gpr.R(rt));
|
||||
#else
|
||||
MOV(bits, MComplex(RBX, addr, SCALE_1, offset), gpr.R(rt));
|
||||
#endif
|
||||
|
||||
FixupBranch skip = J();
|
||||
SetJumpTarget(tooLow);
|
||||
SetJumpTarget(tooHigh);
|
||||
|
||||
// Might also be the scratchpad.
|
||||
CMP(32, R(addr), Imm32(0x00010000));
|
||||
FixupBranch tooLow2 = J_CC(CC_L);
|
||||
CMP(32, R(addr), Imm32(0x00014000));
|
||||
J_CC(CC_L, safe);
|
||||
SetJumpTarget(tooLow2);
|
||||
|
||||
LEA(32, EAX, MDisp(addr, offset));
|
||||
ABI_CallFunctionAA(thunks.ProtectFunction(safeFunc, 2), gpr.R(rt), R(EAX));
|
||||
|
||||
// Should we check the core state?
|
||||
if (!g_Config.bIgnoreBadMemAccess)
|
||||
{
|
||||
CMP(32, M((void*)&coreState), Imm32(0));
|
||||
FixupBranch skip2 = J_CC(CC_E);
|
||||
MOV(32, M(¤tMIPS->pc), Imm32(js.compilerPC + 4));
|
||||
WriteSyscallExit();
|
||||
SetJumpTarget(skip2);
|
||||
}
|
||||
|
||||
SetJumpTarget(skip);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _M_IX86
|
||||
// Need to modify it, too bad.
|
||||
if (addr != EAX)
|
||||
MOV(32, R(EAX), gpr.R(rs));
|
||||
AND(32, R(EAX), Imm32(Memory::MEMVIEW32_MASK));
|
||||
if (needSwap)
|
||||
{
|
||||
MOV(32, R(EDX), gpr.R(rt));
|
||||
MOV(bits, MDisp(EAX, (u32)Memory::base + offset), R(EDX));
|
||||
}
|
||||
else
|
||||
MOV(bits, MDisp(EAX, (u32)Memory::base + offset), gpr.R(rt));
|
||||
#else
|
||||
MOV(bits, MComplex(RBX, addr, SCALE_1, offset), gpr.R(rt));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _M_IX86
|
||||
if (needSwap)
|
||||
gpr.UnlockAllX();
|
||||
#endif
|
||||
gpr.UnlockAll();
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <iterator>
|
||||
#include "../../Core.h"
|
||||
#include "../../CoreTiming.h"
|
||||
#include "../../Config.h"
|
||||
#include "../MIPS.h"
|
||||
#include "../MIPSCodeUtils.h"
|
||||
#include "../MIPSInt.h"
|
||||
@ -301,4 +302,197 @@ bool Jit::CheckJitBreakpoint(u32 addr, int downcountOffset)
|
||||
return false;
|
||||
}
|
||||
|
||||
Jit::JitSafeMem::JitSafeMem(Jit *jit, int raddr, s32 offset)
|
||||
: jit_(jit), raddr_(raddr), offset_(offset), needsCheck_(false), needsSkip_(false)
|
||||
{
|
||||
}
|
||||
|
||||
bool Jit::JitSafeMem::PrepareWrite(OpArg &dest)
|
||||
{
|
||||
// If it's an immediate, we can do the write if valid.
|
||||
if (jit_->gpr.IsImmediate(raddr_))
|
||||
{
|
||||
u32 addr = jit_->gpr.GetImmediate32(raddr_) + offset_;
|
||||
if (Memory::IsValidAddress(addr))
|
||||
{
|
||||
#ifdef _M_IX86
|
||||
dest = M(Memory::base + addr);
|
||||
#else
|
||||
dest = MDisp(RBX, addr);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
// Otherwise, we always can do the write (conditionally.)
|
||||
else
|
||||
dest = PrepareMemoryOpArg();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Jit::JitSafeMem::PrepareRead(OpArg &src, void *safeFunc)
|
||||
{
|
||||
if (jit_->gpr.IsImmediate(raddr_))
|
||||
{
|
||||
u32 addr = jit_->gpr.GetImmediate32(raddr_) + offset_;
|
||||
if (Memory::IsValidAddress(addr))
|
||||
{
|
||||
#ifdef _M_IX86
|
||||
src = M(Memory::base + addr);
|
||||
#else
|
||||
src = MDisp(RBX, addr);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else
|
||||
src = PrepareMemoryOpArg();
|
||||
return true;
|
||||
}
|
||||
|
||||
OpArg Jit::JitSafeMem::PrepareMemoryOpArg()
|
||||
{
|
||||
// We may not even need to move into EAX as a temporary.
|
||||
// TODO: Except on x86 in fastmem mode.
|
||||
if (jit_->gpr.R(raddr_).IsSimpleReg())
|
||||
{
|
||||
jit_->gpr.BindToRegister(raddr_, true, false);
|
||||
xaddr_ = jit_->gpr.RX(raddr_);
|
||||
}
|
||||
else
|
||||
{
|
||||
jit_->MOV(32, R(EAX), jit_->gpr.R(raddr_));
|
||||
xaddr_ = EAX;
|
||||
}
|
||||
|
||||
X64Reg xaddrResult = xaddr_;
|
||||
if (!g_Config.bFastMemory)
|
||||
{
|
||||
// Is it in physical ram?
|
||||
jit_->CMP(32, R(xaddr_), Imm32(PSP_GetKernelMemoryBase()));
|
||||
tooLow_ = jit_->J_CC(CC_L);
|
||||
jit_->CMP(32, R(xaddr_), Imm32(PSP_GetUserMemoryEnd()));
|
||||
tooHigh_ = jit_->J_CC(CC_GE);
|
||||
|
||||
// We may need to jump back up here.
|
||||
safe_ = jit_->GetCodePtr();
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _M_IX86
|
||||
// Need to modify it, too bad.
|
||||
if (xaddr_ != EAX)
|
||||
jit_->MOV(32, R(EAX), R(xaddr_));
|
||||
jit_->AND(32, R(EAX), Imm32(Memory::MEMVIEW32_MASK));
|
||||
xaddrResult = EAX;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _M_IX86
|
||||
return MDisp(xaddrResult, (u32) Memory::base + offset_);
|
||||
#else
|
||||
return MComplex(RBX, xaddrResult, SCALE_1, offset_);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Jit::JitSafeMem::PrepareSlowAccess()
|
||||
{
|
||||
// Skip the fast path (which the caller wrote just now.)
|
||||
skip_ = jit_->J();
|
||||
needsSkip_ = true;
|
||||
jit_->SetJumpTarget(tooLow_);
|
||||
jit_->SetJumpTarget(tooHigh_);
|
||||
|
||||
// Might also be the scratchpad.
|
||||
jit_->CMP(32, R(xaddr_), Imm32(PSP_GetScratchpadMemoryBase()));
|
||||
FixupBranch tooLow = jit_->J_CC(CC_L);
|
||||
jit_->CMP(32, R(xaddr_), Imm32(PSP_GetScratchpadMemoryEnd()));
|
||||
jit_->J_CC(CC_L, safe_);
|
||||
jit_->SetJumpTarget(tooLow);
|
||||
}
|
||||
|
||||
bool Jit::JitSafeMem::PrepareSlowWrite()
|
||||
{
|
||||
// If it's immediate, we only need a slow write on invalid.
|
||||
if (jit_->gpr.IsImmediate(raddr_))
|
||||
{
|
||||
u32 addr = jit_->gpr.GetImmediate32(raddr_) + offset_;
|
||||
return !g_Config.bFastMemory && !Memory::IsValidAddress(addr);
|
||||
}
|
||||
|
||||
if (!g_Config.bFastMemory)
|
||||
{
|
||||
PrepareSlowAccess();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void Jit::JitSafeMem::DoSlowWrite(void *safeFunc, const OpArg src)
|
||||
{
|
||||
if (jit_->gpr.IsImmediate(raddr_))
|
||||
{
|
||||
u32 addr = jit_->gpr.GetImmediate32(raddr_) + offset_;
|
||||
jit_->MOV(32, R(EAX), Imm32(addr));
|
||||
}
|
||||
else
|
||||
jit_->LEA(32, EAX, MDisp(xaddr_, offset_));
|
||||
|
||||
jit_->ABI_CallFunctionAA(jit_->thunks.ProtectFunction(safeFunc, 2), src, R(EAX));
|
||||
needsCheck_ = true;
|
||||
}
|
||||
|
||||
bool Jit::JitSafeMem::PrepareSlowRead(void *safeFunc)
|
||||
{
|
||||
if (jit_->gpr.IsImmediate(raddr_))
|
||||
{
|
||||
u32 addr = jit_->gpr.GetImmediate32(raddr_) + offset_;
|
||||
if (!g_Config.bFastMemory)
|
||||
{
|
||||
jit_->MOV(32, R(EAX), Imm32(addr));
|
||||
jit_->ABI_CallFunctionA(jit_->thunks.ProtectFunction(safeFunc, 1), R(EAX));
|
||||
needsCheck_ = true;
|
||||
return true;
|
||||
}
|
||||
// Can't read a bad immediate in fast memory mode.
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!g_Config.bFastMemory)
|
||||
{
|
||||
PrepareSlowAccess();
|
||||
|
||||
jit_->LEA(32, EAX, MDisp(xaddr_, offset_));
|
||||
jit_->ABI_CallFunctionA(jit_->thunks.ProtectFunction(safeFunc, 1), R(EAX));
|
||||
needsCheck_ = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void Jit::JitSafeMem::WriteFinish()
|
||||
{
|
||||
if (needsCheck_)
|
||||
{
|
||||
// Memory::Read_U32/etc. may have tripped coreState.
|
||||
if (!g_Config.bIgnoreBadMemAccess)
|
||||
{
|
||||
jit_->CMP(32, M((void*)&coreState), Imm32(0));
|
||||
FixupBranch skipCheck = jit_->J_CC(CC_E);
|
||||
jit_->MOV(32, M(¤tMIPS->pc), Imm32(jit_->js.compilerPC + 4));
|
||||
jit_->WriteSyscallExit();
|
||||
jit_->SetJumpTarget(skipCheck);
|
||||
}
|
||||
}
|
||||
if (needsSkip_)
|
||||
jit_->SetJumpTarget(skip_);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -183,6 +183,41 @@ private:
|
||||
ThunkManager thunks;
|
||||
|
||||
MIPSState *mips_;
|
||||
|
||||
class JitSafeMem
|
||||
{
|
||||
public:
|
||||
JitSafeMem(Jit *jit, int raddr, s32 offset);
|
||||
|
||||
// Emit code necessary for a memory write, returns true if MOV to dest is needed.
|
||||
bool PrepareWrite(OpArg &dest);
|
||||
// Emit code proceeding a slow write call, returns true if slow write is needed.
|
||||
bool PrepareSlowWrite();
|
||||
// Emit a slow write from src.
|
||||
void DoSlowWrite(void *safeFunc, const OpArg src);
|
||||
|
||||
// Emit code necessary for a memory read, returns true if MOV from src is needed.
|
||||
bool PrepareRead(OpArg &src, void *safeFunc);
|
||||
// Emit code for a slow read call, and returns true if result is in EAX.
|
||||
bool PrepareSlowRead(void *safeFunc);
|
||||
|
||||
// Cleans up final code for the memory access.
|
||||
void WriteFinish();
|
||||
|
||||
private:
|
||||
OpArg PrepareMemoryOpArg();
|
||||
void PrepareSlowAccess();
|
||||
|
||||
Jit *jit_;
|
||||
int raddr_;
|
||||
s32 offset_;
|
||||
bool needsCheck_;
|
||||
bool needsSkip_;
|
||||
X64Reg xaddr_;
|
||||
FixupBranch tooLow_, tooHigh_, skip_;
|
||||
const u8 *safe_;
|
||||
};
|
||||
friend class JitSafeMem;
|
||||
};
|
||||
|
||||
typedef void (Jit::*MIPSCompileFunc)(u32 opcode);
|
||||
|
@ -55,6 +55,8 @@ typedef void (*readFn16)(u16&, const u32);
|
||||
typedef void (*readFn32)(u32&, const u32);
|
||||
typedef void (*readFn64)(u64&, const u32);
|
||||
|
||||
inline u32 PSP_GetScratchpadMemoryBase() { return 0x00010000;}
|
||||
inline u32 PSP_GetScratchpadMemoryEnd() { return 0x00014000;}
|
||||
|
||||
inline u32 PSP_GetKernelMemoryBase() { return 0x08000000;}
|
||||
inline u32 PSP_GetKernelMemoryEnd() { return 0x08400000;}
|
||||
|
Loading…
Reference in New Issue
Block a user