Merge pull request #2716 from degasus/jitgeneric
CachedInterpreter: New kind of jit which always fallback to interpreter.
This commit is contained in:
commit
0c4209a0f9
|
@ -171,6 +171,7 @@ set(SRCS ActionReplay.cpp
|
|||
PowerPC/JitCommon/JitAsmCommon.cpp
|
||||
PowerPC/JitCommon/JitBase.cpp
|
||||
PowerPC/JitCommon/JitCache.cpp
|
||||
PowerPC/CachedInterpreter.cpp
|
||||
PowerPC/JitILCommon/IR.cpp
|
||||
PowerPC/JitILCommon/JitILBase_Branch.cpp
|
||||
PowerPC/JitILCommon/JitILBase_LoadStore.cpp
|
||||
|
|
|
@ -242,6 +242,7 @@
|
|||
<ClCompile Include="PowerPC\JitCommon\JitCache.cpp" />
|
||||
<ClCompile Include="PowerPC\JitCommon\Jit_Util.cpp" />
|
||||
<ClCompile Include="PowerPC\JitCommon\TrampolineCache.cpp" />
|
||||
<ClCompile Include="PowerPC\CachedInterpreter.cpp" />
|
||||
<ClCompile Include="PowerPC\JitInterface.cpp" />
|
||||
<ClCompile Include="PowerPC\MMU.cpp" />
|
||||
<ClCompile Include="PowerPC\PowerPC.cpp" />
|
||||
|
@ -425,6 +426,7 @@
|
|||
<ClInclude Include="PowerPC\JitCommon\JitCache.h" />
|
||||
<ClInclude Include="PowerPC\JitCommon\Jit_Util.h" />
|
||||
<ClInclude Include="PowerPC\JitCommon\TrampolineCache.h" />
|
||||
<ClInclude Include="PowerPC\CachedInterpreter.h" />
|
||||
<ClInclude Include="PowerPC\JitInterface.h" />
|
||||
<ClInclude Include="PowerPC\PowerPC.h" />
|
||||
<ClInclude Include="PowerPC\PPCAnalyst.h" />
|
||||
|
|
|
@ -609,6 +609,9 @@
|
|||
<ClCompile Include="HW\Wiimote.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PowerPC\CachedInterpreter.cpp">
|
||||
<Filter>PowerPC</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PowerPC\JitInterface.cpp">
|
||||
<Filter>PowerPC</Filter>
|
||||
</ClCompile>
|
||||
|
@ -1174,6 +1177,9 @@
|
|||
<ClInclude Include="PowerPC\Gekko.h">
|
||||
<Filter>PowerPC</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PowerPC\CachedInterpreter.h">
|
||||
<Filter>PowerPC</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PowerPC\JitInterface.h">
|
||||
<Filter>PowerPC</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
@ -0,0 +1,196 @@
|
|||
// Copyright 2014 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Common/Common.h"
|
||||
|
||||
#include "Core/PowerPC/CachedInterpreter.h"
|
||||
|
||||
void CachedInterpreter::Init()
|
||||
{
|
||||
m_code.reserve(CODE_SIZE / sizeof(Instruction));
|
||||
|
||||
JitBaseBlockCache::Init();
|
||||
|
||||
code_block.m_stats = &js.st;
|
||||
code_block.m_gpa = &js.gpa;
|
||||
code_block.m_fpa = &js.fpa;
|
||||
}
|
||||
|
||||
void CachedInterpreter::Shutdown()
|
||||
{
|
||||
JitBaseBlockCache::Shutdown();
|
||||
}
|
||||
|
||||
void CachedInterpreter::Run()
|
||||
{
|
||||
while (!PowerPC::GetState())
|
||||
{
|
||||
SingleStep();
|
||||
}
|
||||
|
||||
// Let the waiting thread know we are done leaving
|
||||
PowerPC::FinishStateMove();
|
||||
}
|
||||
|
||||
void CachedInterpreter::SingleStep()
|
||||
{
|
||||
int block = GetBlockNumberFromStartAddress(PC);
|
||||
if (block >= 0)
|
||||
{
|
||||
Instruction* code = (Instruction*)GetCompiledCodeFromBlock(block);
|
||||
|
||||
while (true)
|
||||
{
|
||||
switch (code->type)
|
||||
{
|
||||
case Instruction::INSTRUCTION_ABORT:
|
||||
return;
|
||||
|
||||
case Instruction::INSTRUCTION_TYPE_COMMON:
|
||||
code->common_callback(UGeckoInstruction(code->data));
|
||||
code++;
|
||||
break;
|
||||
|
||||
case Instruction::INSTRUCTION_TYPE_CONDITIONAL:
|
||||
bool ret = code->conditional_callback(code->data);
|
||||
code++;
|
||||
if (ret)
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Jit(PC);
|
||||
}
|
||||
|
||||
static void EndBlock(UGeckoInstruction data)
|
||||
{
|
||||
PC = NPC;
|
||||
PowerPC::CheckExceptions();
|
||||
PowerPC::ppcState.downcount -= data.hex;
|
||||
if (PowerPC::ppcState.downcount <= 0)
|
||||
{
|
||||
CoreTiming::Advance();
|
||||
}
|
||||
}
|
||||
|
||||
static void WritePC(UGeckoInstruction data)
|
||||
{
|
||||
PC = data.hex;
|
||||
NPC = data.hex + 4;
|
||||
}
|
||||
|
||||
static bool CheckFPU(u32 data)
|
||||
{
|
||||
UReg_MSR& msr = (UReg_MSR&)MSR;
|
||||
if (!msr.FP)
|
||||
{
|
||||
PC = NPC = data;
|
||||
PowerPC::ppcState.Exceptions |= EXCEPTION_FPU_UNAVAILABLE;
|
||||
PowerPC::CheckExceptions();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CachedInterpreter::Jit(u32 address)
|
||||
{
|
||||
if (m_code.size() >= CODE_SIZE / sizeof(Instruction) - 0x1000 || IsFull() || SConfig::GetInstance().bJITNoBlockCache)
|
||||
{
|
||||
ClearCache();
|
||||
}
|
||||
|
||||
u32 nextPC = analyzer.Analyze(PC, &code_block, &code_buffer, code_buffer.GetSize());
|
||||
if (code_block.m_memory_exception)
|
||||
{
|
||||
// Address of instruction could not be translated
|
||||
NPC = nextPC;
|
||||
PowerPC::ppcState.Exceptions |= EXCEPTION_ISI;
|
||||
PowerPC::CheckExceptions();
|
||||
WARN_LOG(POWERPC, "ISI exception at 0x%08x", nextPC);
|
||||
return;
|
||||
}
|
||||
|
||||
int block_num = AllocateBlock(PC);
|
||||
JitBlock *b = GetBlock(block_num);
|
||||
|
||||
js.blockStart = PC;
|
||||
js.firstFPInstructionFound = false;
|
||||
js.fifoBytesThisBlock = 0;
|
||||
js.downcountAmount = 0;
|
||||
js.curBlock = b;
|
||||
|
||||
PPCAnalyst::CodeOp *ops = code_buffer.codebuffer;
|
||||
|
||||
b->checkedEntry = GetCodePtr();
|
||||
b->normalEntry = GetCodePtr();
|
||||
b->runCount = 0;
|
||||
|
||||
for (u32 i = 0; i < code_block.m_num_instructions; i++)
|
||||
{
|
||||
js.downcountAmount += ops[i].opinfo->numCycles;
|
||||
|
||||
u32 function = HLE::GetFunctionIndex(ops[i].address);
|
||||
if (function != 0)
|
||||
{
|
||||
int type = HLE::GetFunctionTypeByIndex(function);
|
||||
if (type == HLE::HLE_HOOK_START || type == HLE::HLE_HOOK_REPLACE)
|
||||
{
|
||||
int flags = HLE::GetFunctionFlagsByIndex(function);
|
||||
if (HLE::IsEnabled(flags))
|
||||
{
|
||||
m_code.emplace_back(WritePC, ops[i].address);
|
||||
m_code.emplace_back(Interpreter::HLEFunction, ops[i].inst);
|
||||
if (type == HLE::HLE_HOOK_REPLACE)
|
||||
{
|
||||
m_code.emplace_back(EndBlock, js.downcountAmount);
|
||||
m_code.emplace_back();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ops[i].skip)
|
||||
{
|
||||
if ((ops[i].opinfo->flags & FL_USE_FPU) && !js.firstFPInstructionFound)
|
||||
{
|
||||
m_code.emplace_back(CheckFPU, ops[i].address);
|
||||
js.firstFPInstructionFound = true;
|
||||
}
|
||||
|
||||
if (ops[i].opinfo->flags & FL_ENDBLOCK)
|
||||
m_code.emplace_back(WritePC, ops[i].address);
|
||||
m_code.emplace_back(GetInterpreterOp(ops[i].inst), ops[i].inst);
|
||||
if (ops[i].opinfo->flags & FL_ENDBLOCK)
|
||||
m_code.emplace_back(EndBlock, js.downcountAmount);
|
||||
}
|
||||
}
|
||||
if (code_block.m_broken)
|
||||
{
|
||||
m_code.emplace_back(WritePC, nextPC);
|
||||
m_code.emplace_back(EndBlock, js.downcountAmount);
|
||||
}
|
||||
m_code.emplace_back();
|
||||
|
||||
b->codeSize = (u32)(GetCodePtr() - b->checkedEntry);
|
||||
b->originalSize = code_block.m_num_instructions;
|
||||
|
||||
FinalizeBlock(block_num, jo.enableBlocklink, b->checkedEntry);
|
||||
}
|
||||
|
||||
void CachedInterpreter::ClearCache()
|
||||
{
|
||||
m_code.clear();
|
||||
JitBaseBlockCache::Clear();
|
||||
}
|
||||
|
||||
void CachedInterpreter::WriteDestroyBlock(const u8* location, u32 address)
|
||||
{
|
||||
}
|
||||
|
||||
void CachedInterpreter::WriteLinkBlock(u8* location, const u8* address)
|
||||
{
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
// Copyright 2014 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "Core/PowerPC/CPUCoreBase.h"
|
||||
#include "Core/PowerPC/PPCAnalyst.h"
|
||||
#include "Core/PowerPC/JitCommon/JitBase.h"
|
||||
|
||||
class CachedInterpreter : public JitBase, JitBaseBlockCache
|
||||
{
|
||||
public:
|
||||
CachedInterpreter() : code_buffer(32000) {}
|
||||
~CachedInterpreter() {}
|
||||
|
||||
void Init() override;
|
||||
void Shutdown() override;
|
||||
|
||||
bool HandleFault(uintptr_t access_address, SContext* ctx) override { return false; }
|
||||
|
||||
void ClearCache() override;
|
||||
|
||||
void Run() override;
|
||||
void SingleStep() override;
|
||||
|
||||
void Jit(u32 address) override;
|
||||
|
||||
JitBaseBlockCache* GetBlockCache() override { return this; }
|
||||
|
||||
const char* GetName() override
|
||||
{
|
||||
return "Cached Interpreter";
|
||||
}
|
||||
|
||||
void WriteLinkBlock(u8* location, const u8* address) override;
|
||||
|
||||
void WriteDestroyBlock(const u8* location, u32 address) override;
|
||||
|
||||
const CommonAsmRoutinesBase* GetAsmRoutines() override { return nullptr; };
|
||||
|
||||
private:
|
||||
struct Instruction
|
||||
{
|
||||
typedef void (*CommonCallback)(UGeckoInstruction);
|
||||
typedef bool (*ConditionalCallback)(u32 data);
|
||||
|
||||
Instruction() : type(INSTRUCTION_ABORT) {};
|
||||
Instruction(const CommonCallback c, UGeckoInstruction i) : common_callback(c), data(i.hex), type(INSTRUCTION_TYPE_COMMON) {};
|
||||
Instruction(const ConditionalCallback c, u32 d) : conditional_callback(c), data(d), type(INSTRUCTION_TYPE_CONDITIONAL) {};
|
||||
|
||||
union
|
||||
{
|
||||
const CommonCallback common_callback;
|
||||
const ConditionalCallback conditional_callback;
|
||||
|
||||
};
|
||||
u32 data;
|
||||
enum
|
||||
{
|
||||
INSTRUCTION_ABORT,
|
||||
INSTRUCTION_TYPE_COMMON,
|
||||
INSTRUCTION_TYPE_CONDITIONAL,
|
||||
} type;
|
||||
};
|
||||
|
||||
const u8* GetCodePtr() { return (u8*)(m_code.data() + m_code.size()); }
|
||||
|
||||
std::vector<Instruction> m_code;
|
||||
|
||||
PPCAnalyst::CodeBuffer code_buffer;
|
||||
};
|
||||
|
|
@ -17,8 +17,8 @@ union UGeckoInstruction
|
|||
{
|
||||
u32 hex;
|
||||
|
||||
UGeckoInstruction(u32 _hex) { hex = _hex;}
|
||||
UGeckoInstruction() { hex = 0;}
|
||||
UGeckoInstruction(u32 _hex) : hex(_hex) {}
|
||||
UGeckoInstruction() : hex(0) {}
|
||||
|
||||
struct
|
||||
{
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/PowerPC/CachedInterpreter.h"
|
||||
#include "Core/PowerPC/JitInterface.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "Core/PowerPC/PPCSymbolDB.h"
|
||||
|
@ -63,6 +64,10 @@ namespace JitInterface
|
|||
ptr = new JitArm64();
|
||||
break;
|
||||
#endif
|
||||
case PowerPC::CORE_CACHEDINTERPRETER:
|
||||
ptr = new CachedInterpreter();
|
||||
break;
|
||||
|
||||
default:
|
||||
PanicAlert("Unrecognizable cpu_core: %d", core);
|
||||
jit = nullptr;
|
||||
|
@ -89,6 +94,9 @@ namespace JitInterface
|
|||
JitArm64Tables::InitTables();
|
||||
break;
|
||||
#endif
|
||||
case PowerPC::CORE_CACHEDINTERPRETER:
|
||||
// has no tables
|
||||
break;
|
||||
default:
|
||||
PanicAlert("Unrecognizable cpu_core: %d", core);
|
||||
break;
|
||||
|
|
|
@ -27,7 +27,8 @@ enum
|
|||
CORE_JIT64,
|
||||
CORE_JITIL64,
|
||||
CORE_JITARM,
|
||||
CORE_JITARM64
|
||||
CORE_JITARM64,
|
||||
CORE_CACHEDINTERPRETER,
|
||||
};
|
||||
|
||||
enum CoreMode
|
||||
|
|
|
@ -22,12 +22,13 @@ GeneralConfigPane::GeneralConfigPane(wxWindow* parent, wxWindowID id)
|
|||
: wxPanel(parent, id)
|
||||
{
|
||||
cpu_cores = {
|
||||
{ 0, _("Interpreter (VERY slow)") },
|
||||
{ PowerPC::CORE_INTERPRETER, _("Interpreter (slowest)") },
|
||||
{ PowerPC::CORE_CACHEDINTERPRETER, _("Cached Interpreter (slower)") },
|
||||
#ifdef _M_X86_64
|
||||
{ 1, _("JIT Recompiler (recommended)") },
|
||||
{ 2, _("JITIL Recompiler (slower, experimental)") },
|
||||
{ PowerPC::CORE_JIT64, _("JIT Recompiler (recommended)") },
|
||||
{ PowerPC::CORE_JITIL64, _("JITIL Recompiler (slow, experimental)") },
|
||||
#elif defined(_M_ARM_64)
|
||||
{ 4, _("Arm64 JIT (experimental)") },
|
||||
{ PowerPC::CORE_JITARM64, _("JIT Arm64 (experimental)") },
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue