CachedInterpreter: New kind of jit which always fallback to interpreter.
This commit is contained in:
parent
6bcdae616b
commit
1c9b5efb4c
|
@ -171,6 +171,7 @@ set(SRCS ActionReplay.cpp
|
||||||
PowerPC/JitCommon/JitAsmCommon.cpp
|
PowerPC/JitCommon/JitAsmCommon.cpp
|
||||||
PowerPC/JitCommon/JitBase.cpp
|
PowerPC/JitCommon/JitBase.cpp
|
||||||
PowerPC/JitCommon/JitCache.cpp
|
PowerPC/JitCommon/JitCache.cpp
|
||||||
|
PowerPC/CachedInterpreter.cpp
|
||||||
PowerPC/JitILCommon/IR.cpp
|
PowerPC/JitILCommon/IR.cpp
|
||||||
PowerPC/JitILCommon/JitILBase_Branch.cpp
|
PowerPC/JitILCommon/JitILBase_Branch.cpp
|
||||||
PowerPC/JitILCommon/JitILBase_LoadStore.cpp
|
PowerPC/JitILCommon/JitILBase_LoadStore.cpp
|
||||||
|
|
|
@ -242,6 +242,7 @@
|
||||||
<ClCompile Include="PowerPC\JitCommon\JitCache.cpp" />
|
<ClCompile Include="PowerPC\JitCommon\JitCache.cpp" />
|
||||||
<ClCompile Include="PowerPC\JitCommon\Jit_Util.cpp" />
|
<ClCompile Include="PowerPC\JitCommon\Jit_Util.cpp" />
|
||||||
<ClCompile Include="PowerPC\JitCommon\TrampolineCache.cpp" />
|
<ClCompile Include="PowerPC\JitCommon\TrampolineCache.cpp" />
|
||||||
|
<ClCompile Include="PowerPC\CachedInterpreter.cpp" />
|
||||||
<ClCompile Include="PowerPC\JitInterface.cpp" />
|
<ClCompile Include="PowerPC\JitInterface.cpp" />
|
||||||
<ClCompile Include="PowerPC\MMU.cpp" />
|
<ClCompile Include="PowerPC\MMU.cpp" />
|
||||||
<ClCompile Include="PowerPC\PowerPC.cpp" />
|
<ClCompile Include="PowerPC\PowerPC.cpp" />
|
||||||
|
@ -425,6 +426,7 @@
|
||||||
<ClInclude Include="PowerPC\JitCommon\JitCache.h" />
|
<ClInclude Include="PowerPC\JitCommon\JitCache.h" />
|
||||||
<ClInclude Include="PowerPC\JitCommon\Jit_Util.h" />
|
<ClInclude Include="PowerPC\JitCommon\Jit_Util.h" />
|
||||||
<ClInclude Include="PowerPC\JitCommon\TrampolineCache.h" />
|
<ClInclude Include="PowerPC\JitCommon\TrampolineCache.h" />
|
||||||
|
<ClInclude Include="PowerPC\CachedInterpreter.h" />
|
||||||
<ClInclude Include="PowerPC\JitInterface.h" />
|
<ClInclude Include="PowerPC\JitInterface.h" />
|
||||||
<ClInclude Include="PowerPC\PowerPC.h" />
|
<ClInclude Include="PowerPC\PowerPC.h" />
|
||||||
<ClInclude Include="PowerPC\PPCAnalyst.h" />
|
<ClInclude Include="PowerPC\PPCAnalyst.h" />
|
||||||
|
|
|
@ -609,6 +609,9 @@
|
||||||
<ClCompile Include="HW\Wiimote.cpp">
|
<ClCompile Include="HW\Wiimote.cpp">
|
||||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote</Filter>
|
<Filter>HW %28Flipper/Hollywood%29\Wiimote</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="PowerPC\CachedInterpreter.cpp">
|
||||||
|
<Filter>PowerPC</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="PowerPC\JitInterface.cpp">
|
<ClCompile Include="PowerPC\JitInterface.cpp">
|
||||||
<Filter>PowerPC</Filter>
|
<Filter>PowerPC</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -1174,6 +1177,9 @@
|
||||||
<ClInclude Include="PowerPC\Gekko.h">
|
<ClInclude Include="PowerPC\Gekko.h">
|
||||||
<Filter>PowerPC</Filter>
|
<Filter>PowerPC</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="PowerPC\CachedInterpreter.h">
|
||||||
|
<Filter>PowerPC</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="PowerPC\JitInterface.h">
|
<ClInclude Include="PowerPC\JitInterface.h">
|
||||||
<Filter>PowerPC</Filter>
|
<Filter>PowerPC</Filter>
|
||||||
</ClInclude>
|
</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;
|
u32 hex;
|
||||||
|
|
||||||
UGeckoInstruction(u32 _hex) { hex = _hex;}
|
UGeckoInstruction(u32 _hex) : hex(_hex) {}
|
||||||
UGeckoInstruction() { hex = 0;}
|
UGeckoInstruction() : hex(0) {}
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include "Core/ConfigManager.h"
|
#include "Core/ConfigManager.h"
|
||||||
#include "Core/HW/Memmap.h"
|
#include "Core/HW/Memmap.h"
|
||||||
|
#include "Core/PowerPC/CachedInterpreter.h"
|
||||||
#include "Core/PowerPC/JitInterface.h"
|
#include "Core/PowerPC/JitInterface.h"
|
||||||
#include "Core/PowerPC/PowerPC.h"
|
#include "Core/PowerPC/PowerPC.h"
|
||||||
#include "Core/PowerPC/PPCSymbolDB.h"
|
#include "Core/PowerPC/PPCSymbolDB.h"
|
||||||
|
@ -63,6 +64,10 @@ namespace JitInterface
|
||||||
ptr = new JitArm64();
|
ptr = new JitArm64();
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
case PowerPC::CORE_CACHEDINTERPRETER:
|
||||||
|
ptr = new CachedInterpreter();
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
PanicAlert("Unrecognizable cpu_core: %d", core);
|
PanicAlert("Unrecognizable cpu_core: %d", core);
|
||||||
jit = nullptr;
|
jit = nullptr;
|
||||||
|
@ -89,6 +94,9 @@ namespace JitInterface
|
||||||
JitArm64Tables::InitTables();
|
JitArm64Tables::InitTables();
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
case PowerPC::CORE_CACHEDINTERPRETER:
|
||||||
|
// has no tables
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
PanicAlert("Unrecognizable cpu_core: %d", core);
|
PanicAlert("Unrecognizable cpu_core: %d", core);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -27,7 +27,8 @@ enum
|
||||||
CORE_JIT64,
|
CORE_JIT64,
|
||||||
CORE_JITIL64,
|
CORE_JITIL64,
|
||||||
CORE_JITARM,
|
CORE_JITARM,
|
||||||
CORE_JITARM64
|
CORE_JITARM64,
|
||||||
|
CORE_CACHEDINTERPRETER,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum CoreMode
|
enum CoreMode
|
||||||
|
|
|
@ -22,12 +22,13 @@ GeneralConfigPane::GeneralConfigPane(wxWindow* parent, wxWindowID id)
|
||||||
: wxPanel(parent, id)
|
: wxPanel(parent, id)
|
||||||
{
|
{
|
||||||
cpu_cores = {
|
cpu_cores = {
|
||||||
{ 0, _("Interpreter (VERY slow)") },
|
{ PowerPC::CORE_INTERPRETER, _("Interpreter (slowest)") },
|
||||||
|
{ PowerPC::CORE_CACHEDINTERPRETER, _("Cached Interpreter (slower)") },
|
||||||
#ifdef _M_X86_64
|
#ifdef _M_X86_64
|
||||||
{ 1, _("JIT Recompiler (recommended)") },
|
{ PowerPC::CORE_JIT64, _("JIT Recompiler (recommended)") },
|
||||||
{ 2, _("JITIL Recompiler (slower, experimental)") },
|
{ PowerPC::CORE_JITIL64, _("JITIL Recompiler (slow, experimental)") },
|
||||||
#elif defined(_M_ARM_64)
|
#elif defined(_M_ARM_64)
|
||||||
{ 4, _("Arm64 JIT (experimental)") },
|
{ PowerPC::CORE_JITARM64, _("JIT Arm64 (experimental)") },
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue