Jit64Common: Split Jit64Util contents into separate files
Much of Jit64Util consists of essentials, not utilities. Breaking these out into their own files also prevents unrelated includes from being present near other classes. This also makes it easier to find and change certain components of the x86-64 JIT, should it be necessary.
This commit is contained in:
parent
49384208cf
commit
94237b694b
|
@ -207,9 +207,10 @@ if(_M_X86)
|
|||
PowerPC/Jit64/JitRegCache.cpp
|
||||
PowerPC/Jit64/Jit_SystemRegisters.cpp
|
||||
PowerPC/Jit64Common/BlockCache.cpp
|
||||
PowerPC/Jit64Common/EmuCodeBlock.cpp
|
||||
PowerPC/Jit64Common/FarCodeCache.cpp
|
||||
PowerPC/Jit64Common/Jit64AsmCommon.cpp
|
||||
PowerPC/Jit64Common/Jit64Base.cpp
|
||||
PowerPC/Jit64Common/Jit64Util.cpp
|
||||
PowerPC/Jit64Common/TrampolineCache.cpp)
|
||||
elseif(_M_ARM_64)
|
||||
set(SRCS ${SRCS}
|
||||
|
|
|
@ -238,9 +238,10 @@
|
|||
<ClCompile Include="PowerPC\Jit64\Jit_Paired.cpp" />
|
||||
<ClCompile Include="PowerPC\Jit64\Jit_SystemRegisters.cpp" />
|
||||
<ClCompile Include="PowerPC\Jit64Common\BlockCache.cpp" />
|
||||
<ClCompile Include="PowerPC\Jit64Common\EmuCodeBlock.cpp" />
|
||||
<ClCompile Include="PowerPC\Jit64Common\FarCodeCache.cpp" />
|
||||
<ClCompile Include="PowerPC\Jit64Common\Jit64AsmCommon.cpp" />
|
||||
<ClCompile Include="PowerPC\Jit64Common\Jit64Base.cpp" />
|
||||
<ClCompile Include="PowerPC\Jit64Common\Jit64Util.cpp" />
|
||||
<ClCompile Include="PowerPC\Jit64Common\TrampolineCache.cpp" />
|
||||
<ClCompile Include="PowerPC\JitCommon\JitAsmCommon.cpp" />
|
||||
<ClCompile Include="PowerPC\JitCommon\JitBase.cpp" />
|
||||
|
@ -431,10 +432,13 @@
|
|||
<ClInclude Include="PowerPC\JitILCommon\IR.h" />
|
||||
<ClInclude Include="PowerPC\JitILCommon\JitILBase.h" />
|
||||
<ClInclude Include="PowerPC\Jit64Common\BlockCache.h" />
|
||||
<ClInclude Include="PowerPC\Jit64Common\EmuCodeBlock.h" />
|
||||
<ClInclude Include="PowerPC\Jit64Common\FarCodeCache.h" />
|
||||
<ClInclude Include="PowerPC\Jit64Common\Jit64AsmCommon.h" />
|
||||
<ClInclude Include="PowerPC\Jit64Common\Jit64Base.h" />
|
||||
<ClInclude Include="PowerPC\Jit64Common\Jit64Util.h" />
|
||||
<ClInclude Include="PowerPC\Jit64Common\Jit64PowerPCState.h" />
|
||||
<ClInclude Include="PowerPC\Jit64Common\TrampolineCache.h" />
|
||||
<ClInclude Include="PowerPC\Jit64Common\TrampolineInfo.h" />
|
||||
<ClInclude Include="PowerPC\JitCommon\JitAsmCommon.h" />
|
||||
<ClInclude Include="PowerPC\JitCommon\JitBase.h" />
|
||||
<ClInclude Include="PowerPC\JitCommon\JitCache.h" />
|
||||
|
|
|
@ -738,15 +738,18 @@
|
|||
<ClCompile Include="PowerPC\Jit64Common\BlockCache.cpp">
|
||||
<Filter>PowerPC\Jit64Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PowerPC\Jit64Common\EmuCodeBlock.cpp">
|
||||
<Filter>PowerPC\Jit64Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PowerPC\Jit64Common\FarCodeCache.cpp">
|
||||
<Filter>PowerPC\Jit64Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PowerPC\Jit64Common\Jit64AsmCommon.cpp">
|
||||
<Filter>PowerPC\Jit64Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PowerPC\Jit64Common\Jit64Base.cpp">
|
||||
<Filter>PowerPC\Jit64Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PowerPC\Jit64Common\Jit64Util.cpp">
|
||||
<Filter>PowerPC\Jit64Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PowerPC\Jit64Common\TrampolineCache.cpp">
|
||||
<Filter>PowerPC\Jit64Common</Filter>
|
||||
</ClCompile>
|
||||
|
@ -1278,18 +1281,27 @@
|
|||
<ClInclude Include="PowerPC\Jit64Common\BlockCache.h">
|
||||
<Filter>PowerPC\Jit64Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PowerPC\Jit64Common\EmuCodeBlock.h">
|
||||
<Filter>PowerPC\Jit64Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PowerPC\Jit64Common\FarCodeCache.h">
|
||||
<Filter>PowerPC\Jit64Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PowerPC\Jit64Common\Jit64AsmCommon.h">
|
||||
<Filter>PowerPC\Jit64Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PowerPC\Jit64Common\Jit64Base.h">
|
||||
<Filter>PowerPC\Jit64Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PowerPC\Jit64Common\Jit64Util.h">
|
||||
<ClInclude Include="PowerPC\Jit64Common\Jit64PowerPCState.h">
|
||||
<Filter>PowerPC\Jit64Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PowerPC\Jit64Common\TrampolineCache.h">
|
||||
<Filter>PowerPC\Jit64Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PowerPC\Jit64Common\TrampolineInfo.h">
|
||||
<Filter>PowerPC\Jit64Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Analytics.h" />
|
||||
<ClInclude Include="IPC_HLE\WII_IPC_HLE_Device_usb_ven.h">
|
||||
<Filter>IPC HLE %28IOS/Starlet%29\USB</Filter>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "Core/HLE/HLE.h"
|
||||
#include "Core/HW/CPU.h"
|
||||
#include "Core/PowerPC/Gekko.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64Util.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64Base.h"
|
||||
#include "Core/PowerPC/PPCAnalyst.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
|
||||
|
|
|
@ -26,7 +26,9 @@
|
|||
#include "Core/PowerPC/Jit64/Jit64_Tables.h"
|
||||
#include "Core/PowerPC/Jit64/JitAsm.h"
|
||||
#include "Core/PowerPC/Jit64/JitRegCache.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64Util.h"
|
||||
#include "Core/PowerPC/Jit64Common/FarCodeCache.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h"
|
||||
#include "Core/PowerPC/Jit64Common/TrampolineCache.h"
|
||||
#include "Core/PowerPC/JitInterface.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "Core/PowerPC/Profiler.h"
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "Core/HW/CPU.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/PowerPC/Jit64/JitAsm.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
|
||||
using namespace Gen;
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include "Common/x64Emitter.h"
|
||||
#include "Core/PowerPC/Jit64/Jit.h"
|
||||
#include "Core/PowerPC/Jit64/JitRegCache.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64Util.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
|
||||
using namespace Gen;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "Core/CoreTiming.h"
|
||||
#include "Core/PowerPC/Gekko.h"
|
||||
#include "Core/PowerPC/Jit64/JitRegCache.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h"
|
||||
#include "Core/PowerPC/PPCAnalyst.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "Core/Core.h"
|
||||
#include "Core/PowerPC/Jit64/Jit.h"
|
||||
#include "Core/PowerPC/Jit64/JitRegCache.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h"
|
||||
#include "Core/PowerPC/PPCAnalyst.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
|
||||
|
|
|
@ -6,12 +6,13 @@
|
|||
#include <vector>
|
||||
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/CPUDetect.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/MathUtil.h"
|
||||
#include "Common/x64Emitter.h"
|
||||
#include "Core/PowerPC/Jit64/Jit.h"
|
||||
#include "Core/PowerPC/Jit64/JitRegCache.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64Util.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h"
|
||||
#include "Core/PowerPC/PPCAnalyst.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include "Core/HW/DSP.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/PowerPC/Jit64/JitRegCache.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64Util.h"
|
||||
#include "Core/PowerPC/JitInterface.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include "Common/CommonTypes.h"
|
||||
#include "Common/x64Emitter.h"
|
||||
#include "Core/PowerPC/Jit64/JitRegCache.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64Util.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h"
|
||||
|
||||
using namespace Gen;
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "Common/CommonTypes.h"
|
||||
#include "Common/x64Emitter.h"
|
||||
#include "Core/PowerPC/Jit64/JitRegCache.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64Util.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h"
|
||||
#include "Core/PowerPC/JitCommon/JitAsmCommon.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
|
||||
|
|
|
@ -4,12 +4,13 @@
|
|||
|
||||
#include "Core/PowerPC/Jit64/Jit.h"
|
||||
#include "Common/BitSet.h"
|
||||
#include "Common/CPUDetect.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/x64Emitter.h"
|
||||
#include "Core/CoreTiming.h"
|
||||
#include "Core/HW/ProcessorInterface.h"
|
||||
#include "Core/PowerPC/Jit64/JitRegCache.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64Util.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
|
||||
using namespace Gen;
|
||||
|
|
|
@ -1,22 +1,45 @@
|
|||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Copyright 2016 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Core/PowerPC/Jit64Common/Jit64Util.h"
|
||||
#include "Common/BitSet.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/PowerPC/Jit64Common/EmuCodeBlock.h"
|
||||
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/CPUDetect.h"
|
||||
#include "Common/Intrinsics.h"
|
||||
#include "Common/MathUtil.h"
|
||||
#include "Common/x64ABI.h"
|
||||
#include "Common/x64Emitter.h"
|
||||
#include "Core/HW/MMIO.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/PowerPC/Gekko.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64Base.h"
|
||||
#include "Core/PowerPC/Jit64Common/TrampolineCache.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
|
||||
using namespace Gen;
|
||||
|
||||
namespace
|
||||
{
|
||||
OpArg SwapImmediate(int access_size, const OpArg& reg_value)
|
||||
{
|
||||
if (access_size == 32)
|
||||
return Imm32(Common::swap32(reg_value.Imm32()));
|
||||
|
||||
if (access_size == 16)
|
||||
return Imm16(Common::swap16(reg_value.Imm16()));
|
||||
|
||||
return Imm8(reg_value.Imm8());
|
||||
}
|
||||
|
||||
OpArg FixImmediate(int access_size, OpArg arg)
|
||||
{
|
||||
if (arg.IsImm())
|
||||
{
|
||||
arg = access_size == 8 ? arg.AsImm8() : access_size == 16 ? arg.AsImm16() : arg.AsImm32();
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
void EmuCodeBlock::MemoryExceptionCheck()
|
||||
{
|
||||
// TODO: We really should untangle the trampolines, exception handlers and
|
||||
|
@ -47,6 +70,49 @@ void EmuCodeBlock::MemoryExceptionCheck()
|
|||
}
|
||||
}
|
||||
|
||||
void EmuCodeBlock::SwitchToFarCode()
|
||||
{
|
||||
nearcode = GetWritableCodePtr();
|
||||
SetCodePtr(farcode.GetWritableCodePtr());
|
||||
}
|
||||
|
||||
void EmuCodeBlock::SwitchToNearCode()
|
||||
{
|
||||
farcode.SetCodePtr(GetWritableCodePtr());
|
||||
SetCodePtr(nearcode);
|
||||
}
|
||||
|
||||
FixupBranch EmuCodeBlock::CheckIfSafeAddress(const OpArg& reg_value, X64Reg reg_addr,
|
||||
BitSet32 registers_in_use)
|
||||
{
|
||||
registers_in_use[reg_addr] = true;
|
||||
if (reg_value.IsSimpleReg())
|
||||
registers_in_use[reg_value.GetSimpleReg()] = true;
|
||||
|
||||
// Get ourselves a free register; try to pick one that doesn't involve pushing, if we can.
|
||||
X64Reg scratch = RSCRATCH;
|
||||
if (!registers_in_use[RSCRATCH])
|
||||
scratch = RSCRATCH;
|
||||
else if (!registers_in_use[RSCRATCH_EXTRA])
|
||||
scratch = RSCRATCH_EXTRA;
|
||||
else
|
||||
scratch = reg_addr;
|
||||
|
||||
if (scratch == reg_addr)
|
||||
PUSH(scratch);
|
||||
else
|
||||
MOV(32, R(scratch), R(reg_addr));
|
||||
|
||||
// Perform lookup to see if we can use fast path.
|
||||
SHR(32, R(scratch), Imm8(PowerPC::BAT_INDEX_SHIFT));
|
||||
TEST(32, MScaled(scratch, SCALE_4, PtrOffset(&PowerPC::dbat_table[0])), Imm32(2));
|
||||
|
||||
if (scratch == reg_addr)
|
||||
POP(scratch);
|
||||
|
||||
return J_CC(CC_Z, farcode.Enabled());
|
||||
}
|
||||
|
||||
void EmuCodeBlock::UnsafeLoadRegToReg(X64Reg reg_addr, X64Reg reg_value, int accessSize, s32 offset,
|
||||
bool signExtend)
|
||||
{
|
||||
|
@ -63,6 +129,38 @@ void EmuCodeBlock::UnsafeLoadRegToRegNoSwap(X64Reg reg_addr, X64Reg reg_value, i
|
|||
MOVZX(32, accessSize, reg_value, MComplex(RMEM, reg_addr, SCALE_1, offset));
|
||||
}
|
||||
|
||||
void EmuCodeBlock::UnsafeWriteRegToReg(OpArg reg_value, X64Reg reg_addr, int accessSize, s32 offset,
|
||||
bool swap, MovInfo* info)
|
||||
{
|
||||
if (info)
|
||||
{
|
||||
info->address = GetWritableCodePtr();
|
||||
info->nonAtomicSwapStore = false;
|
||||
}
|
||||
|
||||
OpArg dest = MComplex(RMEM, reg_addr, SCALE_1, offset);
|
||||
if (reg_value.IsImm())
|
||||
{
|
||||
if (swap)
|
||||
reg_value = SwapImmediate(accessSize, reg_value);
|
||||
MOV(accessSize, dest, reg_value);
|
||||
}
|
||||
else if (swap)
|
||||
{
|
||||
SwapAndStore(accessSize, dest, reg_value.GetSimpleReg(), info);
|
||||
}
|
||||
else
|
||||
{
|
||||
MOV(accessSize, dest, reg_value);
|
||||
}
|
||||
}
|
||||
|
||||
void EmuCodeBlock::UnsafeWriteRegToReg(Gen::X64Reg reg_value, Gen::X64Reg reg_addr, int accessSize,
|
||||
s32 offset, bool swap, Gen::MovInfo* info)
|
||||
{
|
||||
UnsafeWriteRegToReg(R(reg_value), reg_addr, accessSize, offset, swap, info);
|
||||
}
|
||||
|
||||
bool EmuCodeBlock::UnsafeLoadToReg(X64Reg reg_value, OpArg opAddress, int accessSize, s32 offset,
|
||||
bool signExtend, MovInfo* info)
|
||||
{
|
||||
|
@ -104,6 +202,28 @@ bool EmuCodeBlock::UnsafeLoadToReg(X64Reg reg_value, OpArg opAddress, int access
|
|||
return offsetAddedToAddress;
|
||||
}
|
||||
|
||||
void EmuCodeBlock::UnsafeWriteGatherPipe(int accessSize)
|
||||
{
|
||||
// No need to protect these, they don't touch any state
|
||||
// question - should we inline them instead? Pro: Lose a CALL Con: Code bloat
|
||||
switch (accessSize)
|
||||
{
|
||||
case 8:
|
||||
CALL(jit->GetAsmRoutines()->fifoDirectWrite8);
|
||||
break;
|
||||
case 16:
|
||||
CALL(jit->GetAsmRoutines()->fifoDirectWrite16);
|
||||
break;
|
||||
case 32:
|
||||
CALL(jit->GetAsmRoutines()->fifoDirectWrite32);
|
||||
break;
|
||||
case 64:
|
||||
CALL(jit->GetAsmRoutines()->fifoDirectWrite64);
|
||||
break;
|
||||
}
|
||||
jit->js.fifoBytesSinceCheck += accessSize >> 3;
|
||||
}
|
||||
|
||||
// Visitor that generates code to read a MMIO value.
|
||||
template <typename T>
|
||||
class MMIOReadCodeGenerator : public MMIO::ReadHandlingMethodVisitor<T>
|
||||
|
@ -212,37 +332,6 @@ void EmuCodeBlock::MMIOLoadToReg(MMIO::Mapping* mmio, Gen::X64Reg reg_value,
|
|||
}
|
||||
}
|
||||
|
||||
FixupBranch EmuCodeBlock::CheckIfSafeAddress(const OpArg& reg_value, X64Reg reg_addr,
|
||||
BitSet32 registers_in_use)
|
||||
{
|
||||
registers_in_use[reg_addr] = true;
|
||||
if (reg_value.IsSimpleReg())
|
||||
registers_in_use[reg_value.GetSimpleReg()] = true;
|
||||
|
||||
// Get ourselves a free register; try to pick one that doesn't involve pushing, if we can.
|
||||
X64Reg scratch = RSCRATCH;
|
||||
if (!registers_in_use[RSCRATCH])
|
||||
scratch = RSCRATCH;
|
||||
else if (!registers_in_use[RSCRATCH_EXTRA])
|
||||
scratch = RSCRATCH_EXTRA;
|
||||
else
|
||||
scratch = reg_addr;
|
||||
|
||||
if (scratch == reg_addr)
|
||||
PUSH(scratch);
|
||||
else
|
||||
MOV(32, R(scratch), R(reg_addr));
|
||||
|
||||
// Perform lookup to see if we can use fast path.
|
||||
SHR(32, R(scratch), Imm8(PowerPC::BAT_INDEX_SHIFT));
|
||||
TEST(32, MScaled(scratch, SCALE_4, PtrOffset(&PowerPC::dbat_table[0])), Imm32(2));
|
||||
|
||||
if (scratch == reg_addr)
|
||||
POP(scratch);
|
||||
|
||||
return J_CC(CC_Z, farcode.Enabled());
|
||||
}
|
||||
|
||||
void EmuCodeBlock::SafeLoadToReg(X64Reg reg_value, const Gen::OpArg& opAddress, int accessSize,
|
||||
s32 offset, BitSet32 registersInUse, bool signExtend, int flags)
|
||||
{
|
||||
|
@ -399,119 +488,6 @@ void EmuCodeBlock::SafeLoadToRegImmediate(X64Reg reg_value, u32 address, int acc
|
|||
}
|
||||
}
|
||||
|
||||
static OpArg SwapImmediate(int accessSize, const OpArg& reg_value)
|
||||
{
|
||||
if (accessSize == 32)
|
||||
return Imm32(Common::swap32(reg_value.Imm32()));
|
||||
else if (accessSize == 16)
|
||||
return Imm16(Common::swap16(reg_value.Imm16()));
|
||||
else
|
||||
return Imm8(reg_value.Imm8());
|
||||
}
|
||||
|
||||
void EmuCodeBlock::UnsafeWriteRegToReg(OpArg reg_value, X64Reg reg_addr, int accessSize, s32 offset,
|
||||
bool swap, MovInfo* info)
|
||||
{
|
||||
if (info)
|
||||
{
|
||||
info->address = GetWritableCodePtr();
|
||||
info->nonAtomicSwapStore = false;
|
||||
}
|
||||
|
||||
OpArg dest = MComplex(RMEM, reg_addr, SCALE_1, offset);
|
||||
if (reg_value.IsImm())
|
||||
{
|
||||
if (swap)
|
||||
reg_value = SwapImmediate(accessSize, reg_value);
|
||||
MOV(accessSize, dest, reg_value);
|
||||
}
|
||||
else if (swap)
|
||||
{
|
||||
SwapAndStore(accessSize, dest, reg_value.GetSimpleReg(), info);
|
||||
}
|
||||
else
|
||||
{
|
||||
MOV(accessSize, dest, reg_value);
|
||||
}
|
||||
}
|
||||
|
||||
static OpArg FixImmediate(int accessSize, OpArg arg)
|
||||
{
|
||||
if (arg.IsImm())
|
||||
{
|
||||
arg = accessSize == 8 ? arg.AsImm8() : accessSize == 16 ? arg.AsImm16() : arg.AsImm32();
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
|
||||
void EmuCodeBlock::UnsafeWriteGatherPipe(int accessSize)
|
||||
{
|
||||
// No need to protect these, they don't touch any state
|
||||
// question - should we inline them instead? Pro: Lose a CALL Con: Code bloat
|
||||
switch (accessSize)
|
||||
{
|
||||
case 8:
|
||||
CALL(jit->GetAsmRoutines()->fifoDirectWrite8);
|
||||
break;
|
||||
case 16:
|
||||
CALL(jit->GetAsmRoutines()->fifoDirectWrite16);
|
||||
break;
|
||||
case 32:
|
||||
CALL(jit->GetAsmRoutines()->fifoDirectWrite32);
|
||||
break;
|
||||
case 64:
|
||||
CALL(jit->GetAsmRoutines()->fifoDirectWrite64);
|
||||
break;
|
||||
}
|
||||
jit->js.fifoBytesSinceCheck += accessSize >> 3;
|
||||
}
|
||||
|
||||
bool EmuCodeBlock::WriteToConstAddress(int accessSize, OpArg arg, u32 address,
|
||||
BitSet32 registersInUse)
|
||||
{
|
||||
arg = FixImmediate(accessSize, arg);
|
||||
|
||||
// If we already know the address through constant folding, we can do some
|
||||
// fun tricks...
|
||||
if (jit->jo.optimizeGatherPipe && PowerPC::IsOptimizableGatherPipeWrite(address))
|
||||
{
|
||||
if (!arg.IsSimpleReg(RSCRATCH))
|
||||
MOV(accessSize, R(RSCRATCH), arg);
|
||||
|
||||
UnsafeWriteGatherPipe(accessSize);
|
||||
return false;
|
||||
}
|
||||
else if (PowerPC::IsOptimizableRAMAddress(address))
|
||||
{
|
||||
WriteToConstRamAddress(accessSize, arg, address);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Helps external systems know which instruction triggered the write
|
||||
MOV(32, PPCSTATE(pc), Imm32(jit->js.compilerPC));
|
||||
|
||||
ABI_PushRegistersAndAdjustStack(registersInUse, 0);
|
||||
switch (accessSize)
|
||||
{
|
||||
case 64:
|
||||
ABI_CallFunctionAC(64, PowerPC::Write_U64, arg, address);
|
||||
break;
|
||||
case 32:
|
||||
ABI_CallFunctionAC(32, PowerPC::Write_U32, arg, address);
|
||||
break;
|
||||
case 16:
|
||||
ABI_CallFunctionAC(16, PowerPC::Write_U16, arg, address);
|
||||
break;
|
||||
case 8:
|
||||
ABI_CallFunctionAC(8, PowerPC::Write_U8, arg, address);
|
||||
break;
|
||||
}
|
||||
ABI_PopRegistersAndAdjustStack(registersInUse, 0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void EmuCodeBlock::SafeWriteRegToReg(OpArg reg_value, X64Reg reg_addr, int accessSize, s32 offset,
|
||||
BitSet32 registersInUse, int flags)
|
||||
{
|
||||
|
@ -625,6 +601,63 @@ void EmuCodeBlock::SafeWriteRegToReg(OpArg reg_value, X64Reg reg_addr, int acces
|
|||
}
|
||||
}
|
||||
|
||||
void EmuCodeBlock::SafeWriteRegToReg(Gen::X64Reg reg_value, Gen::X64Reg reg_addr, int accessSize,
|
||||
s32 offset, BitSet32 registersInUse, int flags)
|
||||
{
|
||||
SafeWriteRegToReg(R(reg_value), reg_addr, accessSize, offset, registersInUse, flags);
|
||||
}
|
||||
|
||||
bool EmuCodeBlock::WriteClobbersRegValue(int accessSize, bool swap)
|
||||
{
|
||||
return swap && !cpu_info.bMOVBE && accessSize > 8;
|
||||
}
|
||||
|
||||
bool EmuCodeBlock::WriteToConstAddress(int accessSize, OpArg arg, u32 address,
|
||||
BitSet32 registersInUse)
|
||||
{
|
||||
arg = FixImmediate(accessSize, arg);
|
||||
|
||||
// If we already know the address through constant folding, we can do some
|
||||
// fun tricks...
|
||||
if (jit->jo.optimizeGatherPipe && PowerPC::IsOptimizableGatherPipeWrite(address))
|
||||
{
|
||||
if (!arg.IsSimpleReg(RSCRATCH))
|
||||
MOV(accessSize, R(RSCRATCH), arg);
|
||||
|
||||
UnsafeWriteGatherPipe(accessSize);
|
||||
return false;
|
||||
}
|
||||
else if (PowerPC::IsOptimizableRAMAddress(address))
|
||||
{
|
||||
WriteToConstRamAddress(accessSize, arg, address);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Helps external systems know which instruction triggered the write
|
||||
MOV(32, PPCSTATE(pc), Imm32(jit->js.compilerPC));
|
||||
|
||||
ABI_PushRegistersAndAdjustStack(registersInUse, 0);
|
||||
switch (accessSize)
|
||||
{
|
||||
case 64:
|
||||
ABI_CallFunctionAC(64, PowerPC::Write_U64, arg, address);
|
||||
break;
|
||||
case 32:
|
||||
ABI_CallFunctionAC(32, PowerPC::Write_U32, arg, address);
|
||||
break;
|
||||
case 16:
|
||||
ABI_CallFunctionAC(16, PowerPC::Write_U16, arg, address);
|
||||
break;
|
||||
case 8:
|
||||
ABI_CallFunctionAC(8, PowerPC::Write_U8, arg, address);
|
||||
break;
|
||||
}
|
||||
ABI_PopRegistersAndAdjustStack(registersInUse, 0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void EmuCodeBlock::WriteToConstRamAddress(int accessSize, OpArg arg, u32 address, bool swap)
|
||||
{
|
||||
X64Reg reg;
|
||||
|
@ -653,6 +686,30 @@ void EmuCodeBlock::WriteToConstRamAddress(int accessSize, OpArg arg, u32 address
|
|||
MOV(accessSize, MRegSum(RMEM, RSCRATCH2), R(reg));
|
||||
}
|
||||
|
||||
void EmuCodeBlock::JitGetAndClearCAOV(bool oe)
|
||||
{
|
||||
if (oe)
|
||||
AND(8, PPCSTATE(xer_so_ov), Imm8(~XER_OV_MASK)); // XER.OV = 0
|
||||
SHR(8, PPCSTATE(xer_ca), Imm8(1)); // carry = XER.CA, XER.CA = 0
|
||||
}
|
||||
|
||||
void EmuCodeBlock::JitSetCA()
|
||||
{
|
||||
MOV(8, PPCSTATE(xer_ca), Imm8(1)); // XER.CA = 1
|
||||
}
|
||||
|
||||
// Some testing shows CA is set roughly ~1/3 of the time (relative to clears), so
|
||||
// branchless calculation of CA is probably faster in general.
|
||||
void EmuCodeBlock::JitSetCAIf(CCFlags conditionCode)
|
||||
{
|
||||
SETcc(conditionCode, PPCSTATE(xer_ca));
|
||||
}
|
||||
|
||||
void EmuCodeBlock::JitClearCA()
|
||||
{
|
||||
MOV(8, PPCSTATE(xer_ca), Imm8(0));
|
||||
}
|
||||
|
||||
void EmuCodeBlock::ForceSinglePrecision(X64Reg output, const OpArg& input, bool packed,
|
||||
bool duplicate)
|
||||
{
|
||||
|
@ -1083,30 +1140,6 @@ void EmuCodeBlock::SetFPRF(Gen::X64Reg xmm)
|
|||
OR(32, PPCSTATE(fpscr), R(RSCRATCH));
|
||||
}
|
||||
|
||||
void EmuCodeBlock::JitGetAndClearCAOV(bool oe)
|
||||
{
|
||||
if (oe)
|
||||
AND(8, PPCSTATE(xer_so_ov), Imm8(~XER_OV_MASK)); // XER.OV = 0
|
||||
SHR(8, PPCSTATE(xer_ca), Imm8(1)); // carry = XER.CA, XER.CA = 0
|
||||
}
|
||||
|
||||
void EmuCodeBlock::JitSetCA()
|
||||
{
|
||||
MOV(8, PPCSTATE(xer_ca), Imm8(1)); // XER.CA = 1
|
||||
}
|
||||
|
||||
// Some testing shows CA is set roughly ~1/3 of the time (relative to clears), so
|
||||
// branchless calculation of CA is probably faster in general.
|
||||
void EmuCodeBlock::JitSetCAIf(CCFlags conditionCode)
|
||||
{
|
||||
SETcc(conditionCode, PPCSTATE(xer_ca));
|
||||
}
|
||||
|
||||
void EmuCodeBlock::JitClearCA()
|
||||
{
|
||||
MOV(8, PPCSTATE(xer_ca), Imm8(0));
|
||||
}
|
||||
|
||||
void EmuCodeBlock::Clear()
|
||||
{
|
||||
backPatchInfo.clear();
|
|
@ -1,106 +1,23 @@
|
|||
// Copyright 2010 Dolphin Emulator Project
|
||||
// Copyright 2016 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included./
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "Common/BitSet.h"
|
||||
#include "Common/CPUDetect.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/x64Emitter.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
|
||||
#include "Core/PowerPC/Jit64Common/FarCodeCache.h"
|
||||
#include "Core/PowerPC/Jit64Common/TrampolineInfo.h"
|
||||
|
||||
namespace MMIO
|
||||
{
|
||||
class Mapping;
|
||||
}
|
||||
|
||||
// We offset by 0x80 because the range of one byte memory offsets is
|
||||
// -0x80..0x7f.
|
||||
#define PPCSTATE(x) \
|
||||
MDisp(RPPCSTATE, (int)((char*)&PowerPC::ppcState.x - (char*)&PowerPC::ppcState) - 0x80)
|
||||
// In case you want to disable the ppcstate register:
|
||||
// #define PPCSTATE(x) M(&PowerPC::ppcState.x)
|
||||
#define PPCSTATE_LR PPCSTATE(spr[SPR_LR])
|
||||
#define PPCSTATE_CTR PPCSTATE(spr[SPR_CTR])
|
||||
#define PPCSTATE_SRR0 PPCSTATE(spr[SPR_SRR0])
|
||||
#define PPCSTATE_SRR1 PPCSTATE(spr[SPR_SRR1])
|
||||
|
||||
// A place to throw blocks of code we don't want polluting the cache, e.g. rarely taken
|
||||
// exception branches.
|
||||
class FarCodeCache : public Gen::X64CodeBlock
|
||||
{
|
||||
private:
|
||||
bool m_enabled = false;
|
||||
|
||||
public:
|
||||
bool Enabled() const { return m_enabled; }
|
||||
void Init(int size)
|
||||
{
|
||||
AllocCodeSpace(size);
|
||||
m_enabled = true;
|
||||
}
|
||||
void Shutdown()
|
||||
{
|
||||
FreeCodeSpace();
|
||||
m_enabled = false;
|
||||
}
|
||||
};
|
||||
|
||||
constexpr int CODE_SIZE = 1024 * 1024 * 32;
|
||||
|
||||
// a bit of a hack; the MMU results in a vast amount more code ending up in the far cache,
|
||||
// mostly exception handling, so give it a whole bunch more space if the MMU is on.
|
||||
constexpr int FARCODE_SIZE = 1024 * 1024 * 8;
|
||||
constexpr int FARCODE_SIZE_MMU = 1024 * 1024 * 48;
|
||||
|
||||
// same for the trampoline code cache, because fastmem results in far more backpatches in MMU mode
|
||||
constexpr int TRAMPOLINE_CODE_SIZE = 1024 * 1024 * 8;
|
||||
constexpr int TRAMPOLINE_CODE_SIZE_MMU = 1024 * 1024 * 32;
|
||||
|
||||
// Stores information we need to batch-patch a MOV with a call to the slow read/write path after
|
||||
// it faults. There will be 10s of thousands of these structs live, so be wary of making this too
|
||||
// big.
|
||||
struct TrampolineInfo final
|
||||
{
|
||||
// The start of the store operation that failed -- we will patch a JMP here
|
||||
u8* start;
|
||||
|
||||
// The start + len = end of the store operation (points to the next instruction)
|
||||
u32 len;
|
||||
|
||||
// The PPC PC for the current load/store block
|
||||
u32 pc;
|
||||
|
||||
// Saved because we need these to make the ABI call in the trampoline
|
||||
BitSet32 registersInUse;
|
||||
|
||||
// The MOV operation
|
||||
Gen::X64Reg nonAtomicSwapStoreSrc;
|
||||
|
||||
// src/dest for load/store
|
||||
s32 offset;
|
||||
Gen::X64Reg op_reg;
|
||||
Gen::OpArg op_arg;
|
||||
|
||||
// Original SafeLoadXXX/SafeStoreXXX flags
|
||||
u8 flags;
|
||||
|
||||
// Memory access size (in bytes)
|
||||
u8 accessSize : 4;
|
||||
|
||||
// true if this is a read op vs a write
|
||||
bool read : 1;
|
||||
|
||||
// for read operations, true if needs sign-extension after load
|
||||
bool signExtend : 1;
|
||||
|
||||
// Set to true if we added the offset to the address and need to undo it
|
||||
bool offsetAddedToAddress : 1;
|
||||
};
|
||||
|
||||
// Like XCodeBlock but has some utilities for memory access.
|
||||
class EmuCodeBlock : public Gen::X64CodeBlock
|
||||
{
|
||||
|
@ -111,17 +28,8 @@ public:
|
|||
void MemoryExceptionCheck();
|
||||
|
||||
// Simple functions to switch between near and far code emitting
|
||||
void SwitchToFarCode()
|
||||
{
|
||||
nearcode = GetWritableCodePtr();
|
||||
SetCodePtr(farcode.GetWritableCodePtr());
|
||||
}
|
||||
|
||||
void SwitchToNearCode()
|
||||
{
|
||||
farcode.SetCodePtr(GetWritableCodePtr());
|
||||
SetCodePtr(nearcode);
|
||||
}
|
||||
void SwitchToFarCode();
|
||||
void SwitchToNearCode();
|
||||
|
||||
Gen::FixupBranch CheckIfSafeAddress(const Gen::OpArg& reg_value, Gen::X64Reg reg_addr,
|
||||
BitSet32 registers_in_use);
|
||||
|
@ -133,10 +41,8 @@ public:
|
|||
void UnsafeWriteRegToReg(Gen::OpArg reg_value, Gen::X64Reg reg_addr, int accessSize,
|
||||
s32 offset = 0, bool swap = true, Gen::MovInfo* info = nullptr);
|
||||
void UnsafeWriteRegToReg(Gen::X64Reg reg_value, Gen::X64Reg reg_addr, int accessSize,
|
||||
s32 offset = 0, bool swap = true, Gen::MovInfo* info = nullptr)
|
||||
{
|
||||
UnsafeWriteRegToReg(R(reg_value), reg_addr, accessSize, offset, swap, info);
|
||||
}
|
||||
s32 offset = 0, bool swap = true, Gen::MovInfo* info = nullptr);
|
||||
|
||||
bool UnsafeLoadToReg(Gen::X64Reg reg_value, Gen::OpArg opAddress, int accessSize, s32 offset,
|
||||
bool signExtend, Gen::MovInfo* info = nullptr);
|
||||
void UnsafeWriteGatherPipe(int accessSize);
|
||||
|
@ -169,20 +75,15 @@ public:
|
|||
void SafeWriteRegToReg(Gen::OpArg reg_value, Gen::X64Reg reg_addr, int accessSize, s32 offset,
|
||||
BitSet32 registersInUse, int flags = 0);
|
||||
void SafeWriteRegToReg(Gen::X64Reg reg_value, Gen::X64Reg reg_addr, int accessSize, s32 offset,
|
||||
BitSet32 registersInUse, int flags = 0)
|
||||
{
|
||||
SafeWriteRegToReg(R(reg_value), reg_addr, accessSize, offset, registersInUse, flags);
|
||||
}
|
||||
BitSet32 registersInUse, int flags = 0);
|
||||
|
||||
// applies to safe and unsafe WriteRegToReg
|
||||
bool WriteClobbersRegValue(int accessSize, bool swap)
|
||||
{
|
||||
return swap && !cpu_info.bMOVBE && accessSize > 8;
|
||||
}
|
||||
bool WriteClobbersRegValue(int accessSize, bool swap);
|
||||
|
||||
void WriteToConstRamAddress(int accessSize, Gen::OpArg arg, u32 address, bool swap = true);
|
||||
// returns true if an exception could have been caused
|
||||
bool WriteToConstAddress(int accessSize, Gen::OpArg arg, u32 address, BitSet32 registersInUse);
|
||||
void WriteToConstRamAddress(int accessSize, Gen::OpArg arg, u32 address, bool swap = true);
|
||||
|
||||
void JitGetAndClearCAOV(bool oe);
|
||||
void JitSetCA();
|
||||
void JitSetCAIf(Gen::CCFlags conditionCode);
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright 2016 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Core/PowerPC/Jit64Common/FarCodeCache.h"
|
||||
|
||||
void FarCodeCache::Init(int size)
|
||||
{
|
||||
AllocCodeSpace(size);
|
||||
m_enabled = true;
|
||||
}
|
||||
|
||||
void FarCodeCache::Shutdown()
|
||||
{
|
||||
FreeCodeSpace();
|
||||
m_enabled = false;
|
||||
}
|
||||
|
||||
bool FarCodeCache::Enabled() const
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright 2016 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common/x64Emitter.h"
|
||||
|
||||
// a bit of a hack; the MMU results in a vast amount more code ending up in the far cache,
|
||||
// mostly exception handling, so give it a whole bunch more space if the MMU is on.
|
||||
constexpr int FARCODE_SIZE = 1024 * 1024 * 8;
|
||||
constexpr int FARCODE_SIZE_MMU = 1024 * 1024 * 48;
|
||||
|
||||
// A place to throw blocks of code we don't want polluting the cache, e.g. rarely taken
|
||||
// exception branches.
|
||||
class FarCodeCache : public Gen::X64CodeBlock
|
||||
{
|
||||
public:
|
||||
void Init(int size);
|
||||
void Shutdown();
|
||||
|
||||
bool Enabled() const;
|
||||
|
||||
private:
|
||||
bool m_enabled = false;
|
||||
};
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "Core/PowerPC/Jit64Common/Jit64AsmCommon.h"
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/CPUDetect.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/JitRegister.h"
|
||||
#include "Common/MathUtil.h"
|
||||
|
@ -12,7 +13,7 @@
|
|||
#include "Core/HW/GPFifo.h"
|
||||
#include "Core/PowerPC/Gekko.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64Base.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64Util.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
|
||||
#define QUANTIZED_REGS_TO_SAVE \
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64Util.h"
|
||||
#include "Core/PowerPC/Jit64Common/EmuCodeBlock.h"
|
||||
#include "Core/PowerPC/JitCommon/JitAsmCommon.h"
|
||||
|
||||
enum EQuantizeType : u32;
|
||||
|
|
|
@ -32,6 +32,8 @@ constexpr Gen::X64Reg RMEM = Gen::RBX;
|
|||
// to address as much as possible in a one-byte offset form.
|
||||
constexpr Gen::X64Reg RPPCSTATE = Gen::RBP;
|
||||
|
||||
constexpr int CODE_SIZE = 1024 * 1024 * 32;
|
||||
|
||||
class Jitx86Base : public JitBase, public QuantizedMemoryRoutines
|
||||
{
|
||||
protected:
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright 2010 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included./
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
|
||||
// We offset by 0x80 because the range of one byte memory offsets is
|
||||
// -0x80..0x7f.
|
||||
#define PPCSTATE(x) \
|
||||
MDisp(RPPCSTATE, (int)((char*)&PowerPC::ppcState.x - (char*)&PowerPC::ppcState) - 0x80)
|
||||
// In case you want to disable the ppcstate register:
|
||||
// #define PPCSTATE(x) M(&PowerPC::ppcState.x)
|
||||
#define PPCSTATE_LR PPCSTATE(spr[SPR_LR])
|
||||
#define PPCSTATE_CTR PPCSTATE(spr[SPR_CTR])
|
||||
#define PPCSTATE_SRR0 PPCSTATE(spr[SPR_SRR0])
|
||||
#define PPCSTATE_SRR1 PPCSTATE(spr[SPR_SRR1])
|
|
@ -12,7 +12,8 @@
|
|||
#include "Common/MsgHandler.h"
|
||||
#include "Common/x64Emitter.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64Base.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64Util.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h"
|
||||
#include "Core/PowerPC/Jit64Common/TrampolineInfo.h"
|
||||
#include "Core/PowerPC/JitCommon/JitBase.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
|
||||
|
|
|
@ -5,7 +5,14 @@
|
|||
#pragma once
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64Util.h"
|
||||
#include "Core/PowerPC/Jit64Common/EmuCodeBlock.h"
|
||||
|
||||
struct TrampolineInfo;
|
||||
|
||||
// a bit of a hack; the MMU results in more code ending up in the trampoline cache,
|
||||
// because fastmem results in far more backpatches in MMU mode
|
||||
constexpr int TRAMPOLINE_CODE_SIZE = 1024 * 1024 * 8;
|
||||
constexpr int TRAMPOLINE_CODE_SIZE_MMU = 1024 * 1024 * 32;
|
||||
|
||||
// We need at least this many bytes for backpatching.
|
||||
constexpr int BACKPATCH_SIZE = 5;
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright 2016 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common/BitSet.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/x64Emitter.h"
|
||||
|
||||
// Stores information we need to batch-patch a MOV with a call to the slow read/write path after
|
||||
// it faults. There will be 10s of thousands of these structs live, so be wary of making this too
|
||||
// big.
|
||||
struct TrampolineInfo final
|
||||
{
|
||||
// The start of the store operation that failed -- we will patch a JMP here
|
||||
u8* start;
|
||||
|
||||
// The start + len = end of the store operation (points to the next instruction)
|
||||
u32 len;
|
||||
|
||||
// The PPC PC for the current load/store block
|
||||
u32 pc;
|
||||
|
||||
// Saved because we need these to make the ABI call in the trampoline
|
||||
BitSet32 registersInUse;
|
||||
|
||||
// The MOV operation
|
||||
Gen::X64Reg nonAtomicSwapStoreSrc;
|
||||
|
||||
// src/dest for load/store
|
||||
s32 offset;
|
||||
Gen::X64Reg op_reg;
|
||||
Gen::OpArg op_arg;
|
||||
|
||||
// Original SafeLoadXXX/SafeStoreXXX flags
|
||||
u8 flags;
|
||||
|
||||
// Memory access size (in bytes)
|
||||
u8 accessSize : 4;
|
||||
|
||||
// true if this is a read op vs a write
|
||||
bool read : 1;
|
||||
|
||||
// for read operations, true if needs sign-extension after load
|
||||
bool signExtend : 1;
|
||||
|
||||
// Set to true if we added the offset to the address and need to undo it
|
||||
bool offsetAddedToAddress : 1;
|
||||
};
|
|
@ -39,6 +39,7 @@ The register allocation is linear scan allocation.
|
|||
#include "Core/HW/CPU.h"
|
||||
#include "Core/HW/ProcessorInterface.h"
|
||||
#include "Core/PowerPC/Gekko.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h"
|
||||
#include "Core/PowerPC/Jit64IL/JitIL.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "Core/HLE/HLE.h"
|
||||
#include "Core/HW/CPU.h"
|
||||
#include "Core/PatchEngine.h"
|
||||
#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h"
|
||||
#include "Core/PowerPC/Jit64IL/JitIL.h"
|
||||
#include "Core/PowerPC/Jit64IL/JitIL_Tables.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Core/PowerPC/JitILCommon/JitILBase.h"
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
|
||||
void JitILBase::psq_st(UGeckoInstruction inst)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue