mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-03-12 14:46:49 +01:00
Merge pull request #11677 from AdmiralCurtiss/deglobal-jit
Avoid System::GetInstance() and ppcState global in Jit64 and CachedInterpreter.
This commit is contained in:
commit
6b44947488
@ -20,6 +20,8 @@ struct CachedInterpreter::Instruction
|
|||||||
using CommonCallback = void (*)(UGeckoInstruction);
|
using CommonCallback = void (*)(UGeckoInstruction);
|
||||||
using ConditionalCallback = bool (*)(u32);
|
using ConditionalCallback = bool (*)(u32);
|
||||||
using InterpreterCallback = void (*)(Interpreter&, UGeckoInstruction);
|
using InterpreterCallback = void (*)(Interpreter&, UGeckoInstruction);
|
||||||
|
using CachedInterpreterCallback = void (*)(CachedInterpreter&, UGeckoInstruction);
|
||||||
|
using ConditionalCachedInterpreterCallback = bool (*)(CachedInterpreter&, u32);
|
||||||
|
|
||||||
Instruction() {}
|
Instruction() {}
|
||||||
Instruction(const CommonCallback c, UGeckoInstruction i)
|
Instruction(const CommonCallback c, UGeckoInstruction i)
|
||||||
@ -37,12 +39,25 @@ struct CachedInterpreter::Instruction
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Instruction(const CachedInterpreterCallback c, UGeckoInstruction i)
|
||||||
|
: cached_interpreter_callback(c), data(i.hex), type(Type::CachedInterpreter)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Instruction(const ConditionalCachedInterpreterCallback c, u32 d)
|
||||||
|
: conditional_cached_interpreter_callback(c), data(d),
|
||||||
|
type(Type::ConditionalCachedInterpreter)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
enum class Type
|
enum class Type
|
||||||
{
|
{
|
||||||
Abort,
|
Abort,
|
||||||
Common,
|
Common,
|
||||||
Conditional,
|
Conditional,
|
||||||
Interpreter,
|
Interpreter,
|
||||||
|
CachedInterpreter,
|
||||||
|
ConditionalCachedInterpreter,
|
||||||
};
|
};
|
||||||
|
|
||||||
union
|
union
|
||||||
@ -50,13 +65,17 @@ struct CachedInterpreter::Instruction
|
|||||||
const CommonCallback common_callback = nullptr;
|
const CommonCallback common_callback = nullptr;
|
||||||
const ConditionalCallback conditional_callback;
|
const ConditionalCallback conditional_callback;
|
||||||
const InterpreterCallback interpreter_callback;
|
const InterpreterCallback interpreter_callback;
|
||||||
|
const CachedInterpreterCallback cached_interpreter_callback;
|
||||||
|
const ConditionalCachedInterpreterCallback conditional_cached_interpreter_callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
u32 data = 0;
|
u32 data = 0;
|
||||||
Type type = Type::Abort;
|
Type type = Type::Abort;
|
||||||
};
|
};
|
||||||
|
|
||||||
CachedInterpreter::CachedInterpreter() = default;
|
CachedInterpreter::CachedInterpreter(Core::System& system) : JitBase(system)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
CachedInterpreter::~CachedInterpreter() = default;
|
CachedInterpreter::~CachedInterpreter() = default;
|
||||||
|
|
||||||
@ -89,11 +108,12 @@ void CachedInterpreter::ExecuteOneBlock()
|
|||||||
const u8* normal_entry = m_block_cache.Dispatch();
|
const u8* normal_entry = m_block_cache.Dispatch();
|
||||||
if (!normal_entry)
|
if (!normal_entry)
|
||||||
{
|
{
|
||||||
Jit(PowerPC::ppcState.pc);
|
Jit(m_ppc_state.pc);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Instruction* code = reinterpret_cast<const Instruction*>(normal_entry);
|
const Instruction* code = reinterpret_cast<const Instruction*>(normal_entry);
|
||||||
|
auto& interpreter = m_system.GetInterpreter();
|
||||||
|
|
||||||
for (; code->type != Instruction::Type::Abort; ++code)
|
for (; code->type != Instruction::Type::Abort; ++code)
|
||||||
{
|
{
|
||||||
@ -109,8 +129,16 @@ void CachedInterpreter::ExecuteOneBlock()
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Instruction::Type::Interpreter:
|
case Instruction::Type::Interpreter:
|
||||||
code->interpreter_callback(Core::System::GetInstance().GetInterpreter(),
|
code->interpreter_callback(interpreter, UGeckoInstruction(code->data));
|
||||||
UGeckoInstruction(code->data));
|
break;
|
||||||
|
|
||||||
|
case Instruction::Type::CachedInterpreter:
|
||||||
|
code->cached_interpreter_callback(*this, UGeckoInstruction(code->data));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Instruction::Type::ConditionalCachedInterpreter:
|
||||||
|
if (code->conditional_cached_interpreter_callback(*this, code->data))
|
||||||
|
return;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -123,9 +151,8 @@ void CachedInterpreter::ExecuteOneBlock()
|
|||||||
|
|
||||||
void CachedInterpreter::Run()
|
void CachedInterpreter::Run()
|
||||||
{
|
{
|
||||||
auto& system = Core::System::GetInstance();
|
auto& core_timing = m_system.GetCoreTiming();
|
||||||
auto& core_timing = system.GetCoreTiming();
|
auto& cpu = m_system.GetCPU();
|
||||||
auto& cpu = system.GetCPU();
|
|
||||||
|
|
||||||
const CPU::State* state_ptr = cpu.GetStatePtr();
|
const CPU::State* state_ptr = cpu.GetStatePtr();
|
||||||
while (cpu.GetState() == CPU::State::Running)
|
while (cpu.GetState() == CPU::State::Running)
|
||||||
@ -137,96 +164,103 @@ void CachedInterpreter::Run()
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
ExecuteOneBlock();
|
ExecuteOneBlock();
|
||||||
} while (PowerPC::ppcState.downcount > 0 && *state_ptr == CPU::State::Running);
|
} while (m_ppc_state.downcount > 0 && *state_ptr == CPU::State::Running);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CachedInterpreter::SingleStep()
|
void CachedInterpreter::SingleStep()
|
||||||
{
|
{
|
||||||
// Enter new timing slice
|
// Enter new timing slice
|
||||||
Core::System::GetInstance().GetCoreTiming().Advance();
|
m_system.GetCoreTiming().Advance();
|
||||||
ExecuteOneBlock();
|
ExecuteOneBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void EndBlock(UGeckoInstruction data)
|
void CachedInterpreter::EndBlock(CachedInterpreter& cached_interpreter, UGeckoInstruction data)
|
||||||
{
|
{
|
||||||
PowerPC::ppcState.pc = PowerPC::ppcState.npc;
|
auto& ppc_state = cached_interpreter.m_ppc_state;
|
||||||
PowerPC::ppcState.downcount -= data.hex;
|
ppc_state.pc = ppc_state.npc;
|
||||||
PowerPC::UpdatePerformanceMonitor(data.hex, 0, 0, PowerPC::ppcState);
|
ppc_state.downcount -= data.hex;
|
||||||
|
PowerPC::UpdatePerformanceMonitor(data.hex, 0, 0, ppc_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void UpdateNumLoadStoreInstructions(UGeckoInstruction data)
|
void CachedInterpreter::UpdateNumLoadStoreInstructions(CachedInterpreter& cached_interpreter,
|
||||||
|
UGeckoInstruction data)
|
||||||
{
|
{
|
||||||
PowerPC::UpdatePerformanceMonitor(0, data.hex, 0, PowerPC::ppcState);
|
PowerPC::UpdatePerformanceMonitor(0, data.hex, 0, cached_interpreter.m_ppc_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void UpdateNumFloatingPointInstructions(UGeckoInstruction data)
|
void CachedInterpreter::UpdateNumFloatingPointInstructions(CachedInterpreter& cached_interpreter,
|
||||||
|
UGeckoInstruction data)
|
||||||
{
|
{
|
||||||
PowerPC::UpdatePerformanceMonitor(0, 0, data.hex, PowerPC::ppcState);
|
PowerPC::UpdatePerformanceMonitor(0, 0, data.hex, cached_interpreter.m_ppc_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WritePC(UGeckoInstruction data)
|
void CachedInterpreter::WritePC(CachedInterpreter& cached_interpreter, UGeckoInstruction data)
|
||||||
{
|
{
|
||||||
PowerPC::ppcState.pc = data.hex;
|
auto& ppc_state = cached_interpreter.m_ppc_state;
|
||||||
PowerPC::ppcState.npc = data.hex + 4;
|
ppc_state.pc = data.hex;
|
||||||
|
ppc_state.npc = data.hex + 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WriteBrokenBlockNPC(UGeckoInstruction data)
|
void CachedInterpreter::WriteBrokenBlockNPC(CachedInterpreter& cached_interpreter,
|
||||||
|
UGeckoInstruction data)
|
||||||
{
|
{
|
||||||
PowerPC::ppcState.npc = data.hex;
|
cached_interpreter.m_ppc_state.npc = data.hex;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool CheckFPU(u32 data)
|
bool CachedInterpreter::CheckFPU(CachedInterpreter& cached_interpreter, u32 data)
|
||||||
{
|
{
|
||||||
if (!PowerPC::ppcState.msr.FP)
|
auto& ppc_state = cached_interpreter.m_ppc_state;
|
||||||
|
if (!ppc_state.msr.FP)
|
||||||
{
|
{
|
||||||
PowerPC::ppcState.Exceptions |= EXCEPTION_FPU_UNAVAILABLE;
|
ppc_state.Exceptions |= EXCEPTION_FPU_UNAVAILABLE;
|
||||||
PowerPC::CheckExceptions();
|
PowerPC::CheckExceptions();
|
||||||
PowerPC::ppcState.downcount -= data;
|
ppc_state.downcount -= data;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool CheckDSI(u32 data)
|
bool CachedInterpreter::CheckDSI(CachedInterpreter& cached_interpreter, u32 data)
|
||||||
{
|
{
|
||||||
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
|
auto& ppc_state = cached_interpreter.m_ppc_state;
|
||||||
|
if (ppc_state.Exceptions & EXCEPTION_DSI)
|
||||||
{
|
{
|
||||||
PowerPC::CheckExceptions();
|
PowerPC::CheckExceptions();
|
||||||
PowerPC::ppcState.downcount -= data;
|
ppc_state.downcount -= data;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool CheckProgramException(u32 data)
|
bool CachedInterpreter::CheckProgramException(CachedInterpreter& cached_interpreter, u32 data)
|
||||||
{
|
{
|
||||||
if (PowerPC::ppcState.Exceptions & EXCEPTION_PROGRAM)
|
auto& ppc_state = cached_interpreter.m_ppc_state;
|
||||||
|
if (ppc_state.Exceptions & EXCEPTION_PROGRAM)
|
||||||
{
|
{
|
||||||
PowerPC::CheckExceptions();
|
PowerPC::CheckExceptions();
|
||||||
PowerPC::ppcState.downcount -= data;
|
ppc_state.downcount -= data;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool CheckBreakpoint(u32 data)
|
bool CachedInterpreter::CheckBreakpoint(CachedInterpreter& cached_interpreter, u32 data)
|
||||||
{
|
{
|
||||||
PowerPC::CheckBreakPoints();
|
PowerPC::CheckBreakPoints();
|
||||||
auto& system = Core::System::GetInstance();
|
if (cached_interpreter.m_system.GetCPU().GetState() != CPU::State::Running)
|
||||||
if (system.GetCPU().GetState() != CPU::State::Running)
|
|
||||||
{
|
{
|
||||||
PowerPC::ppcState.downcount -= data;
|
cached_interpreter.m_ppc_state.downcount -= data;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool CheckIdle(u32 idle_pc)
|
bool CachedInterpreter::CheckIdle(CachedInterpreter& cached_interpreter, u32 idle_pc)
|
||||||
{
|
{
|
||||||
if (PowerPC::ppcState.npc == idle_pc)
|
if (cached_interpreter.m_ppc_state.npc == idle_pc)
|
||||||
{
|
{
|
||||||
Core::System::GetInstance().GetCoreTiming().Idle();
|
cached_interpreter.m_system.GetCoreTiming().Idle();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -255,20 +289,20 @@ void CachedInterpreter::Jit(u32 address)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const u32 nextPC =
|
const u32 nextPC =
|
||||||
analyzer.Analyze(PowerPC::ppcState.pc, &code_block, &m_code_buffer, m_code_buffer.size());
|
analyzer.Analyze(m_ppc_state.pc, &code_block, &m_code_buffer, m_code_buffer.size());
|
||||||
if (code_block.m_memory_exception)
|
if (code_block.m_memory_exception)
|
||||||
{
|
{
|
||||||
// Address of instruction could not be translated
|
// Address of instruction could not be translated
|
||||||
PowerPC::ppcState.npc = nextPC;
|
m_ppc_state.npc = nextPC;
|
||||||
PowerPC::ppcState.Exceptions |= EXCEPTION_ISI;
|
m_ppc_state.Exceptions |= EXCEPTION_ISI;
|
||||||
PowerPC::CheckExceptions();
|
PowerPC::CheckExceptions();
|
||||||
WARN_LOG_FMT(POWERPC, "ISI exception at {:#010x}", nextPC);
|
WARN_LOG_FMT(POWERPC, "ISI exception at {:#010x}", nextPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
JitBlock* b = m_block_cache.AllocateBlock(PowerPC::ppcState.pc);
|
JitBlock* b = m_block_cache.AllocateBlock(m_ppc_state.pc);
|
||||||
|
|
||||||
js.blockStart = PowerPC::ppcState.pc;
|
js.blockStart = m_ppc_state.pc;
|
||||||
js.firstFPInstructionFound = false;
|
js.firstFPInstructionFound = false;
|
||||||
js.fifoBytesSinceCheck = 0;
|
js.fifoBytesSinceCheck = 0;
|
||||||
js.downcountAmount = 0;
|
js.downcountAmount = 0;
|
||||||
|
@ -13,7 +13,11 @@
|
|||||||
class CachedInterpreter : public JitBase
|
class CachedInterpreter : public JitBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CachedInterpreter();
|
explicit CachedInterpreter(Core::System& system);
|
||||||
|
CachedInterpreter(const CachedInterpreter&) = delete;
|
||||||
|
CachedInterpreter(CachedInterpreter&&) = delete;
|
||||||
|
CachedInterpreter& operator=(const CachedInterpreter&) = delete;
|
||||||
|
CachedInterpreter& operator=(CachedInterpreter&&) = delete;
|
||||||
~CachedInterpreter();
|
~CachedInterpreter();
|
||||||
|
|
||||||
void Init() override;
|
void Init() override;
|
||||||
@ -39,6 +43,19 @@ private:
|
|||||||
|
|
||||||
bool HandleFunctionHooking(u32 address);
|
bool HandleFunctionHooking(u32 address);
|
||||||
|
|
||||||
|
static void EndBlock(CachedInterpreter& cached_interpreter, UGeckoInstruction data);
|
||||||
|
static void UpdateNumLoadStoreInstructions(CachedInterpreter& cached_interpreter,
|
||||||
|
UGeckoInstruction data);
|
||||||
|
static void UpdateNumFloatingPointInstructions(CachedInterpreter& cached_interpreter,
|
||||||
|
UGeckoInstruction data);
|
||||||
|
static void WritePC(CachedInterpreter& cached_interpreter, UGeckoInstruction data);
|
||||||
|
static void WriteBrokenBlockNPC(CachedInterpreter& cached_interpreter, UGeckoInstruction data);
|
||||||
|
static bool CheckFPU(CachedInterpreter& cached_interpreter, u32 data);
|
||||||
|
static bool CheckDSI(CachedInterpreter& cached_interpreter, u32 data);
|
||||||
|
static bool CheckProgramException(CachedInterpreter& cached_interpreter, u32 data);
|
||||||
|
static bool CheckBreakpoint(CachedInterpreter& cached_interpreter, u32 data);
|
||||||
|
static bool CheckIdle(CachedInterpreter& cached_interpreter, u32 idle_pc);
|
||||||
|
|
||||||
BlockCache m_block_cache{*this};
|
BlockCache m_block_cache{*this};
|
||||||
std::vector<Instruction> m_code;
|
std::vector<Instruction> m_code;
|
||||||
};
|
};
|
||||||
|
@ -116,7 +116,7 @@ using namespace PowerPC;
|
|||||||
and such, but it's currently limited to integer ops only. This can definitely be made better.
|
and such, but it's currently limited to integer ops only. This can definitely be made better.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Jit64::Jit64() : QuantizedMemoryRoutines(*this)
|
Jit64::Jit64(Core::System& system) : JitBase(system), QuantizedMemoryRoutines(*this)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,12 +136,11 @@ bool Jit64::HandleFault(uintptr_t access_address, SContext* ctx)
|
|||||||
// Only instructions that access I/O will get these, and there won't be that
|
// Only instructions that access I/O will get these, and there won't be that
|
||||||
// many of them in a typical program/game.
|
// many of them in a typical program/game.
|
||||||
|
|
||||||
auto& system = Core::System::GetInstance();
|
auto& memory = m_system.GetMemory();
|
||||||
auto& memory = system.GetMemory();
|
|
||||||
|
|
||||||
if (memory.IsAddressInFastmemArea(reinterpret_cast<u8*>(access_address)))
|
if (memory.IsAddressInFastmemArea(reinterpret_cast<u8*>(access_address)))
|
||||||
{
|
{
|
||||||
auto& ppc_state = system.GetPPCState();
|
auto& ppc_state = m_system.GetPPCState();
|
||||||
const uintptr_t memory_base = reinterpret_cast<uintptr_t>(
|
const uintptr_t memory_base = reinterpret_cast<uintptr_t>(
|
||||||
ppc_state.msr.DR ? memory.GetLogicalBase() : memory.GetPhysicalBase());
|
ppc_state.msr.DR ? memory.GetLogicalBase() : memory.GetPhysicalBase());
|
||||||
|
|
||||||
@ -253,8 +252,7 @@ void Jit64::Init()
|
|||||||
{
|
{
|
||||||
EnableBlockLink();
|
EnableBlockLink();
|
||||||
|
|
||||||
auto& system = Core::System::GetInstance();
|
auto& memory = m_system.GetMemory();
|
||||||
auto& memory = system.GetMemory();
|
|
||||||
|
|
||||||
jo.fastmem_arena = m_fastmem_enabled && memory.InitFastmemArena();
|
jo.fastmem_arena = m_fastmem_enabled && memory.InitFastmemArena();
|
||||||
jo.optimizeGatherPipe = true;
|
jo.optimizeGatherPipe = true;
|
||||||
@ -322,8 +320,7 @@ void Jit64::Shutdown()
|
|||||||
{
|
{
|
||||||
FreeCodeSpace();
|
FreeCodeSpace();
|
||||||
|
|
||||||
auto& system = Core::System::GetInstance();
|
auto& memory = m_system.GetMemory();
|
||||||
auto& memory = system.GetMemory();
|
|
||||||
memory.ShutdownFastmemArena();
|
memory.ShutdownFastmemArena();
|
||||||
|
|
||||||
blocks.Shutdown();
|
blocks.Shutdown();
|
||||||
@ -344,7 +341,7 @@ void Jit64::FallBackToInterpreter(UGeckoInstruction inst)
|
|||||||
|
|
||||||
Interpreter::Instruction instr = Interpreter::GetInterpreterOp(inst);
|
Interpreter::Instruction instr = Interpreter::GetInterpreterOp(inst);
|
||||||
ABI_PushRegistersAndAdjustStack({}, 0);
|
ABI_PushRegistersAndAdjustStack({}, 0);
|
||||||
ABI_CallFunctionPC(instr, &Core::System::GetInstance().GetInterpreter(), inst.hex);
|
ABI_CallFunctionPC(instr, &m_system.GetInterpreter(), inst.hex);
|
||||||
ABI_PopRegistersAndAdjustStack({}, 0);
|
ABI_PopRegistersAndAdjustStack({}, 0);
|
||||||
|
|
||||||
// If the instruction wrote to any registers which were marked as discarded,
|
// If the instruction wrote to any registers which were marked as discarded,
|
||||||
@ -404,29 +401,27 @@ void Jit64::DoNothing(UGeckoInstruction _inst)
|
|||||||
// Yup, just don't do anything.
|
// Yup, just don't do anything.
|
||||||
}
|
}
|
||||||
|
|
||||||
static const bool ImHereDebug = false;
|
void Jit64::ImHere(Jit64& jit)
|
||||||
static const bool ImHereLog = false;
|
|
||||||
static std::map<u32, int> been_here;
|
|
||||||
|
|
||||||
static void ImHere()
|
|
||||||
{
|
{
|
||||||
|
auto& ppc_state = jit.m_ppc_state;
|
||||||
static File::IOFile f;
|
static File::IOFile f;
|
||||||
if (ImHereLog)
|
if (jit.m_im_here_log)
|
||||||
{
|
{
|
||||||
if (!f)
|
if (!f)
|
||||||
f.Open("log64.txt", "w");
|
f.Open("log64.txt", "w");
|
||||||
|
|
||||||
f.WriteString(fmt::format("{0:08x}\n", PowerPC::ppcState.pc));
|
f.WriteString(fmt::format("{0:08x}\n", ppc_state.pc));
|
||||||
}
|
}
|
||||||
if (been_here.find(PowerPC::ppcState.pc) != been_here.end())
|
auto& been_here = jit.m_been_here;
|
||||||
|
auto it = been_here.find(ppc_state.pc);
|
||||||
|
if (it != been_here.end())
|
||||||
{
|
{
|
||||||
been_here.find(PowerPC::ppcState.pc)->second++;
|
it->second++;
|
||||||
if ((been_here.find(PowerPC::ppcState.pc)->second) & 1023)
|
if (it->second & 1023)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
INFO_LOG_FMT(DYNA_REC, "I'm here - PC = {:08x} , LR = {:08x}", PowerPC::ppcState.pc,
|
INFO_LOG_FMT(DYNA_REC, "I'm here - PC = {:08x} , LR = {:08x}", ppc_state.pc, LR(ppc_state));
|
||||||
LR(PowerPC::ppcState));
|
been_here[ppc_state.pc] = 1;
|
||||||
been_here[PowerPC::ppcState.pc] = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Jit64::Cleanup()
|
bool Jit64::Cleanup()
|
||||||
@ -440,18 +435,18 @@ bool Jit64::Cleanup()
|
|||||||
CMP(64, R(RSCRATCH), Imm32(GPFifo::GATHER_PIPE_SIZE));
|
CMP(64, R(RSCRATCH), Imm32(GPFifo::GATHER_PIPE_SIZE));
|
||||||
FixupBranch exit = J_CC(CC_L);
|
FixupBranch exit = J_CC(CC_L);
|
||||||
ABI_PushRegistersAndAdjustStack({}, 0);
|
ABI_PushRegistersAndAdjustStack({}, 0);
|
||||||
ABI_CallFunctionP(GPFifo::UpdateGatherPipe, &Core::System::GetInstance().GetGPFifo());
|
ABI_CallFunctionP(GPFifo::UpdateGatherPipe, &m_system.GetGPFifo());
|
||||||
ABI_PopRegistersAndAdjustStack({}, 0);
|
ABI_PopRegistersAndAdjustStack({}, 0);
|
||||||
SetJumpTarget(exit);
|
SetJumpTarget(exit);
|
||||||
did_something = true;
|
did_something = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SPEED HACK: MMCR0/MMCR1 should be checked at run-time, not at compile time.
|
// SPEED HACK: MMCR0/MMCR1 should be checked at run-time, not at compile time.
|
||||||
if (MMCR0(PowerPC::ppcState).Hex || MMCR1(PowerPC::ppcState).Hex)
|
if (MMCR0(m_ppc_state).Hex || MMCR1(m_ppc_state).Hex)
|
||||||
{
|
{
|
||||||
ABI_PushRegistersAndAdjustStack({}, 0);
|
ABI_PushRegistersAndAdjustStack({}, 0);
|
||||||
ABI_CallFunctionCCCP(PowerPC::UpdatePerformanceMonitor, js.downcountAmount, js.numLoadStoreInst,
|
ABI_CallFunctionCCCP(PowerPC::UpdatePerformanceMonitor, js.downcountAmount, js.numLoadStoreInst,
|
||||||
js.numFloatingPointInst, &PowerPC::ppcState);
|
js.numFloatingPointInst, &m_ppc_state);
|
||||||
ABI_PopRegistersAndAdjustStack({}, 0);
|
ABI_PopRegistersAndAdjustStack({}, 0);
|
||||||
did_something = true;
|
did_something = true;
|
||||||
}
|
}
|
||||||
@ -663,25 +658,24 @@ void Jit64::Trace()
|
|||||||
std::string fregs;
|
std::string fregs;
|
||||||
|
|
||||||
#ifdef JIT_LOG_GPR
|
#ifdef JIT_LOG_GPR
|
||||||
for (size_t i = 0; i < std::size(PowerPC::ppcState.gpr); i++)
|
for (size_t i = 0; i < std::size(m_ppc_state.gpr); i++)
|
||||||
{
|
{
|
||||||
regs += fmt::format("r{:02d}: {:08x} ", i, PowerPC::ppcState.gpr[i]);
|
regs += fmt::format("r{:02d}: {:08x} ", i, m_ppc_state.gpr[i]);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef JIT_LOG_FPR
|
#ifdef JIT_LOG_FPR
|
||||||
for (size_t i = 0; i < std::size(PowerPC::ppcState.ps); i++)
|
for (size_t i = 0; i < std::size(m_ppc_state.ps); i++)
|
||||||
{
|
{
|
||||||
fregs += fmt::format("f{:02d}: {:016x} ", i, PowerPC::ppcState.ps[i].PS0AsU64());
|
fregs += fmt::format("f{:02d}: {:016x} ", i, m_ppc_state.ps[i].PS0AsU64());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
DEBUG_LOG_FMT(DYNA_REC,
|
DEBUG_LOG_FMT(DYNA_REC,
|
||||||
"JIT64 PC: {:08x} SRR0: {:08x} SRR1: {:08x} FPSCR: {:08x} "
|
"JIT64 PC: {:08x} SRR0: {:08x} SRR1: {:08x} FPSCR: {:08x} "
|
||||||
"MSR: {:08x} LR: {:08x} {} {}",
|
"MSR: {:08x} LR: {:08x} {} {}",
|
||||||
PowerPC::ppcState.pc, SRR0(PowerPC::ppcState), SRR1(PowerPC::ppcState),
|
m_ppc_state.pc, SRR0(m_ppc_state), SRR1(m_ppc_state), m_ppc_state.fpscr.Hex,
|
||||||
PowerPC::ppcState.fpscr.Hex, PowerPC::ppcState.msr.Hex, PowerPC::ppcState.spr[8],
|
m_ppc_state.msr.Hex, m_ppc_state.spr[8], regs, fregs);
|
||||||
regs, fregs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jit64::Jit(u32 em_address)
|
void Jit64::Jit(u32 em_address)
|
||||||
@ -720,7 +714,7 @@ void Jit64::Jit(u32 em_address, bool clear_cache_and_retry_on_failure)
|
|||||||
|
|
||||||
if (!jo.profile_blocks)
|
if (!jo.profile_blocks)
|
||||||
{
|
{
|
||||||
if (Core::System::GetInstance().GetCPU().IsStepping())
|
if (m_system.GetCPU().IsStepping())
|
||||||
{
|
{
|
||||||
block_size = 1;
|
block_size = 1;
|
||||||
|
|
||||||
@ -744,8 +738,8 @@ void Jit64::Jit(u32 em_address, bool clear_cache_and_retry_on_failure)
|
|||||||
if (code_block.m_memory_exception)
|
if (code_block.m_memory_exception)
|
||||||
{
|
{
|
||||||
// Address of instruction could not be translated
|
// Address of instruction could not be translated
|
||||||
PowerPC::ppcState.npc = nextPC;
|
m_ppc_state.npc = nextPC;
|
||||||
PowerPC::ppcState.Exceptions |= EXCEPTION_ISI;
|
m_ppc_state.Exceptions |= EXCEPTION_ISI;
|
||||||
PowerPC::CheckExceptions();
|
PowerPC::CheckExceptions();
|
||||||
WARN_LOG_FMT(POWERPC, "ISI exception at {:#010x}", nextPC);
|
WARN_LOG_FMT(POWERPC, "ISI exception at {:#010x}", nextPC);
|
||||||
return;
|
return;
|
||||||
@ -822,8 +816,6 @@ bool Jit64::SetEmitterStateToFreeCodeRegion()
|
|||||||
|
|
||||||
bool Jit64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
|
bool Jit64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
|
||||||
{
|
{
|
||||||
auto& system = Core::System::GetInstance();
|
|
||||||
|
|
||||||
js.firstFPInstructionFound = false;
|
js.firstFPInstructionFound = false;
|
||||||
js.isLastInstruction = false;
|
js.isLastInstruction = false;
|
||||||
js.blockStart = em_address;
|
js.blockStart = em_address;
|
||||||
@ -839,10 +831,10 @@ bool Jit64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
|
|||||||
b->normalEntry = start;
|
b->normalEntry = start;
|
||||||
|
|
||||||
// Used to get a trace of the last few blocks before a crash, sometimes VERY useful
|
// Used to get a trace of the last few blocks before a crash, sometimes VERY useful
|
||||||
if (ImHereDebug)
|
if (m_im_here_debug)
|
||||||
{
|
{
|
||||||
ABI_PushRegistersAndAdjustStack({}, 0);
|
ABI_PushRegistersAndAdjustStack({}, 0);
|
||||||
ABI_CallFunction(ImHere);
|
ABI_CallFunctionP(ImHere, this);
|
||||||
ABI_PopRegistersAndAdjustStack({}, 0);
|
ABI_PopRegistersAndAdjustStack({}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -895,9 +887,9 @@ bool Jit64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
|
|||||||
// the start of the block in case our guess turns out wrong.
|
// the start of the block in case our guess turns out wrong.
|
||||||
for (int gqr : gqr_static)
|
for (int gqr : gqr_static)
|
||||||
{
|
{
|
||||||
u32 value = GQR(PowerPC::ppcState, gqr);
|
u32 value = GQR(m_ppc_state, gqr);
|
||||||
js.constantGqr[gqr] = value;
|
js.constantGqr[gqr] = value;
|
||||||
CMP_or_TEST(32, PPCSTATE(spr[SPR_GQR0 + gqr]), Imm32(value));
|
CMP_or_TEST(32, PPCSTATE_SPR(SPR_GQR0 + gqr), Imm32(value));
|
||||||
J_CC(CC_NZ, target);
|
J_CC(CC_NZ, target);
|
||||||
}
|
}
|
||||||
js.constantGqrValid = gqr_static;
|
js.constantGqrValid = gqr_static;
|
||||||
@ -944,7 +936,7 @@ bool Jit64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
|
|||||||
js.mustCheckFifo = false;
|
js.mustCheckFifo = false;
|
||||||
BitSet32 registersInUse = CallerSavedRegistersInUse();
|
BitSet32 registersInUse = CallerSavedRegistersInUse();
|
||||||
ABI_PushRegistersAndAdjustStack(registersInUse, 0);
|
ABI_PushRegistersAndAdjustStack(registersInUse, 0);
|
||||||
ABI_CallFunctionP(GPFifo::FastCheckGatherPipe, &system.GetGPFifo());
|
ABI_CallFunctionP(GPFifo::FastCheckGatherPipe, &m_system.GetGPFifo());
|
||||||
ABI_PopRegistersAndAdjustStack(registersInUse, 0);
|
ABI_PopRegistersAndAdjustStack(registersInUse, 0);
|
||||||
gatherPipeIntCheck = true;
|
gatherPipeIntCheck = true;
|
||||||
}
|
}
|
||||||
@ -961,7 +953,7 @@ bool Jit64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
|
|||||||
SetJumpTarget(extException);
|
SetJumpTarget(extException);
|
||||||
TEST(32, PPCSTATE(msr), Imm32(0x0008000));
|
TEST(32, PPCSTATE(msr), Imm32(0x0008000));
|
||||||
FixupBranch noExtIntEnable = J_CC(CC_Z, true);
|
FixupBranch noExtIntEnable = J_CC(CC_Z, true);
|
||||||
MOV(64, R(RSCRATCH), ImmPtr(&system.GetProcessorInterface().m_interrupt_cause));
|
MOV(64, R(RSCRATCH), ImmPtr(&m_system.GetProcessorInterface().m_interrupt_cause));
|
||||||
TEST(32, MatR(RSCRATCH),
|
TEST(32, MatR(RSCRATCH),
|
||||||
Imm32(ProcessorInterface::INT_CAUSE_CP | ProcessorInterface::INT_CAUSE_PE_TOKEN |
|
Imm32(ProcessorInterface::INT_CAUSE_CP | ProcessorInterface::INT_CAUSE_PE_TOKEN |
|
||||||
ProcessorInterface::INT_CAUSE_PE_FINISH));
|
ProcessorInterface::INT_CAUSE_PE_FINISH));
|
||||||
@ -1013,7 +1005,7 @@ bool Jit64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
|
|||||||
js.firstFPInstructionFound = true;
|
js.firstFPInstructionFound = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& cpu = system.GetCPU();
|
auto& cpu = m_system.GetCPU();
|
||||||
if (m_enable_debugging && breakpoints.IsAddressBreakPoint(op.address) && !cpu.IsStepping())
|
if (m_enable_debugging && breakpoints.IsAddressBreakPoint(op.address) && !cpu.IsStepping())
|
||||||
{
|
{
|
||||||
gpr.Flush();
|
gpr.Flush();
|
||||||
@ -1190,7 +1182,7 @@ void Jit64::IntializeSpeculativeConstants()
|
|||||||
const u8* target = nullptr;
|
const u8* target = nullptr;
|
||||||
for (auto i : code_block.m_gpr_inputs)
|
for (auto i : code_block.m_gpr_inputs)
|
||||||
{
|
{
|
||||||
u32 compileTimeValue = PowerPC::ppcState.gpr[i];
|
u32 compileTimeValue = m_ppc_state.gpr[i];
|
||||||
if (PowerPC::IsOptimizableGatherPipeWrite(compileTimeValue) ||
|
if (PowerPC::IsOptimizableGatherPipeWrite(compileTimeValue) ||
|
||||||
PowerPC::IsOptimizableGatherPipeWrite(compileTimeValue - 0x8000) ||
|
PowerPC::IsOptimizableGatherPipeWrite(compileTimeValue - 0x8000) ||
|
||||||
compileTimeValue == 0xCC000000)
|
compileTimeValue == 0xCC000000)
|
||||||
@ -1207,7 +1199,7 @@ void Jit64::IntializeSpeculativeConstants()
|
|||||||
JMP(asm_routines.dispatcher_no_check, true);
|
JMP(asm_routines.dispatcher_no_check, true);
|
||||||
SwitchToNearCode();
|
SwitchToNearCode();
|
||||||
}
|
}
|
||||||
CMP(32, PPCSTATE(gpr[i]), Imm32(compileTimeValue));
|
CMP(32, PPCSTATE_GPR(i), Imm32(compileTimeValue));
|
||||||
J_CC(CC_NZ, target);
|
J_CC(CC_NZ, target);
|
||||||
gpr.SetImmediate32(i, compileTimeValue, false);
|
gpr.SetImmediate32(i, compileTimeValue, false);
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,11 @@ struct CodeOp;
|
|||||||
class Jit64 : public JitBase, public QuantizedMemoryRoutines
|
class Jit64 : public JitBase, public QuantizedMemoryRoutines
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Jit64();
|
explicit Jit64(Core::System& system);
|
||||||
|
Jit64(const Jit64&) = delete;
|
||||||
|
Jit64(Jit64&&) = delete;
|
||||||
|
Jit64& operator=(const Jit64&) = delete;
|
||||||
|
Jit64& operator=(Jit64&&) = delete;
|
||||||
~Jit64() override;
|
~Jit64() override;
|
||||||
|
|
||||||
void Init() override;
|
void Init() override;
|
||||||
@ -256,6 +260,8 @@ private:
|
|||||||
|
|
||||||
void ResetFreeMemoryRanges();
|
void ResetFreeMemoryRanges();
|
||||||
|
|
||||||
|
static void ImHere(Jit64& jit);
|
||||||
|
|
||||||
JitBlockCache blocks{*this};
|
JitBlockCache blocks{*this};
|
||||||
TrampolineCache trampolines{*this};
|
TrampolineCache trampolines{*this};
|
||||||
|
|
||||||
@ -266,6 +272,10 @@ private:
|
|||||||
|
|
||||||
HyoutaUtilities::RangeSizeSet<u8*> m_free_ranges_near;
|
HyoutaUtilities::RangeSizeSet<u8*> m_free_ranges_near;
|
||||||
HyoutaUtilities::RangeSizeSet<u8*> m_free_ranges_far;
|
HyoutaUtilities::RangeSizeSet<u8*> m_free_ranges_far;
|
||||||
|
|
||||||
|
const bool m_im_here_debug = false;
|
||||||
|
const bool m_im_here_log = false;
|
||||||
|
std::map<u32, int> m_been_here;
|
||||||
};
|
};
|
||||||
|
|
||||||
void LogGeneratedX86(size_t size, const PPCAnalyst::CodeBuffer& code_buffer, const u8* normalEntry,
|
void LogGeneratedX86(size_t size, const PPCAnalyst::CodeBuffer& code_buffer, const u8* normalEntry,
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
using namespace Gen;
|
using namespace Gen;
|
||||||
|
|
||||||
Jit64AsmRoutineManager::Jit64AsmRoutineManager(Jit64& jit) : CommonAsmRoutines(jit), m_jit{jit}
|
Jit64AsmRoutineManager::Jit64AsmRoutineManager(Jit64& jit) : CommonAsmRoutines(jit)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,9 +45,11 @@ void Jit64AsmRoutineManager::Generate()
|
|||||||
// waste a bit of space for a second shadow, but whatever.
|
// waste a bit of space for a second shadow, but whatever.
|
||||||
ABI_PushRegistersAndAdjustStack(ABI_ALL_CALLEE_SAVED, 8, /*frame*/ 16);
|
ABI_PushRegistersAndAdjustStack(ABI_ALL_CALLEE_SAVED, 8, /*frame*/ 16);
|
||||||
|
|
||||||
|
auto& ppc_state = m_jit.m_ppc_state;
|
||||||
|
|
||||||
// Two statically allocated registers.
|
// Two statically allocated registers.
|
||||||
// MOV(64, R(RMEM), Imm64((u64)Memory::physical_base));
|
// MOV(64, R(RMEM), Imm64((u64)Memory::physical_base));
|
||||||
MOV(64, R(RPPCSTATE), Imm64((u64)&PowerPC::ppcState + 0x80));
|
MOV(64, R(RPPCSTATE), Imm64((u64)&ppc_state + 0x80));
|
||||||
|
|
||||||
MOV(64, PPCSTATE(stored_stack_pointer), R(RSP));
|
MOV(64, PPCSTATE(stored_stack_pointer), R(RSP));
|
||||||
|
|
||||||
@ -81,7 +83,7 @@ void Jit64AsmRoutineManager::Generate()
|
|||||||
|
|
||||||
dispatcher_no_timing_check = GetCodePtr();
|
dispatcher_no_timing_check = GetCodePtr();
|
||||||
|
|
||||||
auto& system = Core::System::GetInstance();
|
auto& system = m_jit.m_system;
|
||||||
|
|
||||||
FixupBranch dbg_exit;
|
FixupBranch dbg_exit;
|
||||||
if (enable_debugging)
|
if (enable_debugging)
|
||||||
|
@ -11,8 +11,6 @@ namespace Gen
|
|||||||
class X64CodeBlock;
|
class X64CodeBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
class JitBase;
|
|
||||||
|
|
||||||
// In Dolphin, we don't use inline assembly. Instead, we generate all machine-near
|
// In Dolphin, we don't use inline assembly. Instead, we generate all machine-near
|
||||||
// code at runtime. In the case of fixed code like this, after writing it, we write
|
// code at runtime. In the case of fixed code like this, after writing it, we write
|
||||||
// protect the memory, essentially making it work just like precompiled code.
|
// protect the memory, essentially making it work just like precompiled code.
|
||||||
@ -43,6 +41,4 @@ public:
|
|||||||
private:
|
private:
|
||||||
void Generate();
|
void Generate();
|
||||||
void GenerateCommon();
|
void GenerateCommon();
|
||||||
|
|
||||||
JitBase& m_jit;
|
|
||||||
};
|
};
|
||||||
|
@ -780,7 +780,7 @@ void Jit64::FloatCompare(UGeckoInstruction inst, bool upper)
|
|||||||
SetJumpTarget(continue3);
|
SetJumpTarget(continue3);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOV(64, PPCSTATE(cr.fields[crf]), R(RSCRATCH));
|
MOV(64, PPCSTATE_CR(crf), R(RSCRATCH));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jit64::fcmpX(UGeckoInstruction inst)
|
void Jit64::fcmpX(UGeckoInstruction inst)
|
||||||
|
@ -148,16 +148,16 @@ void Jit64::ComputeRC(preg_t preg, bool needs_test, bool needs_sext)
|
|||||||
|
|
||||||
if (arg.IsImm())
|
if (arg.IsImm())
|
||||||
{
|
{
|
||||||
MOV(64, PPCSTATE(cr.fields[0]), Imm32(arg.SImm32()));
|
MOV(64, PPCSTATE_CR(0), Imm32(arg.SImm32()));
|
||||||
}
|
}
|
||||||
else if (needs_sext)
|
else if (needs_sext)
|
||||||
{
|
{
|
||||||
MOVSX(64, 32, RSCRATCH, arg);
|
MOVSX(64, 32, RSCRATCH, arg);
|
||||||
MOV(64, PPCSTATE(cr.fields[0]), R(RSCRATCH));
|
MOV(64, PPCSTATE_CR(0), R(RSCRATCH));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MOV(64, PPCSTATE(cr.fields[0]), arg);
|
MOV(64, PPCSTATE_CR(0), arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CheckMergedBranch(0))
|
if (CheckMergedBranch(0))
|
||||||
@ -391,14 +391,14 @@ void Jit64::DoMergedBranch()
|
|||||||
if (js.op[1].branchIsIdleLoop)
|
if (js.op[1].branchIsIdleLoop)
|
||||||
{
|
{
|
||||||
if (next.LK)
|
if (next.LK)
|
||||||
MOV(32, PPCSTATE(spr[SPR_LR]), Imm32(nextPC + 4));
|
MOV(32, PPCSTATE_SPR(SPR_LR), Imm32(nextPC + 4));
|
||||||
|
|
||||||
WriteIdleExit(js.op[1].branchTo);
|
WriteIdleExit(js.op[1].branchTo);
|
||||||
}
|
}
|
||||||
else if (next.OPCD == 16) // bcx
|
else if (next.OPCD == 16) // bcx
|
||||||
{
|
{
|
||||||
if (next.LK)
|
if (next.LK)
|
||||||
MOV(32, PPCSTATE(spr[SPR_LR]), Imm32(nextPC + 4));
|
MOV(32, PPCSTATE_SPR(SPR_LR), Imm32(nextPC + 4));
|
||||||
|
|
||||||
u32 destination;
|
u32 destination;
|
||||||
if (next.AA)
|
if (next.AA)
|
||||||
@ -410,18 +410,18 @@ void Jit64::DoMergedBranch()
|
|||||||
else if ((next.OPCD == 19) && (next.SUBOP10 == 528)) // bcctrx
|
else if ((next.OPCD == 19) && (next.SUBOP10 == 528)) // bcctrx
|
||||||
{
|
{
|
||||||
if (next.LK)
|
if (next.LK)
|
||||||
MOV(32, PPCSTATE(spr[SPR_LR]), Imm32(nextPC + 4));
|
MOV(32, PPCSTATE_SPR(SPR_LR), Imm32(nextPC + 4));
|
||||||
MOV(32, R(RSCRATCH), PPCSTATE(spr[SPR_CTR]));
|
MOV(32, R(RSCRATCH), PPCSTATE_SPR(SPR_CTR));
|
||||||
AND(32, R(RSCRATCH), Imm32(0xFFFFFFFC));
|
AND(32, R(RSCRATCH), Imm32(0xFFFFFFFC));
|
||||||
WriteExitDestInRSCRATCH(next.LK, nextPC + 4);
|
WriteExitDestInRSCRATCH(next.LK, nextPC + 4);
|
||||||
}
|
}
|
||||||
else if ((next.OPCD == 19) && (next.SUBOP10 == 16)) // bclrx
|
else if ((next.OPCD == 19) && (next.SUBOP10 == 16)) // bclrx
|
||||||
{
|
{
|
||||||
MOV(32, R(RSCRATCH), PPCSTATE(spr[SPR_LR]));
|
MOV(32, R(RSCRATCH), PPCSTATE_SPR(SPR_LR));
|
||||||
if (!m_enable_blr_optimization)
|
if (!m_enable_blr_optimization)
|
||||||
AND(32, R(RSCRATCH), Imm32(0xFFFFFFFC));
|
AND(32, R(RSCRATCH), Imm32(0xFFFFFFFC));
|
||||||
if (next.LK)
|
if (next.LK)
|
||||||
MOV(32, PPCSTATE(spr[SPR_LR]), Imm32(nextPC + 4));
|
MOV(32, PPCSTATE_SPR(SPR_LR), Imm32(nextPC + 4));
|
||||||
WriteBLRExit();
|
WriteBLRExit();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -551,12 +551,12 @@ void Jit64::cmpXX(UGeckoInstruction inst)
|
|||||||
(u64)gpr.Imm32(a) - (u64)comparand.Imm32();
|
(u64)gpr.Imm32(a) - (u64)comparand.Imm32();
|
||||||
if (compareResult == (s32)compareResult)
|
if (compareResult == (s32)compareResult)
|
||||||
{
|
{
|
||||||
MOV(64, PPCSTATE(cr.fields[crf]), Imm32((u32)compareResult));
|
MOV(64, PPCSTATE_CR(crf), Imm32((u32)compareResult));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MOV(64, R(RSCRATCH), Imm64(compareResult));
|
MOV(64, R(RSCRATCH), Imm64(compareResult));
|
||||||
MOV(64, PPCSTATE(cr.fields[crf]), R(RSCRATCH));
|
MOV(64, PPCSTATE_CR(crf), R(RSCRATCH));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (merge_branch)
|
if (merge_branch)
|
||||||
@ -573,7 +573,7 @@ void Jit64::cmpXX(UGeckoInstruction inst)
|
|||||||
RCX64Reg Ra = gpr.Bind(a, RCMode::Read);
|
RCX64Reg Ra = gpr.Bind(a, RCMode::Read);
|
||||||
RegCache::Realize(Ra);
|
RegCache::Realize(Ra);
|
||||||
|
|
||||||
MOV(64, PPCSTATE(cr.fields[crf]), Ra);
|
MOV(64, PPCSTATE_CR(crf), Ra);
|
||||||
if (merge_branch)
|
if (merge_branch)
|
||||||
{
|
{
|
||||||
TEST(64, Ra, Ra);
|
TEST(64, Ra, Ra);
|
||||||
@ -621,7 +621,7 @@ void Jit64::cmpXX(UGeckoInstruction inst)
|
|||||||
|
|
||||||
if (comparand.IsImm() && comparand.Imm32() == 0)
|
if (comparand.IsImm() && comparand.Imm32() == 0)
|
||||||
{
|
{
|
||||||
MOV(64, PPCSTATE(cr.fields[crf]), R(input));
|
MOV(64, PPCSTATE_CR(crf), R(input));
|
||||||
// Place the comparison next to the branch for macro-op fusion
|
// Place the comparison next to the branch for macro-op fusion
|
||||||
if (merge_branch)
|
if (merge_branch)
|
||||||
TEST(64, R(input), R(input));
|
TEST(64, R(input), R(input));
|
||||||
@ -629,7 +629,7 @@ void Jit64::cmpXX(UGeckoInstruction inst)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
SUB(64, R(input), comparand);
|
SUB(64, R(input), comparand);
|
||||||
MOV(64, PPCSTATE(cr.fields[crf]), R(input));
|
MOV(64, PPCSTATE_CR(crf), R(input));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (merge_branch)
|
if (merge_branch)
|
||||||
|
@ -320,7 +320,7 @@ void Jit64::dcbx(UGeckoInstruction inst)
|
|||||||
FixupBranch bat_lookup_failed;
|
FixupBranch bat_lookup_failed;
|
||||||
MOV(32, R(effective_address), R(addr));
|
MOV(32, R(effective_address), R(addr));
|
||||||
const u8* loop_start = GetCodePtr();
|
const u8* loop_start = GetCodePtr();
|
||||||
if (PowerPC::ppcState.msr.IR)
|
if (m_ppc_state.msr.IR)
|
||||||
{
|
{
|
||||||
// Translate effective address to physical address.
|
// Translate effective address to physical address.
|
||||||
bat_lookup_failed = BATAddressLookup(addr, tmp, PowerPC::ibat_table.data());
|
bat_lookup_failed = BATAddressLookup(addr, tmp, PowerPC::ibat_table.data());
|
||||||
@ -349,7 +349,7 @@ void Jit64::dcbx(UGeckoInstruction inst)
|
|||||||
|
|
||||||
SwitchToFarCode();
|
SwitchToFarCode();
|
||||||
SetJumpTarget(invalidate_needed);
|
SetJumpTarget(invalidate_needed);
|
||||||
if (PowerPC::ppcState.msr.IR)
|
if (m_ppc_state.msr.IR)
|
||||||
SetJumpTarget(bat_lookup_failed);
|
SetJumpTarget(bat_lookup_failed);
|
||||||
|
|
||||||
BitSet32 registersInUse = CallerSavedRegistersInUse();
|
BitSet32 registersInUse = CallerSavedRegistersInUse();
|
||||||
@ -422,7 +422,7 @@ void Jit64::dcbz(UGeckoInstruction inst)
|
|||||||
end_dcbz_hack = J_CC(CC_L);
|
end_dcbz_hack = J_CC(CC_L);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool emit_fast_path = PowerPC::ppcState.msr.DR && m_jit.jo.fastmem_arena;
|
bool emit_fast_path = m_ppc_state.msr.DR && m_jit.jo.fastmem_arena;
|
||||||
|
|
||||||
if (emit_fast_path)
|
if (emit_fast_path)
|
||||||
{
|
{
|
||||||
|
@ -23,7 +23,7 @@ void Jit64::psq_stXX(UGeckoInstruction inst)
|
|||||||
JITDISABLE(bJITLoadStorePairedOff);
|
JITDISABLE(bJITLoadStorePairedOff);
|
||||||
|
|
||||||
// For performance, the AsmCommon routines assume address translation is on.
|
// For performance, the AsmCommon routines assume address translation is on.
|
||||||
FALLBACK_IF(!PowerPC::ppcState.msr.DR);
|
FALLBACK_IF(!m_ppc_state.msr.DR);
|
||||||
|
|
||||||
s32 offset = inst.SIMM_12;
|
s32 offset = inst.SIMM_12;
|
||||||
bool indexed = inst.OPCD == 4;
|
bool indexed = inst.OPCD == 4;
|
||||||
@ -90,7 +90,7 @@ void Jit64::psq_stXX(UGeckoInstruction inst)
|
|||||||
// UU[SCALE]UUUUU[TYPE] where SCALE is 6 bits and TYPE is 3 bits, so we have to AND with
|
// UU[SCALE]UUUUU[TYPE] where SCALE is 6 bits and TYPE is 3 bits, so we have to AND with
|
||||||
// 0b0011111100000111, or 0x3F07.
|
// 0b0011111100000111, or 0x3F07.
|
||||||
MOV(32, R(RSCRATCH2), Imm32(0x3F07));
|
MOV(32, R(RSCRATCH2), Imm32(0x3F07));
|
||||||
AND(32, R(RSCRATCH2), PPCSTATE(spr[SPR_GQR0 + i]));
|
AND(32, R(RSCRATCH2), PPCSTATE_SPR(SPR_GQR0 + i));
|
||||||
LEA(64, RSCRATCH,
|
LEA(64, RSCRATCH,
|
||||||
M(w ? asm_routines.single_store_quantized : asm_routines.paired_store_quantized));
|
M(w ? asm_routines.single_store_quantized : asm_routines.paired_store_quantized));
|
||||||
// 8-bit operations do not zero upper 32-bits of 64-bit registers.
|
// 8-bit operations do not zero upper 32-bits of 64-bit registers.
|
||||||
@ -112,7 +112,7 @@ void Jit64::psq_lXX(UGeckoInstruction inst)
|
|||||||
JITDISABLE(bJITLoadStorePairedOff);
|
JITDISABLE(bJITLoadStorePairedOff);
|
||||||
|
|
||||||
// For performance, the AsmCommon routines assume address translation is on.
|
// For performance, the AsmCommon routines assume address translation is on.
|
||||||
FALLBACK_IF(!PowerPC::ppcState.msr.DR);
|
FALLBACK_IF(!m_ppc_state.msr.DR);
|
||||||
|
|
||||||
s32 offset = inst.SIMM_12;
|
s32 offset = inst.SIMM_12;
|
||||||
bool indexed = inst.OPCD == 4;
|
bool indexed = inst.OPCD == 4;
|
||||||
@ -147,7 +147,7 @@ void Jit64::psq_lXX(UGeckoInstruction inst)
|
|||||||
// Stash PC in case asm_routine causes exception
|
// Stash PC in case asm_routine causes exception
|
||||||
MOV(32, PPCSTATE(pc), Imm32(js.compilerPC));
|
MOV(32, PPCSTATE(pc), Imm32(js.compilerPC));
|
||||||
// Get the high part of the GQR register
|
// Get the high part of the GQR register
|
||||||
OpArg gqr = PPCSTATE(spr[SPR_GQR0 + i]);
|
OpArg gqr = PPCSTATE_SPR(SPR_GQR0 + i);
|
||||||
gqr.AddMemOffset(2);
|
gqr.AddMemOffset(2);
|
||||||
MOV(32, R(RSCRATCH2), Imm32(0x3F07));
|
MOV(32, R(RSCRATCH2), Imm32(0x3F07));
|
||||||
AND(32, R(RSCRATCH2), gqr);
|
AND(32, R(RSCRATCH2), gqr);
|
||||||
|
@ -20,7 +20,7 @@ using namespace Gen;
|
|||||||
|
|
||||||
static OpArg CROffset(int field)
|
static OpArg CROffset(int field)
|
||||||
{
|
{
|
||||||
return PPCSTATE(cr.fields[field]);
|
return PPCSTATE_CR(field);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jit64::GetCRFieldBit(int field, int bit, X64Reg out, bool negate)
|
void Jit64::GetCRFieldBit(int field, int bit, X64Reg out, bool negate)
|
||||||
@ -216,9 +216,9 @@ void Jit64::UpdateFPExceptionSummary(X64Reg fpscr, X64Reg tmp1, X64Reg tmp2)
|
|||||||
OR(32, R(fpscr), R(tmp1));
|
OR(32, R(fpscr), R(tmp1));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DoICacheReset()
|
static void DoICacheReset(PowerPC::PowerPCState& ppc_state)
|
||||||
{
|
{
|
||||||
PowerPC::ppcState.iCache.Reset();
|
ppc_state.iCache.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jit64::mtspr(UGeckoInstruction inst)
|
void Jit64::mtspr(UGeckoInstruction inst)
|
||||||
@ -282,11 +282,11 @@ void Jit64::mtspr(UGeckoInstruction inst)
|
|||||||
|
|
||||||
MOV(32, R(RSCRATCH), Rd);
|
MOV(32, R(RSCRATCH), Rd);
|
||||||
BTR(32, R(RSCRATCH), Imm8(31 - 20)); // ICFI
|
BTR(32, R(RSCRATCH), Imm8(31 - 20)); // ICFI
|
||||||
MOV(32, PPCSTATE(spr[iIndex]), R(RSCRATCH));
|
MOV(32, PPCSTATE_SPR(iIndex), R(RSCRATCH));
|
||||||
FixupBranch dont_reset_icache = J_CC(CC_NC);
|
FixupBranch dont_reset_icache = J_CC(CC_NC);
|
||||||
BitSet32 regs = CallerSavedRegistersInUse();
|
BitSet32 regs = CallerSavedRegistersInUse();
|
||||||
ABI_PushRegistersAndAdjustStack(regs, 0);
|
ABI_PushRegistersAndAdjustStack(regs, 0);
|
||||||
ABI_CallFunction(DoICacheReset);
|
ABI_CallFunctionP(DoICacheReset, &m_ppc_state);
|
||||||
ABI_PopRegistersAndAdjustStack(regs, 0);
|
ABI_PopRegistersAndAdjustStack(regs, 0);
|
||||||
SetJumpTarget(dont_reset_icache);
|
SetJumpTarget(dont_reset_icache);
|
||||||
return;
|
return;
|
||||||
@ -299,7 +299,7 @@ void Jit64::mtspr(UGeckoInstruction inst)
|
|||||||
// OK, this is easy.
|
// OK, this is easy.
|
||||||
RCOpArg Rd = gpr.BindOrImm(d, RCMode::Read);
|
RCOpArg Rd = gpr.BindOrImm(d, RCMode::Read);
|
||||||
RegCache::Realize(Rd);
|
RegCache::Realize(Rd);
|
||||||
MOV(32, PPCSTATE(spr[iIndex]), Rd);
|
MOV(32, PPCSTATE_SPR(iIndex), Rd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jit64::mfspr(UGeckoInstruction inst)
|
void Jit64::mfspr(UGeckoInstruction inst)
|
||||||
@ -323,7 +323,7 @@ void Jit64::mfspr(UGeckoInstruction inst)
|
|||||||
RCX64Reg rax = gpr.Scratch(RAX);
|
RCX64Reg rax = gpr.Scratch(RAX);
|
||||||
RCX64Reg rcx = gpr.Scratch(RCX);
|
RCX64Reg rcx = gpr.Scratch(RCX);
|
||||||
|
|
||||||
auto& core_timing_globals = Core::System::GetInstance().GetCoreTiming().GetGlobals();
|
auto& core_timing_globals = m_system.GetCoreTiming().GetGlobals();
|
||||||
MOV(64, rcx, ImmPtr(&core_timing_globals));
|
MOV(64, rcx, ImmPtr(&core_timing_globals));
|
||||||
|
|
||||||
// An inline implementation of CoreTiming::GetFakeTimeBase, since in timer-heavy games the
|
// An inline implementation of CoreTiming::GetFakeTimeBase, since in timer-heavy games the
|
||||||
@ -355,7 +355,7 @@ void Jit64::mfspr(UGeckoInstruction inst)
|
|||||||
MOV(64, rax, MDisp(rcx, offsetof(CoreTiming::Globals, fake_TB_start_value)));
|
MOV(64, rax, MDisp(rcx, offsetof(CoreTiming::Globals, fake_TB_start_value)));
|
||||||
SHR(64, rdx, Imm8(3));
|
SHR(64, rdx, Imm8(3));
|
||||||
ADD(64, rax, rdx);
|
ADD(64, rax, rdx);
|
||||||
MOV(64, PPCSTATE(spr[SPR_TL]), rax);
|
MOV(64, PPCSTATE_SPR(SPR_TL), rax);
|
||||||
|
|
||||||
if (CanMergeNextInstructions(1))
|
if (CanMergeNextInstructions(1))
|
||||||
{
|
{
|
||||||
@ -422,7 +422,7 @@ void Jit64::mfspr(UGeckoInstruction inst)
|
|||||||
{
|
{
|
||||||
RCX64Reg Rd = gpr.Bind(d, RCMode::Write);
|
RCX64Reg Rd = gpr.Bind(d, RCMode::Write);
|
||||||
RegCache::Realize(Rd);
|
RegCache::Realize(Rd);
|
||||||
MOV(32, Rd, PPCSTATE(spr[iIndex]));
|
MOV(32, Rd, PPCSTATE_SPR(iIndex));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -457,8 +457,7 @@ void Jit64::mtmsr(UGeckoInstruction inst)
|
|||||||
FixupBranch noExceptionsPending = J_CC(CC_Z, true);
|
FixupBranch noExceptionsPending = J_CC(CC_Z, true);
|
||||||
|
|
||||||
// Check if a CP interrupt is waiting and keep the GPU emulation in sync (issue 4336)
|
// Check if a CP interrupt is waiting and keep the GPU emulation in sync (issue 4336)
|
||||||
auto& system = Core::System::GetInstance();
|
MOV(64, R(RSCRATCH), ImmPtr(&m_system.GetProcessorInterface().m_interrupt_cause));
|
||||||
MOV(64, R(RSCRATCH), ImmPtr(&system.GetProcessorInterface().m_interrupt_cause));
|
|
||||||
TEST(32, MatR(RSCRATCH), Imm32(ProcessorInterface::INT_CAUSE_CP));
|
TEST(32, MatR(RSCRATCH), Imm32(ProcessorInterface::INT_CAUSE_CP));
|
||||||
FixupBranch cpInt = J_CC(CC_NZ, true);
|
FixupBranch cpInt = J_CC(CC_NZ, true);
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ const X64Reg* FPURegCache::GetAllocationOrder(size_t* count) const
|
|||||||
|
|
||||||
OpArg FPURegCache::GetDefaultLocation(preg_t preg) const
|
OpArg FPURegCache::GetDefaultLocation(preg_t preg) const
|
||||||
{
|
{
|
||||||
return PPCSTATE(ps[preg].ps0);
|
return PPCSTATE_PS0(preg);
|
||||||
}
|
}
|
||||||
|
|
||||||
BitSet32 FPURegCache::GetRegUtilization() const
|
BitSet32 FPURegCache::GetRegUtilization() const
|
||||||
|
@ -27,7 +27,7 @@ void GPRRegCache::LoadRegister(preg_t preg, X64Reg new_loc)
|
|||||||
|
|
||||||
OpArg GPRRegCache::GetDefaultLocation(preg_t preg) const
|
OpArg GPRRegCache::GetDefaultLocation(preg_t preg) const
|
||||||
{
|
{
|
||||||
return PPCSTATE(gpr[preg]);
|
return PPCSTATE_GPR(preg);
|
||||||
}
|
}
|
||||||
|
|
||||||
const X64Reg* GPRRegCache::GetAllocationOrder(size_t* count) const
|
const X64Reg* GPRRegCache::GetAllocationOrder(size_t* count) const
|
||||||
|
@ -209,10 +209,10 @@ template <typename T>
|
|||||||
class MMIOReadCodeGenerator : public MMIO::ReadHandlingMethodVisitor<T>
|
class MMIOReadCodeGenerator : public MMIO::ReadHandlingMethodVisitor<T>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MMIOReadCodeGenerator(Gen::X64CodeBlock* code, BitSet32 registers_in_use, Gen::X64Reg dst_reg,
|
MMIOReadCodeGenerator(Core::System* system, Gen::X64CodeBlock* code, BitSet32 registers_in_use,
|
||||||
u32 address, bool sign_extend)
|
Gen::X64Reg dst_reg, u32 address, bool sign_extend)
|
||||||
: m_code(code), m_registers_in_use(registers_in_use), m_dst_reg(dst_reg), m_address(address),
|
: m_system(system), m_code(code), m_registers_in_use(registers_in_use), m_dst_reg(dst_reg),
|
||||||
m_sign_extend(sign_extend)
|
m_address(address), m_sign_extend(sign_extend)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -273,11 +273,12 @@ private:
|
|||||||
void CallLambda(int sbits, const std::function<T(Core::System&, u32)>* lambda)
|
void CallLambda(int sbits, const std::function<T(Core::System&, u32)>* lambda)
|
||||||
{
|
{
|
||||||
m_code->ABI_PushRegistersAndAdjustStack(m_registers_in_use, 0);
|
m_code->ABI_PushRegistersAndAdjustStack(m_registers_in_use, 0);
|
||||||
m_code->ABI_CallLambdaPC(lambda, &Core::System::GetInstance(), m_address);
|
m_code->ABI_CallLambdaPC(lambda, m_system, m_address);
|
||||||
m_code->ABI_PopRegistersAndAdjustStack(m_registers_in_use, 0);
|
m_code->ABI_PopRegistersAndAdjustStack(m_registers_in_use, 0);
|
||||||
MoveOpArgToReg(sbits, R(ABI_RETURN));
|
MoveOpArgToReg(sbits, R(ABI_RETURN));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Core::System* m_system;
|
||||||
Gen::X64CodeBlock* m_code;
|
Gen::X64CodeBlock* m_code;
|
||||||
BitSet32 m_registers_in_use;
|
BitSet32 m_registers_in_use;
|
||||||
Gen::X64Reg m_dst_reg;
|
Gen::X64Reg m_dst_reg;
|
||||||
@ -293,19 +294,22 @@ void EmuCodeBlock::MMIOLoadToReg(MMIO::Mapping* mmio, Gen::X64Reg reg_value,
|
|||||||
{
|
{
|
||||||
case 8:
|
case 8:
|
||||||
{
|
{
|
||||||
MMIOReadCodeGenerator<u8> gen(this, registers_in_use, reg_value, address, sign_extend);
|
MMIOReadCodeGenerator<u8> gen(&m_jit.m_system, this, registers_in_use, reg_value, address,
|
||||||
|
sign_extend);
|
||||||
mmio->GetHandlerForRead<u8>(address).Visit(gen);
|
mmio->GetHandlerForRead<u8>(address).Visit(gen);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 16:
|
case 16:
|
||||||
{
|
{
|
||||||
MMIOReadCodeGenerator<u16> gen(this, registers_in_use, reg_value, address, sign_extend);
|
MMIOReadCodeGenerator<u16> gen(&m_jit.m_system, this, registers_in_use, reg_value, address,
|
||||||
|
sign_extend);
|
||||||
mmio->GetHandlerForRead<u16>(address).Visit(gen);
|
mmio->GetHandlerForRead<u16>(address).Visit(gen);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 32:
|
case 32:
|
||||||
{
|
{
|
||||||
MMIOReadCodeGenerator<u32> gen(this, registers_in_use, reg_value, address, sign_extend);
|
MMIOReadCodeGenerator<u32> gen(&m_jit.m_system, this, registers_in_use, reg_value, address,
|
||||||
|
sign_extend);
|
||||||
mmio->GetHandlerForRead<u32>(address).Visit(gen);
|
mmio->GetHandlerForRead<u32>(address).Visit(gen);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -367,7 +371,7 @@ void EmuCodeBlock::SafeLoadToReg(X64Reg reg_value, const Gen::OpArg& opAddress,
|
|||||||
}
|
}
|
||||||
|
|
||||||
FixupBranch exit;
|
FixupBranch exit;
|
||||||
const bool dr_set = (flags & SAFE_LOADSTORE_DR_ON) || PowerPC::ppcState.msr.DR;
|
const bool dr_set = (flags & SAFE_LOADSTORE_DR_ON) || m_jit.m_ppc_state.msr.DR;
|
||||||
const bool fast_check_address = !slowmem && dr_set && m_jit.jo.fastmem_arena;
|
const bool fast_check_address = !slowmem && dr_set && m_jit.jo.fastmem_arena;
|
||||||
if (fast_check_address)
|
if (fast_check_address)
|
||||||
{
|
{
|
||||||
@ -442,8 +446,7 @@ void EmuCodeBlock::SafeLoadToRegImmediate(X64Reg reg_value, u32 address, int acc
|
|||||||
u32 mmioAddress = PowerPC::IsOptimizableMMIOAccess(address, accessSize);
|
u32 mmioAddress = PowerPC::IsOptimizableMMIOAccess(address, accessSize);
|
||||||
if (accessSize != 64 && mmioAddress)
|
if (accessSize != 64 && mmioAddress)
|
||||||
{
|
{
|
||||||
auto& system = Core::System::GetInstance();
|
auto& memory = m_jit.m_system.GetMemory();
|
||||||
auto& memory = system.GetMemory();
|
|
||||||
MMIOLoadToReg(memory.GetMMIOMapping(), reg_value, registersInUse, mmioAddress, accessSize,
|
MMIOLoadToReg(memory.GetMMIOMapping(), reg_value, registersInUse, mmioAddress, accessSize,
|
||||||
signExtend);
|
signExtend);
|
||||||
return;
|
return;
|
||||||
@ -537,7 +540,7 @@ void EmuCodeBlock::SafeWriteRegToReg(OpArg reg_value, X64Reg reg_addr, int acces
|
|||||||
}
|
}
|
||||||
|
|
||||||
FixupBranch exit;
|
FixupBranch exit;
|
||||||
const bool dr_set = (flags & SAFE_LOADSTORE_DR_ON) || PowerPC::ppcState.msr.DR;
|
const bool dr_set = (flags & SAFE_LOADSTORE_DR_ON) || m_jit.m_ppc_state.msr.DR;
|
||||||
const bool fast_check_address = !slowmem && dr_set && m_jit.jo.fastmem_arena;
|
const bool fast_check_address = !slowmem && dr_set && m_jit.jo.fastmem_arena;
|
||||||
if (fast_check_address)
|
if (fast_check_address)
|
||||||
{
|
{
|
||||||
|
@ -305,7 +305,7 @@ void CommonAsmRoutines::GenMfcr()
|
|||||||
if (i != 0)
|
if (i != 0)
|
||||||
SHL(32, R(dst), Imm8(4));
|
SHL(32, R(dst), Imm8(4));
|
||||||
|
|
||||||
MOV(64, R(cr_val), PPCSTATE(cr.fields[i]));
|
MOV(64, R(cr_val), PPCSTATE_CR(i));
|
||||||
|
|
||||||
// EQ: Bits 31-0 == 0; set flag bit 1
|
// EQ: Bits 31-0 == 0; set flag bit 1
|
||||||
TEST(32, R(cr_val), R(cr_val));
|
TEST(32, R(cr_val), R(cr_val));
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
|
|
||||||
enum EQuantizeType : u32;
|
enum EQuantizeType : u32;
|
||||||
|
|
||||||
|
class Jit64;
|
||||||
|
|
||||||
class QuantizedMemoryRoutines : public EmuCodeBlock
|
class QuantizedMemoryRoutines : public EmuCodeBlock
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -24,7 +26,7 @@ private:
|
|||||||
class CommonAsmRoutines : public CommonAsmRoutinesBase, public QuantizedMemoryRoutines
|
class CommonAsmRoutines : public CommonAsmRoutinesBase, public QuantizedMemoryRoutines
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit CommonAsmRoutines(Jit64& jit) : QuantizedMemoryRoutines(jit) {}
|
explicit CommonAsmRoutines(Jit64& jit) : QuantizedMemoryRoutines(jit), m_jit(jit) {}
|
||||||
void GenFrsqrte();
|
void GenFrsqrte();
|
||||||
void GenFres();
|
void GenFres();
|
||||||
void GenMfcr();
|
void GenMfcr();
|
||||||
@ -37,4 +39,6 @@ protected:
|
|||||||
void GenQuantizedSingleLoads();
|
void GenQuantizedSingleLoads();
|
||||||
void GenQuantizedStores();
|
void GenQuantizedStores();
|
||||||
void GenQuantizedSingleStores();
|
void GenQuantizedSingleStores();
|
||||||
|
|
||||||
|
Jit64& m_jit;
|
||||||
};
|
};
|
||||||
|
@ -3,17 +3,38 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Core/PowerPC/Jit64Common/Jit64Constants.h"
|
#include "Core/PowerPC/Jit64Common/Jit64Constants.h"
|
||||||
#include "Core/PowerPC/PowerPC.h"
|
#include "Core/PowerPC/PowerPC.h"
|
||||||
|
|
||||||
// We offset by 0x80 because the range of one byte memory offsets is
|
// We offset by 0x80 because the range of one byte memory offsets is
|
||||||
// -0x80..0x7f.
|
// -0x80..0x7f.
|
||||||
#define PPCSTATE(x) \
|
#define PPCSTATE_OFF(i) (static_cast<int>(offsetof(PowerPC::PowerPCState, i)) - 0x80)
|
||||||
MDisp(RPPCSTATE, (int)((char*)&PowerPC::ppcState.x - (char*)&PowerPC::ppcState) - 0x80)
|
#define PPCSTATE_OFF_ARRAY(elem, i) \
|
||||||
// In case you want to disable the ppcstate register:
|
(static_cast<int>(offsetof(PowerPC::PowerPCState, elem[0]) + \
|
||||||
// #define PPCSTATE(x) M(&PowerPC::ppcState.x)
|
sizeof(PowerPC::PowerPCState::elem[0]) * (i)) - \
|
||||||
#define PPCSTATE_LR PPCSTATE(spr[SPR_LR])
|
0x80)
|
||||||
#define PPCSTATE_CTR PPCSTATE(spr[SPR_CTR])
|
|
||||||
#define PPCSTATE_SRR0 PPCSTATE(spr[SPR_SRR0])
|
#define PPCSTATE_OFF_GPR(i) PPCSTATE_OFF_ARRAY(gpr, i)
|
||||||
#define PPCSTATE_SRR1 PPCSTATE(spr[SPR_SRR1])
|
#define PPCSTATE_OFF_CR(i) PPCSTATE_OFF_ARRAY(cr.fields, i)
|
||||||
|
#define PPCSTATE_OFF_SR(i) PPCSTATE_OFF_ARRAY(sr, i)
|
||||||
|
#define PPCSTATE_OFF_SPR(i) PPCSTATE_OFF_ARRAY(spr, i)
|
||||||
|
|
||||||
|
static_assert(std::is_same_v<decltype(PowerPC::PowerPCState::ps[0]), PowerPC::PairedSingle&>);
|
||||||
|
#define PPCSTATE_OFF_PS0(i) (PPCSTATE_OFF_ARRAY(ps, i) + offsetof(PowerPC::PairedSingle, ps0))
|
||||||
|
#define PPCSTATE_OFF_PS1(i) (PPCSTATE_OFF_ARRAY(ps, i) + offsetof(PowerPC::PairedSingle, ps1))
|
||||||
|
|
||||||
|
#define PPCSTATE(i) MDisp(RPPCSTATE, PPCSTATE_OFF(i))
|
||||||
|
#define PPCSTATE_GPR(i) MDisp(RPPCSTATE, PPCSTATE_OFF_ARRAY(gpr, i))
|
||||||
|
#define PPCSTATE_CR(i) MDisp(RPPCSTATE, PPCSTATE_OFF_ARRAY(cr.fields, i))
|
||||||
|
#define PPCSTATE_SR(i) MDisp(RPPCSTATE, PPCSTATE_OFF_ARRAY(sr, i))
|
||||||
|
#define PPCSTATE_SPR(i) MDisp(RPPCSTATE, PPCSTATE_OFF_ARRAY(spr, i))
|
||||||
|
#define PPCSTATE_PS0(i) MDisp(RPPCSTATE, PPCSTATE_OFF_PS0(i))
|
||||||
|
#define PPCSTATE_PS1(i) MDisp(RPPCSTATE, PPCSTATE_OFF_PS1(i))
|
||||||
|
|
||||||
|
#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)
|
||||||
|
@ -38,7 +38,7 @@ constexpr size_t CODE_SIZE = 1024 * 1024 * 32;
|
|||||||
constexpr size_t FARCODE_SIZE = 1024 * 1024 * 64;
|
constexpr size_t FARCODE_SIZE = 1024 * 1024 * 64;
|
||||||
constexpr size_t FARCODE_SIZE_MMU = 1024 * 1024 * 64;
|
constexpr size_t FARCODE_SIZE_MMU = 1024 * 1024 * 64;
|
||||||
|
|
||||||
JitArm64::JitArm64() : m_float_emit(this)
|
JitArm64::JitArm64(Core::System& system) : JitBase(system), m_float_emit(this)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,11 @@
|
|||||||
class JitArm64 : public JitBase, public Arm64Gen::ARM64CodeBlock, public CommonAsmRoutinesBase
|
class JitArm64 : public JitBase, public Arm64Gen::ARM64CodeBlock, public CommonAsmRoutinesBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
JitArm64();
|
explicit JitArm64(Core::System& system);
|
||||||
|
JitArm64(const JitArm64&) = delete;
|
||||||
|
JitArm64(JitArm64&&) = delete;
|
||||||
|
JitArm64& operator=(const JitArm64&) = delete;
|
||||||
|
JitArm64& operator=(JitArm64&&) = delete;
|
||||||
~JitArm64() override;
|
~JitArm64() override;
|
||||||
|
|
||||||
void Init() override;
|
void Init() override;
|
||||||
|
@ -60,7 +60,8 @@ void JitTrampoline(JitBase& jit, u32 em_address)
|
|||||||
jit.Jit(em_address);
|
jit.Jit(em_address);
|
||||||
}
|
}
|
||||||
|
|
||||||
JitBase::JitBase() : m_code_buffer(code_buffer_size)
|
JitBase::JitBase(Core::System& system)
|
||||||
|
: m_code_buffer(code_buffer_size), m_system(system), m_ppc_state(system.GetPPCState())
|
||||||
{
|
{
|
||||||
m_registered_config_callback_id = Config::AddConfigChangedCallback(
|
m_registered_config_callback_id = Config::AddConfigChangedCallback(
|
||||||
[this] { Core::RunAsCPUThread([this] { RefreshConfig(); }); });
|
[this] { Core::RunAsCPUThread([this] { RefreshConfig(); }); });
|
||||||
@ -94,8 +95,8 @@ void JitBase::RefreshConfig()
|
|||||||
m_fprf = Config::Get(Config::MAIN_FPRF);
|
m_fprf = Config::Get(Config::MAIN_FPRF);
|
||||||
m_accurate_nans = Config::Get(Config::MAIN_ACCURATE_NANS);
|
m_accurate_nans = Config::Get(Config::MAIN_ACCURATE_NANS);
|
||||||
m_fastmem_enabled = Config::Get(Config::MAIN_FASTMEM);
|
m_fastmem_enabled = Config::Get(Config::MAIN_FASTMEM);
|
||||||
m_mmu_enabled = Core::System::GetInstance().IsMMUMode();
|
m_mmu_enabled = m_system.IsMMUMode();
|
||||||
m_pause_on_panic_enabled = Core::System::GetInstance().IsPauseOnPanicMode();
|
m_pause_on_panic_enabled = m_system.IsPauseOnPanicMode();
|
||||||
m_accurate_cpu_cache_enabled = Config::Get(Config::MAIN_ACCURATE_CPU_CACHE);
|
m_accurate_cpu_cache_enabled = Config::Get(Config::MAIN_ACCURATE_CPU_CACHE);
|
||||||
if (m_accurate_cpu_cache_enabled)
|
if (m_accurate_cpu_cache_enabled)
|
||||||
{
|
{
|
||||||
@ -192,7 +193,7 @@ bool JitBase::HandleStackFault()
|
|||||||
// to reset the guard page.
|
// to reset the guard page.
|
||||||
// Yeah, it's kind of gross.
|
// Yeah, it's kind of gross.
|
||||||
GetBlockCache()->InvalidateICache(0, 0xffffffff, true);
|
GetBlockCache()->InvalidateICache(0, 0xffffffff, true);
|
||||||
Core::System::GetInstance().GetCoreTiming().ForceExceptionCheck(0);
|
m_system.GetCoreTiming().ForceExceptionCheck(0);
|
||||||
m_cleanup_after_stackfault = true;
|
m_cleanup_after_stackfault = true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -213,8 +214,7 @@ void JitBase::CleanUpAfterStackFault()
|
|||||||
|
|
||||||
bool JitBase::CanMergeNextInstructions(int count) const
|
bool JitBase::CanMergeNextInstructions(int count) const
|
||||||
{
|
{
|
||||||
auto& system = Core::System::GetInstance();
|
if (m_system.GetCPU().IsStepping() || js.instructionsLeft < count)
|
||||||
if (system.GetCPU().IsStepping() || js.instructionsLeft < count)
|
|
||||||
return false;
|
return false;
|
||||||
// Be careful: a breakpoint kills flags in between instructions
|
// Be careful: a breakpoint kills flags in between instructions
|
||||||
for (int i = 1; i <= count; i++)
|
for (int i = 1; i <= count; i++)
|
||||||
@ -230,8 +230,7 @@ bool JitBase::CanMergeNextInstructions(int count) const
|
|||||||
void JitBase::UpdateMemoryAndExceptionOptions()
|
void JitBase::UpdateMemoryAndExceptionOptions()
|
||||||
{
|
{
|
||||||
bool any_watchpoints = PowerPC::memchecks.HasAny();
|
bool any_watchpoints = PowerPC::memchecks.HasAny();
|
||||||
jo.fastmem =
|
jo.fastmem = m_fastmem_enabled && jo.fastmem_arena && (m_ppc_state.msr.DR || !any_watchpoints);
|
||||||
m_fastmem_enabled && jo.fastmem_arena && (PowerPC::ppcState.msr.DR || !any_watchpoints);
|
|
||||||
jo.memcheck = m_mmu_enabled || m_pause_on_panic_enabled || any_watchpoints;
|
jo.memcheck = m_mmu_enabled || m_pause_on_panic_enabled || any_watchpoints;
|
||||||
jo.fp_exceptions = m_enable_float_exceptions;
|
jo.fp_exceptions = m_enable_float_exceptions;
|
||||||
jo.div_by_zero_exceptions = m_enable_div_by_zero_exceptions;
|
jo.div_by_zero_exceptions = m_enable_div_by_zero_exceptions;
|
||||||
|
@ -17,6 +17,15 @@
|
|||||||
#include "Core/PowerPC/JitCommon/JitCache.h"
|
#include "Core/PowerPC/JitCommon/JitCache.h"
|
||||||
#include "Core/PowerPC/PPCAnalyst.h"
|
#include "Core/PowerPC/PPCAnalyst.h"
|
||||||
|
|
||||||
|
namespace Core
|
||||||
|
{
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
namespace PowerPC
|
||||||
|
{
|
||||||
|
struct PowerPCState;
|
||||||
|
}
|
||||||
|
|
||||||
//#define JIT_LOG_GENERATED_CODE // Enables logging of generated code
|
//#define JIT_LOG_GENERATED_CODE // Enables logging of generated code
|
||||||
//#define JIT_LOG_GPR // Enables logging of the PPC general purpose regs
|
//#define JIT_LOG_GPR // Enables logging of the PPC general purpose regs
|
||||||
//#define JIT_LOG_FPR // Enables logging of the PPC floating point regs
|
//#define JIT_LOG_FPR // Enables logging of the PPC floating point regs
|
||||||
@ -162,7 +171,11 @@ protected:
|
|||||||
bool ShouldHandleFPExceptionForInstruction(const PPCAnalyst::CodeOp* op);
|
bool ShouldHandleFPExceptionForInstruction(const PPCAnalyst::CodeOp* op);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
JitBase();
|
explicit JitBase(Core::System& system);
|
||||||
|
JitBase(const JitBase&) = delete;
|
||||||
|
JitBase(JitBase&&) = delete;
|
||||||
|
JitBase& operator=(const JitBase&) = delete;
|
||||||
|
JitBase& operator=(JitBase&&) = delete;
|
||||||
~JitBase() override;
|
~JitBase() override;
|
||||||
|
|
||||||
bool IsDebuggingEnabled() const { return m_enable_debugging; }
|
bool IsDebuggingEnabled() const { return m_enable_debugging; }
|
||||||
@ -182,6 +195,9 @@ public:
|
|||||||
// This should probably be removed from public:
|
// This should probably be removed from public:
|
||||||
JitOptions jo{};
|
JitOptions jo{};
|
||||||
JitState js{};
|
JitState js{};
|
||||||
|
|
||||||
|
Core::System& m_system;
|
||||||
|
PowerPC::PowerPCState& m_ppc_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
void JitTrampoline(JitBase& jit, u32 em_address);
|
void JitTrampoline(JitBase& jit, u32 em_address);
|
||||||
|
@ -54,20 +54,22 @@ void DoState(PointerWrap& p)
|
|||||||
}
|
}
|
||||||
CPUCoreBase* InitJitCore(PowerPC::CPUCore core)
|
CPUCoreBase* InitJitCore(PowerPC::CPUCore core)
|
||||||
{
|
{
|
||||||
|
auto& system = Core::System::GetInstance();
|
||||||
|
|
||||||
switch (core)
|
switch (core)
|
||||||
{
|
{
|
||||||
#if _M_X86
|
#if _M_X86
|
||||||
case PowerPC::CPUCore::JIT64:
|
case PowerPC::CPUCore::JIT64:
|
||||||
g_jit = new Jit64();
|
g_jit = new Jit64(system);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#if _M_ARM_64
|
#if _M_ARM_64
|
||||||
case PowerPC::CPUCore::JITARM64:
|
case PowerPC::CPUCore::JITARM64:
|
||||||
g_jit = new JitArm64();
|
g_jit = new JitArm64(system);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case PowerPC::CPUCore::CachedInterpreter:
|
case PowerPC::CPUCore::CachedInterpreter:
|
||||||
g_jit = new CachedInterpreter();
|
g_jit = new CachedInterpreter(system);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "Core/MemTools.h"
|
#include "Core/MemTools.h"
|
||||||
#include "Core/PowerPC/JitCommon/JitBase.h"
|
#include "Core/PowerPC/JitCommon/JitBase.h"
|
||||||
#include "Core/PowerPC/JitInterface.h"
|
#include "Core/PowerPC/JitInterface.h"
|
||||||
|
#include "Core/System.h"
|
||||||
|
|
||||||
// include order is important
|
// include order is important
|
||||||
#include <gtest/gtest.h> // NOLINT
|
#include <gtest/gtest.h> // NOLINT
|
||||||
@ -25,6 +26,8 @@ enum
|
|||||||
class PageFaultFakeJit : public JitBase
|
class PageFaultFakeJit : public JitBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
explicit PageFaultFakeJit(Core::System& system) : JitBase(system) {}
|
||||||
|
|
||||||
// CPUCoreBase methods
|
// CPUCoreBase methods
|
||||||
void Init() override {}
|
void Init() override {}
|
||||||
void Shutdown() override {}
|
void Shutdown() override {}
|
||||||
@ -72,7 +75,7 @@ TEST(PageFault, PageFault)
|
|||||||
EXPECT_NE(data, nullptr);
|
EXPECT_NE(data, nullptr);
|
||||||
Common::WriteProtectMemory(data, PAGE_GRAN, false);
|
Common::WriteProtectMemory(data, PAGE_GRAN, false);
|
||||||
|
|
||||||
PageFaultFakeJit pfjit;
|
PageFaultFakeJit pfjit(Core::System::GetInstance());
|
||||||
JitInterface::SetJit(&pfjit);
|
JitInterface::SetJit(&pfjit);
|
||||||
pfjit.m_data = data;
|
pfjit.m_data = data;
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "Core/PowerPC/Jit64/Jit.h"
|
#include "Core/PowerPC/Jit64/Jit.h"
|
||||||
#include "Core/PowerPC/Jit64Common/Jit64AsmCommon.h"
|
#include "Core/PowerPC/Jit64Common/Jit64AsmCommon.h"
|
||||||
#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h"
|
#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h"
|
||||||
|
#include "Core/System.h"
|
||||||
|
|
||||||
#include "../TestValues.h"
|
#include "../TestValues.h"
|
||||||
|
|
||||||
@ -22,7 +23,7 @@ namespace
|
|||||||
class TestCommonAsmRoutines : public CommonAsmRoutines
|
class TestCommonAsmRoutines : public CommonAsmRoutines
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TestCommonAsmRoutines() : CommonAsmRoutines(jit)
|
explicit TestCommonAsmRoutines(Core::System& system) : CommonAsmRoutines(jit), jit(system)
|
||||||
{
|
{
|
||||||
using namespace Gen;
|
using namespace Gen;
|
||||||
|
|
||||||
@ -51,7 +52,7 @@ public:
|
|||||||
|
|
||||||
TEST(Jit64, ConvertDoubleToSingle)
|
TEST(Jit64, ConvertDoubleToSingle)
|
||||||
{
|
{
|
||||||
TestCommonAsmRoutines routines;
|
TestCommonAsmRoutines routines(Core::System::GetInstance());
|
||||||
|
|
||||||
for (const u64 input : double_test_values)
|
for (const u64 input : double_test_values)
|
||||||
{
|
{
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "Core/PowerPC/Jit64/Jit.h"
|
#include "Core/PowerPC/Jit64/Jit.h"
|
||||||
#include "Core/PowerPC/Jit64Common/Jit64AsmCommon.h"
|
#include "Core/PowerPC/Jit64Common/Jit64AsmCommon.h"
|
||||||
#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h"
|
#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h"
|
||||||
|
#include "Core/System.h"
|
||||||
|
|
||||||
#include "../TestValues.h"
|
#include "../TestValues.h"
|
||||||
|
|
||||||
@ -22,7 +23,7 @@ namespace
|
|||||||
class TestCommonAsmRoutines : public CommonAsmRoutines
|
class TestCommonAsmRoutines : public CommonAsmRoutines
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TestCommonAsmRoutines() : CommonAsmRoutines(jit)
|
explicit TestCommonAsmRoutines(Core::System& system) : CommonAsmRoutines(jit), jit(system)
|
||||||
{
|
{
|
||||||
using namespace Gen;
|
using namespace Gen;
|
||||||
|
|
||||||
@ -58,7 +59,7 @@ public:
|
|||||||
|
|
||||||
TEST(Jit64, Frsqrte)
|
TEST(Jit64, Frsqrte)
|
||||||
{
|
{
|
||||||
TestCommonAsmRoutines routines;
|
TestCommonAsmRoutines routines(Core::System::GetInstance());
|
||||||
|
|
||||||
UReg_FPSCR fpscr;
|
UReg_FPSCR fpscr;
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "Common/FPURoundMode.h"
|
#include "Common/FPURoundMode.h"
|
||||||
#include "Core/PowerPC/Interpreter/Interpreter_FPUtils.h"
|
#include "Core/PowerPC/Interpreter/Interpreter_FPUtils.h"
|
||||||
#include "Core/PowerPC/JitArm64/Jit.h"
|
#include "Core/PowerPC/JitArm64/Jit.h"
|
||||||
|
#include "Core/System.h"
|
||||||
|
|
||||||
#include "../TestValues.h"
|
#include "../TestValues.h"
|
||||||
|
|
||||||
@ -30,7 +31,7 @@ struct Pair
|
|||||||
class TestConversion : private JitArm64
|
class TestConversion : private JitArm64
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TestConversion()
|
explicit TestConversion(Core::System& system) : JitArm64(system)
|
||||||
{
|
{
|
||||||
const Common::ScopedJITPageWriteAndNoExecute enable_jit_page_writes;
|
const Common::ScopedJITPageWriteAndNoExecute enable_jit_page_writes;
|
||||||
|
|
||||||
@ -119,7 +120,7 @@ private:
|
|||||||
|
|
||||||
TEST(JitArm64, ConvertDoubleToSingle)
|
TEST(JitArm64, ConvertDoubleToSingle)
|
||||||
{
|
{
|
||||||
TestConversion test;
|
TestConversion test(Core::System::GetInstance());
|
||||||
|
|
||||||
for (const u64 input : double_test_values)
|
for (const u64 input : double_test_values)
|
||||||
{
|
{
|
||||||
@ -154,7 +155,7 @@ TEST(JitArm64, ConvertDoubleToSingle)
|
|||||||
|
|
||||||
TEST(JitArm64, ConvertSingleToDouble)
|
TEST(JitArm64, ConvertSingleToDouble)
|
||||||
{
|
{
|
||||||
TestConversion test;
|
TestConversion test(Core::System::GetInstance());
|
||||||
|
|
||||||
for (const u32 input : single_test_values)
|
for (const u32 input : single_test_values)
|
||||||
{
|
{
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "Core/PowerPC/Interpreter/Interpreter_FPUtils.h"
|
#include "Core/PowerPC/Interpreter/Interpreter_FPUtils.h"
|
||||||
#include "Core/PowerPC/JitArm64/Jit.h"
|
#include "Core/PowerPC/JitArm64/Jit.h"
|
||||||
#include "Core/PowerPC/PowerPC.h"
|
#include "Core/PowerPC/PowerPC.h"
|
||||||
|
#include "Core/System.h"
|
||||||
|
|
||||||
#include "../TestValues.h"
|
#include "../TestValues.h"
|
||||||
|
|
||||||
@ -22,7 +23,7 @@ using namespace Arm64Gen;
|
|||||||
class TestFPRF : public JitArm64
|
class TestFPRF : public JitArm64
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TestFPRF()
|
explicit TestFPRF(Core::System& system) : JitArm64(system)
|
||||||
{
|
{
|
||||||
const Common::ScopedJITPageWriteAndNoExecute enable_jit_page_writes;
|
const Common::ScopedJITPageWriteAndNoExecute enable_jit_page_writes;
|
||||||
|
|
||||||
@ -67,7 +68,7 @@ static u32 RunUpdateFPRF(const std::function<void()>& f)
|
|||||||
|
|
||||||
TEST(JitArm64, FPRF)
|
TEST(JitArm64, FPRF)
|
||||||
{
|
{
|
||||||
TestFPRF test;
|
TestFPRF test(Core::System::GetInstance());
|
||||||
|
|
||||||
for (const u64 double_input : double_test_values)
|
for (const u64 double_input : double_test_values)
|
||||||
{
|
{
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "Core/PowerPC/Interpreter/Interpreter_FPUtils.h"
|
#include "Core/PowerPC/Interpreter/Interpreter_FPUtils.h"
|
||||||
#include "Core/PowerPC/JitArm64/Jit.h"
|
#include "Core/PowerPC/JitArm64/Jit.h"
|
||||||
#include "Core/PowerPC/PowerPC.h"
|
#include "Core/PowerPC/PowerPC.h"
|
||||||
|
#include "Core/System.h"
|
||||||
|
|
||||||
#include "../TestValues.h"
|
#include "../TestValues.h"
|
||||||
|
|
||||||
@ -21,7 +22,7 @@ using namespace Arm64Gen;
|
|||||||
class TestFres : public JitArm64
|
class TestFres : public JitArm64
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TestFres()
|
explicit TestFres(Core::System& system) : JitArm64(system)
|
||||||
{
|
{
|
||||||
const Common::ScopedJITPageWriteAndNoExecute enable_jit_page_writes;
|
const Common::ScopedJITPageWriteAndNoExecute enable_jit_page_writes;
|
||||||
|
|
||||||
@ -50,7 +51,7 @@ public:
|
|||||||
|
|
||||||
TEST(JitArm64, Fres)
|
TEST(JitArm64, Fres)
|
||||||
{
|
{
|
||||||
TestFres test;
|
TestFres test(Core::System::GetInstance());
|
||||||
|
|
||||||
for (const u64 ivalue : double_test_values)
|
for (const u64 ivalue : double_test_values)
|
||||||
{
|
{
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "Core/PowerPC/Interpreter/Interpreter_FPUtils.h"
|
#include "Core/PowerPC/Interpreter/Interpreter_FPUtils.h"
|
||||||
#include "Core/PowerPC/JitArm64/Jit.h"
|
#include "Core/PowerPC/JitArm64/Jit.h"
|
||||||
#include "Core/PowerPC/PowerPC.h"
|
#include "Core/PowerPC/PowerPC.h"
|
||||||
|
#include "Core/System.h"
|
||||||
|
|
||||||
#include "../TestValues.h"
|
#include "../TestValues.h"
|
||||||
|
|
||||||
@ -21,7 +22,7 @@ using namespace Arm64Gen;
|
|||||||
class TestFrsqrte : public JitArm64
|
class TestFrsqrte : public JitArm64
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TestFrsqrte()
|
explicit TestFrsqrte(Core::System& system) : JitArm64(system)
|
||||||
{
|
{
|
||||||
const Common::ScopedJITPageWriteAndNoExecute enable_jit_page_writes;
|
const Common::ScopedJITPageWriteAndNoExecute enable_jit_page_writes;
|
||||||
|
|
||||||
@ -50,7 +51,7 @@ public:
|
|||||||
|
|
||||||
TEST(JitArm64, Frsqrte)
|
TEST(JitArm64, Frsqrte)
|
||||||
{
|
{
|
||||||
TestFrsqrte test;
|
TestFrsqrte test(Core::System::GetInstance());
|
||||||
|
|
||||||
for (const u64 ivalue : double_test_values)
|
for (const u64 ivalue : double_test_values)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user