Fastmem writes for x86-64.
This commit is contained in:
parent
18abc33306
commit
2a339c926e
|
@ -411,31 +411,6 @@ void XEmitter::ABI_CallFunctionA(void *func, const Gen::OpArg &arg1)
|
||||||
ABI_RestoreStack(0);
|
ABI_RestoreStack(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void XEmitter::ABI_PushAllCallerSavedRegsAndAdjustStack() {
|
|
||||||
PUSH(RCX);
|
|
||||||
PUSH(RDX);
|
|
||||||
PUSH(RSI);
|
|
||||||
PUSH(RDI);
|
|
||||||
PUSH(R8);
|
|
||||||
PUSH(R9);
|
|
||||||
PUSH(R10);
|
|
||||||
PUSH(R11);
|
|
||||||
PUSH(R11);
|
|
||||||
}
|
|
||||||
|
|
||||||
void XEmitter::ABI_PopAllCallerSavedRegsAndAdjustStack() {
|
|
||||||
POP(R11);
|
|
||||||
POP(R11);
|
|
||||||
POP(R10);
|
|
||||||
POP(R9);
|
|
||||||
POP(R8);
|
|
||||||
POP(RDI);
|
|
||||||
POP(RSI);
|
|
||||||
POP(RDX);
|
|
||||||
POP(RCX);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// Win64 Specific Code
|
// Win64 Specific Code
|
||||||
|
|
||||||
|
|
|
@ -153,6 +153,19 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo *info)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 0x88: // mem <- r8
|
||||||
|
{
|
||||||
|
info->isMemoryWrite = true;
|
||||||
|
if (info->operandSize == 4)
|
||||||
|
{
|
||||||
|
info->operandSize = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 0x89: // mem <- r16/32/64
|
case 0x89: // mem <- r16/32/64
|
||||||
{
|
{
|
||||||
info->isMemoryWrite = true;
|
info->isMemoryWrite = true;
|
||||||
|
|
|
@ -646,12 +646,6 @@ public:
|
||||||
void ABI_PushAllCalleeSavedRegsAndAdjustStack();
|
void ABI_PushAllCalleeSavedRegsAndAdjustStack();
|
||||||
void ABI_PopAllCalleeSavedRegsAndAdjustStack();
|
void ABI_PopAllCalleeSavedRegsAndAdjustStack();
|
||||||
|
|
||||||
// A function that doesn't know anything about it's surroundings, should
|
|
||||||
// be surrounded by these to establish a safe environment, where it can roam free.
|
|
||||||
// An example is a backpatch injected function.
|
|
||||||
void ABI_PushAllCallerSavedRegsAndAdjustStack();
|
|
||||||
void ABI_PopAllCallerSavedRegsAndAdjustStack();
|
|
||||||
|
|
||||||
unsigned int ABI_GetAlignedFrameSize(unsigned int frameSize, bool noProlog = false);
|
unsigned int ABI_GetAlignedFrameSize(unsigned int frameSize, bool noProlog = false);
|
||||||
void ABI_AlignStack(unsigned int frameSize, bool noProlog = false);
|
void ABI_AlignStack(unsigned int frameSize, bool noProlog = false);
|
||||||
void ABI_RestoreStack(unsigned int frameSize, bool noProlog = false);
|
void ABI_RestoreStack(unsigned int frameSize, bool noProlog = false);
|
||||||
|
|
|
@ -209,8 +209,6 @@ void Jit64::stfd(UGeckoInstruction inst)
|
||||||
MOVD_xmm(R(EAX), XMM0);
|
MOVD_xmm(R(EAX), XMM0);
|
||||||
SafeWriteRegToReg(EAX, ABI_PARAM1, 32, 0);
|
SafeWriteRegToReg(EAX, ABI_PARAM1, 32, 0);
|
||||||
|
|
||||||
MOVAPD(XMM0, fpr.R(s));
|
|
||||||
MOVD_xmm(R(EAX), XMM0);
|
|
||||||
LEA(32, ABI_PARAM1, MDisp(gpr.R(a).GetSimpleReg(), offset));
|
LEA(32, ABI_PARAM1, MDisp(gpr.R(a).GetSimpleReg(), offset));
|
||||||
SafeWriteRegToReg(EAX, ABI_PARAM1, 32, 4);
|
SafeWriteRegToReg(EAX, ABI_PARAM1, 32, 4);
|
||||||
|
|
||||||
|
|
|
@ -1322,9 +1322,7 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak
|
||||||
int addr_scale = SCALE_8;
|
int addr_scale = SCALE_8;
|
||||||
#endif
|
#endif
|
||||||
Jit->MOV(32, R(ECX), regLocForInst(RI, getOp1(I)));
|
Jit->MOV(32, R(ECX), regLocForInst(RI, getOp1(I)));
|
||||||
Jit->ABI_AlignStack(0);
|
|
||||||
Jit->CALLptr(MScaled(EDX, addr_scale, (u32)(u64)(((JitIL *)jit)->asm_routines.pairedLoadQuantized)));
|
Jit->CALLptr(MScaled(EDX, addr_scale, (u32)(u64)(((JitIL *)jit)->asm_routines.pairedLoadQuantized)));
|
||||||
Jit->ABI_RestoreStack(0);
|
|
||||||
Jit->MOVAPD(reg, R(XMM0));
|
Jit->MOVAPD(reg, R(XMM0));
|
||||||
RI.fregs[reg] = I;
|
RI.fregs[reg] = I;
|
||||||
regNormalRegClear(RI, I);
|
regNormalRegClear(RI, I);
|
||||||
|
@ -1429,9 +1427,7 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak
|
||||||
#endif
|
#endif
|
||||||
Jit->MOV(32, R(ECX), regLocForInst(RI, getOp2(I)));
|
Jit->MOV(32, R(ECX), regLocForInst(RI, getOp2(I)));
|
||||||
Jit->MOVAPD(XMM0, fregLocForInst(RI, getOp1(I)));
|
Jit->MOVAPD(XMM0, fregLocForInst(RI, getOp1(I)));
|
||||||
Jit->ABI_AlignStack(0);
|
|
||||||
Jit->CALLptr(MScaled(EDX, addr_scale, (u32)(u64)(((JitIL *)jit)->asm_routines.pairedStoreQuantized)));
|
Jit->CALLptr(MScaled(EDX, addr_scale, (u32)(u64)(((JitIL *)jit)->asm_routines.pairedStoreQuantized)));
|
||||||
Jit->ABI_RestoreStack(0);
|
|
||||||
if (RI.IInfo[I - RI.FirstI] & 4)
|
if (RI.IInfo[I - RI.FirstI] & 4)
|
||||||
fregClearInst(RI, getOp1(I));
|
fregClearInst(RI, getOp1(I));
|
||||||
if (RI.IInfo[I - RI.FirstI] & 8)
|
if (RI.IInfo[I - RI.FirstI] & 8)
|
||||||
|
|
|
@ -206,7 +206,7 @@ void CommonAsmRoutines::GenQuantizedStores() {
|
||||||
PACKSSDW(XMM0, R(XMM0));
|
PACKSSDW(XMM0, R(XMM0));
|
||||||
PACKUSWB(XMM0, R(XMM0));
|
PACKUSWB(XMM0, R(XMM0));
|
||||||
MOVD_xmm(R(EAX), XMM0);
|
MOVD_xmm(R(EAX), XMM0);
|
||||||
SafeWriteRegToReg(AX, ECX, 16, 0, false, true);
|
SafeWriteRegToReg(AX, ECX, 16, 0, SAFE_WRITE_NO_SWAP | SAFE_WRITE_NO_PROLOG | SAFE_WRITE_NO_FASTMEM);
|
||||||
|
|
||||||
RET();
|
RET();
|
||||||
|
|
||||||
|
@ -225,7 +225,7 @@ void CommonAsmRoutines::GenQuantizedStores() {
|
||||||
PACKSSWB(XMM0, R(XMM0));
|
PACKSSWB(XMM0, R(XMM0));
|
||||||
MOVD_xmm(R(EAX), XMM0);
|
MOVD_xmm(R(EAX), XMM0);
|
||||||
|
|
||||||
SafeWriteRegToReg(AX, ECX, 16, 0, false, true);
|
SafeWriteRegToReg(AX, ECX, 16, 0, SAFE_WRITE_NO_SWAP | SAFE_WRITE_NO_PROLOG | SAFE_WRITE_NO_FASTMEM);
|
||||||
|
|
||||||
RET();
|
RET();
|
||||||
|
|
||||||
|
@ -251,7 +251,7 @@ void CommonAsmRoutines::GenQuantizedStores() {
|
||||||
MOV(16, R(AX), M((char*)psTemp + 4));
|
MOV(16, R(AX), M((char*)psTemp + 4));
|
||||||
|
|
||||||
BSWAP(32, EAX);
|
BSWAP(32, EAX);
|
||||||
SafeWriteRegToReg(EAX, ECX, 32, 0, false, true);
|
SafeWriteRegToReg(EAX, ECX, 32, 0, SAFE_WRITE_NO_SWAP | SAFE_WRITE_NO_PROLOG | SAFE_WRITE_NO_FASTMEM);
|
||||||
|
|
||||||
RET();
|
RET();
|
||||||
|
|
||||||
|
@ -271,7 +271,7 @@ void CommonAsmRoutines::GenQuantizedStores() {
|
||||||
MOVD_xmm(R(EAX), XMM0);
|
MOVD_xmm(R(EAX), XMM0);
|
||||||
BSWAP(32, EAX);
|
BSWAP(32, EAX);
|
||||||
ROL(32, R(EAX), Imm8(16));
|
ROL(32, R(EAX), Imm8(16));
|
||||||
SafeWriteRegToReg(EAX, ECX, 32, 0, false, true);
|
SafeWriteRegToReg(EAX, ECX, 32, 0, SAFE_WRITE_NO_SWAP | SAFE_WRITE_NO_PROLOG | SAFE_WRITE_NO_FASTMEM);
|
||||||
|
|
||||||
RET();
|
RET();
|
||||||
|
|
||||||
|
@ -295,7 +295,7 @@ void CommonAsmRoutines::GenQuantizedSingleStores() {
|
||||||
|
|
||||||
// Easy!
|
// Easy!
|
||||||
const u8* storeSingleFloat = AlignCode4();
|
const u8* storeSingleFloat = AlignCode4();
|
||||||
SafeWriteFloatToReg(XMM0, ECX);
|
SafeWriteFloatToReg(XMM0, ECX, SAFE_WRITE_NO_FASTMEM);
|
||||||
RET();
|
RET();
|
||||||
/*
|
/*
|
||||||
if (cpu_info.bSSSE3) {
|
if (cpu_info.bSSSE3) {
|
||||||
|
@ -303,11 +303,11 @@ void CommonAsmRoutines::GenQuantizedSingleStores() {
|
||||||
// TODO: SafeWriteFloat
|
// TODO: SafeWriteFloat
|
||||||
MOVSS(M(&psTemp[0]), XMM0);
|
MOVSS(M(&psTemp[0]), XMM0);
|
||||||
MOV(32, R(EAX), M(&psTemp[0]));
|
MOV(32, R(EAX), M(&psTemp[0]));
|
||||||
SafeWriteRegToReg(EAX, ECX, 32, 0, false, true);
|
SafeWriteRegToReg(EAX, ECX, 32, 0, SAFE_WRITE_NO_SWAP | SAFE_WRITE_NO_PROLOG | SAFE_WRITE_NO_FASTMEM);
|
||||||
} else {
|
} else {
|
||||||
MOVSS(M(&psTemp[0]), XMM0);
|
MOVSS(M(&psTemp[0]), XMM0);
|
||||||
MOV(32, R(EAX), M(&psTemp[0]));
|
MOV(32, R(EAX), M(&psTemp[0]));
|
||||||
SafeWriteRegToReg(EAX, ECX, 32, 0, true, true);
|
SafeWriteRegToReg(EAX, ECX, 32, 0, SAFE_WRITE_NO_PROLOG | SAFE_WRITE_NO_FASTMEM);
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
const u8* storeSingleU8 = AlignCode4(); // Used by MKWii
|
const u8* storeSingleU8 = AlignCode4(); // Used by MKWii
|
||||||
|
@ -318,7 +318,7 @@ void CommonAsmRoutines::GenQuantizedSingleStores() {
|
||||||
MAXSS(XMM0, R(XMM1));
|
MAXSS(XMM0, R(XMM1));
|
||||||
MINSS(XMM0, M((void *)&m_255));
|
MINSS(XMM0, M((void *)&m_255));
|
||||||
CVTTSS2SI(EAX, R(XMM0));
|
CVTTSS2SI(EAX, R(XMM0));
|
||||||
SafeWriteRegToReg(AL, ECX, 8, 0, true, true);
|
SafeWriteRegToReg(AL, ECX, 8, 0, SAFE_WRITE_NO_PROLOG | SAFE_WRITE_NO_FASTMEM);
|
||||||
RET();
|
RET();
|
||||||
|
|
||||||
const u8* storeSingleS8 = AlignCode4();
|
const u8* storeSingleS8 = AlignCode4();
|
||||||
|
@ -328,7 +328,7 @@ void CommonAsmRoutines::GenQuantizedSingleStores() {
|
||||||
MAXSS(XMM0, M((void *)&m_m128));
|
MAXSS(XMM0, M((void *)&m_m128));
|
||||||
MINSS(XMM0, M((void *)&m_127));
|
MINSS(XMM0, M((void *)&m_127));
|
||||||
CVTTSS2SI(EAX, R(XMM0));
|
CVTTSS2SI(EAX, R(XMM0));
|
||||||
SafeWriteRegToReg(AL, ECX, 8, 0, true, true);
|
SafeWriteRegToReg(AL, ECX, 8, 0, SAFE_WRITE_NO_PROLOG | SAFE_WRITE_NO_FASTMEM);
|
||||||
RET();
|
RET();
|
||||||
|
|
||||||
const u8* storeSingleU16 = AlignCode4(); // Used by MKWii
|
const u8* storeSingleU16 = AlignCode4(); // Used by MKWii
|
||||||
|
@ -339,7 +339,7 @@ void CommonAsmRoutines::GenQuantizedSingleStores() {
|
||||||
MAXSS(XMM0, R(XMM1));
|
MAXSS(XMM0, R(XMM1));
|
||||||
MINSS(XMM0, M((void *)&m_65535));
|
MINSS(XMM0, M((void *)&m_65535));
|
||||||
CVTTSS2SI(EAX, R(XMM0));
|
CVTTSS2SI(EAX, R(XMM0));
|
||||||
SafeWriteRegToReg(EAX, ECX, 16, 0, true, true);
|
SafeWriteRegToReg(EAX, ECX, 16, 0, SAFE_WRITE_NO_PROLOG | SAFE_WRITE_NO_FASTMEM);
|
||||||
RET();
|
RET();
|
||||||
|
|
||||||
const u8* storeSingleS16 = AlignCode4();
|
const u8* storeSingleS16 = AlignCode4();
|
||||||
|
@ -349,7 +349,7 @@ void CommonAsmRoutines::GenQuantizedSingleStores() {
|
||||||
MAXSS(XMM0, M((void *)&m_m32768));
|
MAXSS(XMM0, M((void *)&m_m32768));
|
||||||
MINSS(XMM0, M((void *)&m_32767));
|
MINSS(XMM0, M((void *)&m_32767));
|
||||||
CVTTSS2SI(EAX, R(XMM0));
|
CVTTSS2SI(EAX, R(XMM0));
|
||||||
SafeWriteRegToReg(EAX, ECX, 16, 0, true, true);
|
SafeWriteRegToReg(EAX, ECX, 16, 0, SAFE_WRITE_NO_PROLOG | SAFE_WRITE_NO_FASTMEM);
|
||||||
RET();
|
RET();
|
||||||
|
|
||||||
singleStoreQuantized = reinterpret_cast<const u8**>(const_cast<u8*>(AlignCode16()));
|
singleStoreQuantized = reinterpret_cast<const u8**>(const_cast<u8*>(AlignCode16()));
|
||||||
|
|
|
@ -67,7 +67,10 @@ const u8 *TrampolineCache::GetReadTrampoline(const InstructionInfo &info)
|
||||||
X64Reg dataReg = (X64Reg)info.regOperandReg;
|
X64Reg dataReg = (X64Reg)info.regOperandReg;
|
||||||
|
|
||||||
// It's a read. Easy.
|
// It's a read. Easy.
|
||||||
ABI_PushAllCallerSavedRegsAndAdjustStack();
|
// It ought to be necessary to align the stack here. Since it seems to not
|
||||||
|
// affect anybody, I'm not going to add it just to be completely safe about
|
||||||
|
// performance.
|
||||||
|
|
||||||
if (addrReg != ABI_PARAM1)
|
if (addrReg != ABI_PARAM1)
|
||||||
MOV(32, R(ABI_PARAM1), R((X64Reg)addrReg));
|
MOV(32, R(ABI_PARAM1), R((X64Reg)addrReg));
|
||||||
if (info.displacement) {
|
if (info.displacement) {
|
||||||
|
@ -87,8 +90,6 @@ const u8 *TrampolineCache::GetReadTrampoline(const InstructionInfo &info)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ABI_PopAllCallerSavedRegsAndAdjustStack();
|
|
||||||
|
|
||||||
if (dataReg != EAX)
|
if (dataReg != EAX)
|
||||||
{
|
{
|
||||||
MOV(32, R(dataReg), R(EAX));
|
MOV(32, R(dataReg), R(EAX));
|
||||||
|
@ -109,32 +110,24 @@ const u8 *TrampolineCache::GetWriteTrampoline(const InstructionInfo &info)
|
||||||
|
|
||||||
#ifdef _M_X64
|
#ifdef _M_X64
|
||||||
X64Reg dataReg = (X64Reg)info.regOperandReg;
|
X64Reg dataReg = (X64Reg)info.regOperandReg;
|
||||||
if (dataReg != EAX)
|
|
||||||
PanicAlert("Backpatch write - not through EAX");
|
|
||||||
|
|
||||||
X64Reg addrReg = (X64Reg)info.scaledReg;
|
X64Reg addrReg = (X64Reg)info.scaledReg;
|
||||||
|
|
||||||
// It's a write. Yay. Remember that we don't have to be super efficient since it's "just" a
|
// It's a write. Yay. Remember that we don't have to be super efficient since it's "just" a
|
||||||
// hardware access - we can take shortcuts.
|
// hardware access - we can take shortcuts.
|
||||||
//if (emAddress == 0xCC008000)
|
// Don't treat FIFO writes specially for now because they require a burst
|
||||||
// PanicAlert("Caught a FIFO write");
|
// check anyway.
|
||||||
CMP(32, R(addrReg), Imm32(0xCC008000));
|
|
||||||
FixupBranch skip_fast = J_CC(CC_NE, false);
|
|
||||||
MOV(32, R(ABI_PARAM1), R((X64Reg)dataReg));
|
|
||||||
CALL((void*)jit->GetAsmRoutines()->fifoDirectWrite32);
|
|
||||||
RET();
|
|
||||||
SetJumpTarget(skip_fast);
|
|
||||||
ABI_PushAllCallerSavedRegsAndAdjustStack();
|
|
||||||
|
|
||||||
|
if (dataReg == ABI_PARAM2)
|
||||||
|
PanicAlert("Incorrect use of SafeWriteRegToReg");
|
||||||
if (addrReg != ABI_PARAM1)
|
if (addrReg != ABI_PARAM1)
|
||||||
{
|
{
|
||||||
MOV(32, R(ABI_PARAM1), R((X64Reg)dataReg));
|
MOV(64, R(ABI_PARAM1), R((X64Reg)dataReg));
|
||||||
MOV(32, R(ABI_PARAM2), R((X64Reg)addrReg));
|
MOV(64, R(ABI_PARAM2), R((X64Reg)addrReg));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MOV(32, R(ABI_PARAM2), R((X64Reg)addrReg));
|
MOV(64, R(ABI_PARAM2), R((X64Reg)addrReg));
|
||||||
MOV(32, R(ABI_PARAM1), R((X64Reg)dataReg));
|
MOV(64, R(ABI_PARAM1), R((X64Reg)dataReg));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.displacement)
|
if (info.displacement)
|
||||||
|
@ -142,13 +135,25 @@ const u8 *TrampolineCache::GetWriteTrampoline(const InstructionInfo &info)
|
||||||
ADD(32, R(ABI_PARAM2), Imm32(info.displacement));
|
ADD(32, R(ABI_PARAM2), Imm32(info.displacement));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SUB(64, R(RSP), Imm8(8));
|
||||||
|
|
||||||
switch (info.operandSize)
|
switch (info.operandSize)
|
||||||
{
|
{
|
||||||
|
case 8:
|
||||||
|
CALL(thunks.ProtectFunction((void *)&Memory::Write_U64, 2));
|
||||||
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
CALL(thunks.ProtectFunction((void *)&Memory::Write_U32, 2));
|
CALL(thunks.ProtectFunction((void *)&Memory::Write_U32, 2));
|
||||||
break;
|
break;
|
||||||
|
case 2:
|
||||||
|
CALL(thunks.ProtectFunction((void *)&Memory::Write_U16, 2));
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
CALL(thunks.ProtectFunction((void *)&Memory::Write_U8, 2));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
ABI_PopAllCallerSavedRegsAndAdjustStack();
|
|
||||||
|
ADD(64, R(RSP), Imm8(8));
|
||||||
RET();
|
RET();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -193,21 +198,35 @@ const u8 *Jitx86Base::BackPatch(u8 *codePtr, u32 emAddress, void *ctx_void)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PanicAlert("BackPatch : Currently only supporting reads."
|
|
||||||
"\n\nAttempted to write to %08x.", emAddress);
|
|
||||||
|
|
||||||
// TODO: special case FIFO writes. Also, support 32-bit mode.
|
// TODO: special case FIFO writes. Also, support 32-bit mode.
|
||||||
// Also, debug this so that it actually works correctly :P
|
// We entered here with a BSWAP-ed register. We'll have to swap it back.
|
||||||
XEmitter emitter(codePtr - 2);
|
u64 *ptr = ContextRN(ctx, info.regOperandReg);
|
||||||
// We know it's EAX so the BSWAP before will be two byte. Overwrite it.
|
int bswapSize = 0;
|
||||||
|
switch (info.operandSize)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
bswapSize = 0;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
bswapSize = 4 + (info.regOperandReg >= 8 ? 1 : 0);
|
||||||
|
*ptr = Common::swap16((u16) *ptr);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
bswapSize = 2 + (info.regOperandReg >= 8 ? 1 : 0);
|
||||||
|
*ptr = Common::swap32((u32) *ptr);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
bswapSize = 3;
|
||||||
|
*ptr = Common::swap64(*ptr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 *start = codePtr - bswapSize;
|
||||||
|
XEmitter emitter(start);
|
||||||
const u8 *trampoline = trampolines.GetWriteTrampoline(info);
|
const u8 *trampoline = trampolines.GetWriteTrampoline(info);
|
||||||
emitter.CALL((void *)trampoline);
|
emitter.CALL((void *)trampoline);
|
||||||
emitter.NOP((int)info.instructionSize - 3);
|
emitter.NOP(codePtr + info.instructionSize - emitter.GetCodePtr());
|
||||||
if (info.instructionSize < 3)
|
return start;
|
||||||
PanicAlert("Instruction too small");
|
|
||||||
// We entered here with a BSWAP-ed EAX. We'll have to swap it back.
|
|
||||||
ctx->CTX_RAX = Common::swap32((u32)ctx->CTX_RAX);
|
|
||||||
return codePtr - 2;
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -223,8 +223,27 @@ void EmuCodeBlock::UnsafeWriteRegToReg(X64Reg reg_value, X64Reg reg_addr, int ac
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroys both arg registers
|
// Destroys both arg registers
|
||||||
void EmuCodeBlock::SafeWriteRegToReg(X64Reg reg_value, X64Reg reg_addr, int accessSize, s32 offset, bool swap, bool noProlog)
|
void EmuCodeBlock::SafeWriteRegToReg(X64Reg reg_value, X64Reg reg_addr, int accessSize, s32 offset, int flags)
|
||||||
{
|
{
|
||||||
|
#if defined(_M_X64)
|
||||||
|
if (!Core::g_CoreStartupParameter.bMMU &&
|
||||||
|
Core::g_CoreStartupParameter.bFastmem &&
|
||||||
|
!(flags & (SAFE_WRITE_NO_SWAP | SAFE_WRITE_NO_FASTMEM))
|
||||||
|
#ifdef ENABLE_MEM_CHECK
|
||||||
|
&& !Core::g_CoreStartupParameter.bEnableDebugging
|
||||||
|
#endif
|
||||||
|
)
|
||||||
|
{
|
||||||
|
UnsafeWriteRegToReg(reg_value, reg_addr, accessSize, offset, !(flags & SAFE_WRITE_NO_SWAP));
|
||||||
|
if (accessSize == 8)
|
||||||
|
{
|
||||||
|
NOP(1);
|
||||||
|
NOP(1);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (offset)
|
if (offset)
|
||||||
ADD(32, R(reg_addr), Imm32((u32)offset));
|
ADD(32, R(reg_addr), Imm32((u32)offset));
|
||||||
|
|
||||||
|
@ -245,6 +264,8 @@ void EmuCodeBlock::SafeWriteRegToReg(X64Reg reg_value, X64Reg reg_addr, int acce
|
||||||
TEST(32, R(reg_addr), Imm32(mem_mask));
|
TEST(32, R(reg_addr), Imm32(mem_mask));
|
||||||
FixupBranch fast = J_CC(CC_Z);
|
FixupBranch fast = J_CC(CC_Z);
|
||||||
MOV(32, M(&PC), Imm32(jit->js.compilerPC)); // Helps external systems know which instruction triggered the write
|
MOV(32, M(&PC), Imm32(jit->js.compilerPC)); // Helps external systems know which instruction triggered the write
|
||||||
|
bool noProlog = flags & SAFE_WRITE_NO_PROLOG;
|
||||||
|
bool swap = !(flags & SAFE_WRITE_NO_SWAP);
|
||||||
switch (accessSize)
|
switch (accessSize)
|
||||||
{
|
{
|
||||||
case 32: ABI_CallFunctionRR(thunks.ProtectFunction(swap ? ((void *)&Memory::Write_U32) : ((void *)&Memory::Write_U32_Swap), 2), reg_value, reg_addr, noProlog); break;
|
case 32: ABI_CallFunctionRR(thunks.ProtectFunction(swap ? ((void *)&Memory::Write_U32) : ((void *)&Memory::Write_U32_Swap), 2), reg_value, reg_addr, noProlog); break;
|
||||||
|
@ -257,7 +278,7 @@ void EmuCodeBlock::SafeWriteRegToReg(X64Reg reg_value, X64Reg reg_addr, int acce
|
||||||
SetJumpTarget(exit);
|
SetJumpTarget(exit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuCodeBlock::SafeWriteFloatToReg(X64Reg xmm_value, X64Reg reg_addr)
|
void EmuCodeBlock::SafeWriteFloatToReg(X64Reg xmm_value, X64Reg reg_addr, int flags)
|
||||||
{
|
{
|
||||||
if (false && cpu_info.bSSSE3) {
|
if (false && cpu_info.bSSSE3) {
|
||||||
// This path should be faster but for some reason it causes errors so I've disabled it.
|
// This path should be faster but for some reason it causes errors so I've disabled it.
|
||||||
|
@ -290,7 +311,7 @@ void EmuCodeBlock::SafeWriteFloatToReg(X64Reg xmm_value, X64Reg reg_addr)
|
||||||
} else {
|
} else {
|
||||||
MOVSS(M(&float_buffer), xmm_value);
|
MOVSS(M(&float_buffer), xmm_value);
|
||||||
MOV(32, R(EAX), M(&float_buffer));
|
MOV(32, R(EAX), M(&float_buffer));
|
||||||
SafeWriteRegToReg(EAX, reg_addr, 32, 0, true);
|
SafeWriteRegToReg(EAX, reg_addr, 32, 0, flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,10 +16,16 @@ public:
|
||||||
void UnsafeWriteRegToReg(Gen::X64Reg reg_value, Gen::X64Reg reg_addr, int accessSize, s32 offset = 0, bool swap = true);
|
void UnsafeWriteRegToReg(Gen::X64Reg reg_value, Gen::X64Reg reg_addr, int accessSize, s32 offset = 0, bool swap = true);
|
||||||
void UnsafeLoadToEAX(const Gen::OpArg & opAddress, int accessSize, s32 offset, bool signExtend);
|
void UnsafeLoadToEAX(const Gen::OpArg & opAddress, int accessSize, s32 offset, bool signExtend);
|
||||||
void SafeLoadToEAX(const Gen::OpArg & opAddress, int accessSize, s32 offset, bool signExtend);
|
void SafeLoadToEAX(const Gen::OpArg & opAddress, int accessSize, s32 offset, bool signExtend);
|
||||||
void SafeWriteRegToReg(Gen::X64Reg reg_value, Gen::X64Reg reg_addr, int accessSize, s32 offset, bool swap = true, bool noProlog = false);
|
enum SafeWriteFlags
|
||||||
|
{
|
||||||
|
SAFE_WRITE_NO_SWAP = 1,
|
||||||
|
SAFE_WRITE_NO_PROLOG = 2,
|
||||||
|
SAFE_WRITE_NO_FASTMEM = 4
|
||||||
|
};
|
||||||
|
void SafeWriteRegToReg(Gen::X64Reg reg_value, Gen::X64Reg reg_addr, int accessSize, s32 offset, int flags = 0);
|
||||||
|
|
||||||
// Trashes both inputs and EAX.
|
// Trashes both inputs and EAX.
|
||||||
void SafeWriteFloatToReg(Gen::X64Reg xmm_value, Gen::X64Reg reg_addr);
|
void SafeWriteFloatToReg(Gen::X64Reg xmm_value, Gen::X64Reg reg_addr, int flags = 0);
|
||||||
|
|
||||||
void WriteToConstRamAddress(int accessSize, const Gen::OpArg& arg, u32 address);
|
void WriteToConstRamAddress(int accessSize, const Gen::OpArg& arg, u32 address);
|
||||||
void WriteFloatToConstRamAddress(const Gen::X64Reg& xmm_reg, u32 address);
|
void WriteFloatToConstRamAddress(const Gen::X64Reg& xmm_reg, u32 address);
|
||||||
|
|
Loading…
Reference in New Issue