Merge pull request #4522 from lioncash/jitutil
Jit64Common: Split Jit64Util contents into separate files
This commit is contained in:
commit
10862cd0e8
|
@ -209,9 +209,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" />
|
||||
|
@ -433,10 +434,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" />
|
||||
|
|
|
@ -735,15 +735,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>
|
||||
|
@ -1281,18 +1284,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