Merge pull request #11717 from AdmiralCurtiss/ppcstate-rest
Replace most remaining global ppcState references.
This commit is contained in:
commit
5686c614ec
|
@ -16,6 +16,7 @@
|
||||||
#include "Core/PowerPC/Expression.h"
|
#include "Core/PowerPC/Expression.h"
|
||||||
#include "Core/PowerPC/JitInterface.h"
|
#include "Core/PowerPC/JitInterface.h"
|
||||||
#include "Core/PowerPC/MMU.h"
|
#include "Core/PowerPC/MMU.h"
|
||||||
|
#include "Core/PowerPC/PowerPC.h"
|
||||||
#include "Core/System.h"
|
#include "Core/System.h"
|
||||||
|
|
||||||
bool BreakPoints::IsAddressBreakPoint(u32 address) const
|
bool BreakPoints::IsAddressBreakPoint(u32 address) const
|
||||||
|
@ -352,14 +353,14 @@ bool MemChecks::OverlapsMemcheck(u32 address, u32 length) const
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TMemCheck::Action(Common::DebugInterface* debug_interface, u64 value, u32 addr, bool write,
|
bool TMemCheck::Action(Core::System& system, Common::DebugInterface* debug_interface, u64 value,
|
||||||
size_t size, u32 pc)
|
u32 addr, bool write, size_t size, u32 pc)
|
||||||
{
|
{
|
||||||
if (!is_enabled)
|
if (!is_enabled)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (((write && is_break_on_write) || (!write && is_break_on_read)) &&
|
if (((write && is_break_on_write) || (!write && is_break_on_read)) &&
|
||||||
EvaluateCondition(this->condition))
|
EvaluateCondition(system, this->condition))
|
||||||
{
|
{
|
||||||
if (log_on_hit)
|
if (log_on_hit)
|
||||||
{
|
{
|
||||||
|
|
|
@ -45,8 +45,8 @@ struct TMemCheck
|
||||||
std::optional<Expression> condition;
|
std::optional<Expression> condition;
|
||||||
|
|
||||||
// returns whether to break
|
// returns whether to break
|
||||||
bool Action(Common::DebugInterface* debug_interface, u64 value, u32 addr, bool write, size_t size,
|
bool Action(Core::System& system, Common::DebugInterface* debug_interface, u64 value, u32 addr,
|
||||||
u32 pc);
|
bool write, size_t size, u32 pc);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Code breakpoints.
|
// Code breakpoints.
|
||||||
|
|
|
@ -267,21 +267,22 @@ std::optional<Expression> Expression::TryParse(std::string_view text)
|
||||||
return Expression{text, std::move(ex), std::move(vars)};
|
return Expression{text, std::move(ex), std::move(vars)};
|
||||||
}
|
}
|
||||||
|
|
||||||
double Expression::Evaluate() const
|
double Expression::Evaluate(Core::System& system) const
|
||||||
{
|
{
|
||||||
SynchronizeBindings(SynchronizeDirection::From);
|
SynchronizeBindings(system, SynchronizeDirection::From);
|
||||||
|
|
||||||
double result = expr_eval(m_expr.get());
|
double result = expr_eval(m_expr.get());
|
||||||
|
|
||||||
SynchronizeBindings(SynchronizeDirection::To);
|
SynchronizeBindings(system, SynchronizeDirection::To);
|
||||||
|
|
||||||
Reporting(result);
|
Reporting(result);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Expression::SynchronizeBindings(SynchronizeDirection dir) const
|
void Expression::SynchronizeBindings(Core::System& system, SynchronizeDirection dir) const
|
||||||
{
|
{
|
||||||
|
auto& ppc_state = system.GetPPCState();
|
||||||
auto bind = m_binds.begin();
|
auto bind = m_binds.begin();
|
||||||
for (auto* v = m_vars->head; v != nullptr; v = v->next, ++bind)
|
for (auto* v = m_vars->head; v != nullptr; v = v->next, ++bind)
|
||||||
{
|
{
|
||||||
|
@ -293,25 +294,25 @@ void Expression::SynchronizeBindings(SynchronizeDirection dir) const
|
||||||
break;
|
break;
|
||||||
case VarBindingType::GPR:
|
case VarBindingType::GPR:
|
||||||
if (dir == SynchronizeDirection::From)
|
if (dir == SynchronizeDirection::From)
|
||||||
v->value = static_cast<double>(PowerPC::ppcState.gpr[bind->index]);
|
v->value = static_cast<double>(ppc_state.gpr[bind->index]);
|
||||||
else
|
else
|
||||||
PowerPC::ppcState.gpr[bind->index] = static_cast<u32>(static_cast<s64>(v->value));
|
ppc_state.gpr[bind->index] = static_cast<u32>(static_cast<s64>(v->value));
|
||||||
break;
|
break;
|
||||||
case VarBindingType::FPR:
|
case VarBindingType::FPR:
|
||||||
if (dir == SynchronizeDirection::From)
|
if (dir == SynchronizeDirection::From)
|
||||||
v->value = PowerPC::ppcState.ps[bind->index].PS0AsDouble();
|
v->value = ppc_state.ps[bind->index].PS0AsDouble();
|
||||||
else
|
else
|
||||||
PowerPC::ppcState.ps[bind->index].SetPS0(v->value);
|
ppc_state.ps[bind->index].SetPS0(v->value);
|
||||||
break;
|
break;
|
||||||
case VarBindingType::SPR:
|
case VarBindingType::SPR:
|
||||||
if (dir == SynchronizeDirection::From)
|
if (dir == SynchronizeDirection::From)
|
||||||
v->value = static_cast<double>(PowerPC::ppcState.spr[bind->index]);
|
v->value = static_cast<double>(ppc_state.spr[bind->index]);
|
||||||
else
|
else
|
||||||
PowerPC::ppcState.spr[bind->index] = static_cast<u32>(static_cast<s64>(v->value));
|
ppc_state.spr[bind->index] = static_cast<u32>(static_cast<s64>(v->value));
|
||||||
break;
|
break;
|
||||||
case VarBindingType::PCtr:
|
case VarBindingType::PCtr:
|
||||||
if (dir == SynchronizeDirection::From)
|
if (dir == SynchronizeDirection::From)
|
||||||
v->value = static_cast<double>(PowerPC::ppcState.pc);
|
v->value = static_cast<double>(ppc_state.pc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,8 @@ struct expr_var_list;
|
||||||
namespace Core
|
namespace Core
|
||||||
{
|
{
|
||||||
class CPUThreadGuard;
|
class CPUThreadGuard;
|
||||||
}
|
class System;
|
||||||
|
} // namespace Core
|
||||||
|
|
||||||
struct ExprDeleter
|
struct ExprDeleter
|
||||||
{
|
{
|
||||||
|
@ -36,7 +37,7 @@ class Expression
|
||||||
public:
|
public:
|
||||||
static std::optional<Expression> TryParse(std::string_view text);
|
static std::optional<Expression> TryParse(std::string_view text);
|
||||||
|
|
||||||
double Evaluate() const;
|
double Evaluate(Core::System& system) const;
|
||||||
|
|
||||||
std::string GetText() const;
|
std::string GetText() const;
|
||||||
|
|
||||||
|
@ -64,7 +65,7 @@ private:
|
||||||
|
|
||||||
Expression(std::string_view text, ExprPointer ex, ExprVarListPointer vars);
|
Expression(std::string_view text, ExprPointer ex, ExprVarListPointer vars);
|
||||||
|
|
||||||
void SynchronizeBindings(SynchronizeDirection dir) const;
|
void SynchronizeBindings(Core::System& system, SynchronizeDirection dir) const;
|
||||||
void Reporting(const double result) const;
|
void Reporting(const double result) const;
|
||||||
|
|
||||||
std::string m_text;
|
std::string m_text;
|
||||||
|
@ -73,7 +74,7 @@ private:
|
||||||
std::vector<VarBinding> m_binds;
|
std::vector<VarBinding> m_binds;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool EvaluateCondition(const std::optional<Expression>& condition)
|
inline bool EvaluateCondition(Core::System& system, const std::optional<Expression>& condition)
|
||||||
{
|
{
|
||||||
return !condition || condition->Evaluate() != 0.0;
|
return !condition || condition->Evaluate(system) != 0.0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,13 +120,13 @@ int Interpreter::SingleStepInner()
|
||||||
// TODO: Does it make sense to use m_prev_inst here?
|
// TODO: Does it make sense to use m_prev_inst here?
|
||||||
// It seems like we should use the num_cycles for the instruction at PC instead
|
// It seems like we should use the num_cycles for the instruction at PC instead
|
||||||
// (m_prev_inst has not yet been updated)
|
// (m_prev_inst has not yet been updated)
|
||||||
return PPCTables::GetOpInfo(m_prev_inst)->num_cycles;
|
return PPCTables::GetOpInfo(m_prev_inst, m_ppc_state.pc)->num_cycles;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ppc_state.npc = m_ppc_state.pc + sizeof(UGeckoInstruction);
|
m_ppc_state.npc = m_ppc_state.pc + sizeof(UGeckoInstruction);
|
||||||
m_prev_inst.hex = m_mmu.Read_Opcode(m_ppc_state.pc);
|
m_prev_inst.hex = m_mmu.Read_Opcode(m_ppc_state.pc);
|
||||||
|
|
||||||
const GekkoOPInfo* opinfo = PPCTables::GetOpInfo(m_prev_inst);
|
const GekkoOPInfo* opinfo = PPCTables::GetOpInfo(m_prev_inst, m_ppc_state.pc);
|
||||||
|
|
||||||
// Uncomment to trace the interpreter
|
// Uncomment to trace the interpreter
|
||||||
// if ((m_ppc_state.pc & 0x00FFFFFF) >= 0x000AB54C &&
|
// if ((m_ppc_state.pc & 0x00FFFFFF) >= 0x000AB54C &&
|
||||||
|
|
|
@ -32,7 +32,7 @@ struct PowerPCState;
|
||||||
|
|
||||||
// Use these to control the instruction selection
|
// Use these to control the instruction selection
|
||||||
// #define INSTRUCTION_START FallBackToInterpreter(inst); return;
|
// #define INSTRUCTION_START FallBackToInterpreter(inst); return;
|
||||||
// #define INSTRUCTION_START PPCTables::CountInstruction(inst);
|
// #define INSTRUCTION_START PPCTables::CountInstruction(inst, m_ppc_state.pc);
|
||||||
#define INSTRUCTION_START
|
#define INSTRUCTION_START
|
||||||
|
|
||||||
#define FALLBACK_IF(cond) \
|
#define FALLBACK_IF(cond) \
|
||||||
|
|
|
@ -163,14 +163,13 @@ JitInterface::GetHostCode(u32 address) const
|
||||||
return GetHostCodeError::NoJitActive;
|
return GetHostCodeError::NoJitActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
JitBlock* block =
|
auto& ppc_state = m_system.GetPPCState();
|
||||||
m_jit->GetBlockCache()->GetBlockFromStartAddress(address, PowerPC::ppcState.msr.Hex);
|
JitBlock* block = m_jit->GetBlockCache()->GetBlockFromStartAddress(address, ppc_state.msr.Hex);
|
||||||
if (!block)
|
if (!block)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 500; i++)
|
for (int i = 0; i < 500; i++)
|
||||||
{
|
{
|
||||||
block = m_jit->GetBlockCache()->GetBlockFromStartAddress(address - 4 * i,
|
block = m_jit->GetBlockCache()->GetBlockFromStartAddress(address - 4 * i, ppc_state.msr.Hex);
|
||||||
PowerPC::ppcState.msr.Hex);
|
|
||||||
if (block)
|
if (block)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -287,25 +286,26 @@ void JitInterface::CompileExceptionCheck(ExceptionType type)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PowerPC::ppcState.pc != 0 &&
|
auto& ppc_state = m_system.GetPPCState();
|
||||||
(exception_addresses->find(PowerPC::ppcState.pc)) == (exception_addresses->end()))
|
if (ppc_state.pc != 0 &&
|
||||||
|
(exception_addresses->find(ppc_state.pc)) == (exception_addresses->end()))
|
||||||
{
|
{
|
||||||
if (type == ExceptionType::FIFOWrite)
|
if (type == ExceptionType::FIFOWrite)
|
||||||
{
|
{
|
||||||
ASSERT(Core::IsCPUThread());
|
ASSERT(Core::IsCPUThread());
|
||||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
Core::CPUThreadGuard guard(m_system);
|
||||||
|
|
||||||
// Check in case the code has been replaced since: do we need to do this?
|
// Check in case the code has been replaced since: do we need to do this?
|
||||||
const OpType optype =
|
const OpType optype =
|
||||||
PPCTables::GetOpInfo(PowerPC::MMU::HostRead_U32(guard, PowerPC::ppcState.pc))->type;
|
PPCTables::GetOpInfo(PowerPC::MMU::HostRead_U32(guard, ppc_state.pc), ppc_state.pc)->type;
|
||||||
if (optype != OpType::Store && optype != OpType::StoreFP && optype != OpType::StorePS)
|
if (optype != OpType::Store && optype != OpType::StoreFP && optype != OpType::StorePS)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
exception_addresses->insert(PowerPC::ppcState.pc);
|
exception_addresses->insert(ppc_state.pc);
|
||||||
|
|
||||||
// Invalidate the JIT block so that it gets recompiled with the external exception check
|
// Invalidate the JIT block so that it gets recompiled with the external exception check
|
||||||
// included.
|
// included.
|
||||||
m_jit->GetBlockCache()->InvalidateICache(PowerPC::ppcState.pc, 4, true);
|
m_jit->GetBlockCache()->InvalidateICache(ppc_state.pc, 4, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -545,7 +545,8 @@ void MMU::Memcheck(u32 address, u64 var, bool write, size_t size)
|
||||||
|
|
||||||
mc->num_hits++;
|
mc->num_hits++;
|
||||||
|
|
||||||
const bool pause = mc->Action(&debug_interface, var, address, write, size, m_ppc_state.pc);
|
const bool pause =
|
||||||
|
mc->Action(m_system, &debug_interface, var, address, write, size, m_ppc_state.pc);
|
||||||
if (!pause)
|
if (!pause)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -114,7 +114,7 @@ bool AnalyzeFunction(const Core::CPUThreadGuard& guard, u32 startAddr, Common::S
|
||||||
}
|
}
|
||||||
const PowerPC::TryReadInstResult read_result = mmu.TryReadInstruction(addr);
|
const PowerPC::TryReadInstResult read_result = mmu.TryReadInstruction(addr);
|
||||||
const UGeckoInstruction instr = read_result.hex;
|
const UGeckoInstruction instr = read_result.hex;
|
||||||
if (read_result.valid && PPCTables::IsValidInstruction(instr))
|
if (read_result.valid && PPCTables::IsValidInstruction(instr, addr))
|
||||||
{
|
{
|
||||||
// BLR or RFI
|
// BLR or RFI
|
||||||
// 4e800021 is blrl, not the end of a function
|
// 4e800021 is blrl, not the end of a function
|
||||||
|
@ -274,7 +274,7 @@ static void FindFunctionsFromBranches(const Core::CPUThreadGuard& guard, u32 sta
|
||||||
const PowerPC::TryReadInstResult read_result = mmu.TryReadInstruction(addr);
|
const PowerPC::TryReadInstResult read_result = mmu.TryReadInstruction(addr);
|
||||||
const UGeckoInstruction instr = read_result.hex;
|
const UGeckoInstruction instr = read_result.hex;
|
||||||
|
|
||||||
if (read_result.valid && PPCTables::IsValidInstruction(instr))
|
if (read_result.valid && PPCTables::IsValidInstruction(instr, addr))
|
||||||
{
|
{
|
||||||
switch (instr.OPCD)
|
switch (instr.OPCD)
|
||||||
{
|
{
|
||||||
|
@ -323,7 +323,7 @@ static void FindFunctionsFromHandlers(const Core::CPUThreadGuard& guard, PPCSymb
|
||||||
for (const auto& entry : handlers)
|
for (const auto& entry : handlers)
|
||||||
{
|
{
|
||||||
const PowerPC::TryReadInstResult read_result = mmu.TryReadInstruction(entry.first);
|
const PowerPC::TryReadInstResult read_result = mmu.TryReadInstruction(entry.first);
|
||||||
if (read_result.valid && PPCTables::IsValidInstruction(read_result.hex))
|
if (read_result.valid && PPCTables::IsValidInstruction(read_result.hex, entry.first))
|
||||||
{
|
{
|
||||||
// Check if this function is already mapped
|
// Check if this function is already mapped
|
||||||
Common::Symbol* f = func_db->AddFunction(guard, entry.first);
|
Common::Symbol* f = func_db->AddFunction(guard, entry.first);
|
||||||
|
@ -357,7 +357,7 @@ static void FindFunctionsAfterReturnInstruction(const Core::CPUThreadGuard& guar
|
||||||
location += 4;
|
location += 4;
|
||||||
read_result = mmu.TryReadInstruction(location);
|
read_result = mmu.TryReadInstruction(location);
|
||||||
}
|
}
|
||||||
if (read_result.valid && PPCTables::IsValidInstruction(read_result.hex))
|
if (read_result.valid && PPCTables::IsValidInstruction(read_result.hex, location))
|
||||||
{
|
{
|
||||||
// check if this function is already mapped
|
// check if this function is already mapped
|
||||||
Common::Symbol* f = func_db->AddFunction(guard, location);
|
Common::Symbol* f = func_db->AddFunction(guard, location);
|
||||||
|
@ -778,7 +778,7 @@ u32 PPCAnalyzer::Analyze(u32 address, CodeBlock* block, CodeBuffer* buffer,
|
||||||
num_inst++;
|
num_inst++;
|
||||||
|
|
||||||
const UGeckoInstruction inst = result.hex;
|
const UGeckoInstruction inst = result.hex;
|
||||||
const GekkoOPInfo* opinfo = PPCTables::GetOpInfo(inst);
|
const GekkoOPInfo* opinfo = PPCTables::GetOpInfo(inst, address);
|
||||||
code[i] = {};
|
code[i] = {};
|
||||||
code[i].opinfo = opinfo;
|
code[i].opinfo = opinfo;
|
||||||
code[i].address = address;
|
code[i].address = address;
|
||||||
|
|
|
@ -392,19 +392,21 @@ void Cache::DoState(PointerWrap& p)
|
||||||
u32 InstructionCache::ReadInstruction(u32 addr)
|
u32 InstructionCache::ReadInstruction(u32 addr)
|
||||||
{
|
{
|
||||||
auto& system = Core::System::GetInstance();
|
auto& system = Core::System::GetInstance();
|
||||||
auto& memory = system.GetMemory();
|
auto& ppc_state = system.GetPPCState();
|
||||||
|
|
||||||
if (!HID0(PowerPC::ppcState).ICE || m_disable_icache) // instruction cache is disabled
|
if (!HID0(ppc_state).ICE || m_disable_icache) // instruction cache is disabled
|
||||||
return memory.Read_U32(addr);
|
return system.GetMemory().Read_U32(addr);
|
||||||
|
|
||||||
u32 value;
|
u32 value;
|
||||||
Read(addr, &value, sizeof(value), HID0(PowerPC::ppcState).ILOCK);
|
Read(addr, &value, sizeof(value), HID0(ppc_state).ILOCK);
|
||||||
return Common::swap32(value);
|
return Common::swap32(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstructionCache::Invalidate(u32 addr)
|
void InstructionCache::Invalidate(u32 addr)
|
||||||
{
|
{
|
||||||
if (!HID0(PowerPC::ppcState).ICE || m_disable_icache)
|
auto& system = Core::System::GetInstance();
|
||||||
|
auto& ppc_state = system.GetPPCState();
|
||||||
|
if (!HID0(ppc_state).ICE || m_disable_icache)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Invalidates the whole set
|
// Invalidates the whole set
|
||||||
|
@ -424,7 +426,7 @@ void InstructionCache::Invalidate(u32 addr)
|
||||||
valid[set] = 0;
|
valid[set] = 0;
|
||||||
modified[set] = 0;
|
modified[set] = 0;
|
||||||
|
|
||||||
Core::System::GetInstance().GetJitInterface().InvalidateICacheLine(addr);
|
system.GetJitInterface().InvalidateICacheLine(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstructionCache::RefreshConfig()
|
void InstructionCache::RefreshConfig()
|
||||||
|
|
|
@ -613,7 +613,7 @@ constexpr Tables s_tables = []() consteval
|
||||||
}
|
}
|
||||||
();
|
();
|
||||||
|
|
||||||
const GekkoOPInfo* GetOpInfo(UGeckoInstruction inst)
|
const GekkoOPInfo* GetOpInfo(UGeckoInstruction inst, u32 pc)
|
||||||
{
|
{
|
||||||
const GekkoOPInfo* info = &s_tables.all_instructions[s_tables.primary_table[inst.OPCD]];
|
const GekkoOPInfo* info = &s_tables.all_instructions[s_tables.primary_table[inst.OPCD]];
|
||||||
if (info->type == OpType::Subtable)
|
if (info->type == OpType::Subtable)
|
||||||
|
@ -631,8 +631,7 @@ const GekkoOPInfo* GetOpInfo(UGeckoInstruction inst)
|
||||||
case 63:
|
case 63:
|
||||||
return &s_tables.all_instructions[s_tables.table63[inst.SUBOP10]];
|
return &s_tables.all_instructions[s_tables.table63[inst.SUBOP10]];
|
||||||
default:
|
default:
|
||||||
ASSERT_MSG(POWERPC, 0, "GetOpInfo - invalid subtable op {:08x} @ {:08x}", inst.hex,
|
ASSERT_MSG(POWERPC, 0, "GetOpInfo - invalid subtable op {:08x} @ {:08x}", inst.hex, pc);
|
||||||
PowerPC::ppcState.pc);
|
|
||||||
return &s_tables.all_instructions[s_tables.unknown_op_info];
|
return &s_tables.all_instructions[s_tables.unknown_op_info];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -640,8 +639,7 @@ const GekkoOPInfo* GetOpInfo(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
if (info->type == OpType::Invalid)
|
if (info->type == OpType::Invalid)
|
||||||
{
|
{
|
||||||
ASSERT_MSG(POWERPC, 0, "GetOpInfo - invalid op {:08x} @ {:08x}", inst.hex,
|
ASSERT_MSG(POWERPC, 0, "GetOpInfo - invalid op {:08x} @ {:08x}", inst.hex, pc);
|
||||||
PowerPC::ppcState.pc);
|
|
||||||
return &s_tables.all_instructions[s_tables.unknown_op_info];
|
return &s_tables.all_instructions[s_tables.unknown_op_info];
|
||||||
}
|
}
|
||||||
return info;
|
return info;
|
||||||
|
@ -658,21 +656,21 @@ std::vector<u32> rsplocations;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const char* GetInstructionName(UGeckoInstruction inst)
|
const char* GetInstructionName(UGeckoInstruction inst, u32 pc)
|
||||||
{
|
{
|
||||||
const GekkoOPInfo* info = GetOpInfo(inst);
|
const GekkoOPInfo* info = GetOpInfo(inst, pc);
|
||||||
return info->opname;
|
return info->opname;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsValidInstruction(UGeckoInstruction inst)
|
bool IsValidInstruction(UGeckoInstruction inst, u32 pc)
|
||||||
{
|
{
|
||||||
const GekkoOPInfo* info = GetOpInfo(inst);
|
const GekkoOPInfo* info = GetOpInfo(inst, pc);
|
||||||
return info->type != OpType::Invalid && info->type != OpType::Unknown;
|
return info->type != OpType::Invalid && info->type != OpType::Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CountInstruction(UGeckoInstruction inst)
|
void CountInstruction(UGeckoInstruction inst, u32 pc)
|
||||||
{
|
{
|
||||||
const GekkoOPInfo* info = GetOpInfo(inst);
|
const GekkoOPInfo* info = GetOpInfo(inst, pc);
|
||||||
info->stats->run_count++;
|
info->stats->run_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -118,13 +118,13 @@ struct GekkoOPInfo
|
||||||
|
|
||||||
namespace PPCTables
|
namespace PPCTables
|
||||||
{
|
{
|
||||||
const GekkoOPInfo* GetOpInfo(UGeckoInstruction inst);
|
const GekkoOPInfo* GetOpInfo(UGeckoInstruction inst, u32 pc);
|
||||||
|
|
||||||
bool IsValidInstruction(UGeckoInstruction inst);
|
bool IsValidInstruction(UGeckoInstruction inst, u32 pc);
|
||||||
|
|
||||||
void CountInstruction(UGeckoInstruction inst);
|
void CountInstruction(UGeckoInstruction inst, u32 pc);
|
||||||
void CountInstructionCompile(const GekkoOPInfo* info, u32 pc);
|
void CountInstructionCompile(const GekkoOPInfo* info, u32 pc);
|
||||||
void PrintInstructionRunCounts();
|
void PrintInstructionRunCounts();
|
||||||
void LogCompiledInstructions();
|
void LogCompiledInstructions();
|
||||||
const char* GetInstructionName(UGeckoInstruction inst);
|
const char* GetInstructionName(UGeckoInstruction inst, u32 pc);
|
||||||
} // namespace PPCTables
|
} // namespace PPCTables
|
||||||
|
|
|
@ -645,7 +645,7 @@ void CheckBreakPoints()
|
||||||
{
|
{
|
||||||
const TBreakPoint* bp = PowerPC::breakpoints.GetBreakpoint(PowerPC::ppcState.pc);
|
const TBreakPoint* bp = PowerPC::breakpoints.GetBreakpoint(PowerPC::ppcState.pc);
|
||||||
|
|
||||||
if (!bp || !bp->is_enabled || !EvaluateCondition(bp->condition))
|
if (!bp || !bp->is_enabled || !EvaluateCondition(Core::System::GetInstance(), bp->condition))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (bp->break_on_hit)
|
if (bp->break_on_hit)
|
||||||
|
|
|
@ -135,7 +135,7 @@ constexpr int CODE_VIEW_COLUMN_DESCRIPTION = 4;
|
||||||
constexpr int CODE_VIEW_COLUMN_BRANCH_ARROWS = 5;
|
constexpr int CODE_VIEW_COLUMN_BRANCH_ARROWS = 5;
|
||||||
constexpr int CODE_VIEW_COLUMNCOUNT = 6;
|
constexpr int CODE_VIEW_COLUMNCOUNT = 6;
|
||||||
|
|
||||||
CodeViewWidget::CodeViewWidget()
|
CodeViewWidget::CodeViewWidget() : m_system(Core::System::GetInstance())
|
||||||
{
|
{
|
||||||
setColumnCount(CODE_VIEW_COLUMNCOUNT);
|
setColumnCount(CODE_VIEW_COLUMNCOUNT);
|
||||||
setShowGrid(false);
|
setShowGrid(false);
|
||||||
|
@ -168,11 +168,11 @@ CodeViewWidget::CodeViewWidget()
|
||||||
&CodeViewWidget::FontBasedSizing);
|
&CodeViewWidget::FontBasedSizing);
|
||||||
|
|
||||||
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this] {
|
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this] {
|
||||||
m_address = PowerPC::ppcState.pc;
|
m_address = m_system.GetPPCState().pc;
|
||||||
Update();
|
Update();
|
||||||
});
|
});
|
||||||
connect(Host::GetInstance(), &Host::UpdateDisasmDialog, this, [this] {
|
connect(Host::GetInstance(), &Host::UpdateDisasmDialog, this, [this] {
|
||||||
m_address = PowerPC::ppcState.pc;
|
m_address = m_system.GetPPCState().pc;
|
||||||
Update();
|
Update();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -259,7 +259,7 @@ void CodeViewWidget::Update()
|
||||||
|
|
||||||
if (Core::GetState() == Core::State::Paused)
|
if (Core::GetState() == Core::State::Paused)
|
||||||
{
|
{
|
||||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
Core::CPUThreadGuard guard(m_system);
|
||||||
Update(&guard);
|
Update(&guard);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -294,7 +294,8 @@ void CodeViewWidget::Update(const Core::CPUThreadGuard* guard)
|
||||||
for (int i = 0; i < rows; i++)
|
for (int i = 0; i < rows; i++)
|
||||||
setRowHeight(i, rowh);
|
setRowHeight(i, rowh);
|
||||||
|
|
||||||
const std::optional<u32> pc = guard ? std::make_optional(PowerPC::ppcState.pc) : std::nullopt;
|
const std::optional<u32> pc =
|
||||||
|
guard ? std::make_optional(m_system.GetPPCState().pc) : std::nullopt;
|
||||||
|
|
||||||
const bool dark_theme = qApp->palette().color(QPalette::Base).valueF() < 0.5;
|
const bool dark_theme = qApp->palette().color(QPalette::Base).valueF() < 0.5;
|
||||||
|
|
||||||
|
@ -533,7 +534,7 @@ void CodeViewWidget::SetAddress(u32 address, SetAddressUpdate update)
|
||||||
|
|
||||||
void CodeViewWidget::ReplaceAddress(u32 address, ReplaceWith replace)
|
void CodeViewWidget::ReplaceAddress(u32 address, ReplaceWith replace)
|
||||||
{
|
{
|
||||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
Core::CPUThreadGuard guard(m_system);
|
||||||
|
|
||||||
PowerPC::debug_interface.SetPatch(guard, address,
|
PowerPC::debug_interface.SetPatch(guard, address,
|
||||||
replace == ReplaceWith::BLR ? 0x4e800020 : 0x60000000);
|
replace == ReplaceWith::BLR ? 0x4e800020 : 0x60000000);
|
||||||
|
@ -595,10 +596,11 @@ void CodeViewWidget::OnContextMenu()
|
||||||
bool follow_branch_enabled = false;
|
bool follow_branch_enabled = false;
|
||||||
if (paused)
|
if (paused)
|
||||||
{
|
{
|
||||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
Core::CPUThreadGuard guard(m_system);
|
||||||
const std::string disasm = PowerPC::debug_interface.Disassemble(&guard, PowerPC::ppcState.pc);
|
const u32 pc = m_system.GetPPCState().pc;
|
||||||
|
const std::string disasm = PowerPC::debug_interface.Disassemble(&guard, pc);
|
||||||
|
|
||||||
if (addr == PowerPC::ppcState.pc)
|
if (addr == pc)
|
||||||
{
|
{
|
||||||
const auto target_it = std::find(disasm.begin(), disasm.end(), '\t');
|
const auto target_it = std::find(disasm.begin(), disasm.end(), '\t');
|
||||||
const auto target_end = std::find(target_it, disasm.end(), ',');
|
const auto target_end = std::find(target_it, disasm.end(), ',');
|
||||||
|
@ -651,7 +653,7 @@ void CodeViewWidget::AutoStep(CodeTrace::AutoStop option)
|
||||||
// Autosteps and follows value in the target (left-most) register. The Used and Changed options
|
// Autosteps and follows value in the target (left-most) register. The Used and Changed options
|
||||||
// silently follows target through reshuffles in memory and registers and stops on use or update.
|
// silently follows target through reshuffles in memory and registers and stops on use or update.
|
||||||
|
|
||||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
Core::CPUThreadGuard guard(m_system);
|
||||||
|
|
||||||
CodeTrace code_trace;
|
CodeTrace code_trace;
|
||||||
bool repeat = false;
|
bool repeat = false;
|
||||||
|
@ -741,8 +743,8 @@ void CodeViewWidget::OnCopyTargetAddress()
|
||||||
|
|
||||||
const u32 addr = GetContextAddress();
|
const u32 addr = GetContextAddress();
|
||||||
|
|
||||||
const std::string code_line = [addr] {
|
const std::string code_line = [this, addr] {
|
||||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
Core::CPUThreadGuard guard(m_system);
|
||||||
return PowerPC::debug_interface.Disassemble(&guard, addr);
|
return PowerPC::debug_interface.Disassemble(&guard, addr);
|
||||||
}();
|
}();
|
||||||
|
|
||||||
|
@ -771,8 +773,8 @@ void CodeViewWidget::OnShowTargetInMemory()
|
||||||
|
|
||||||
const u32 addr = GetContextAddress();
|
const u32 addr = GetContextAddress();
|
||||||
|
|
||||||
const std::string code_line = [addr] {
|
const std::string code_line = [this, addr] {
|
||||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
Core::CPUThreadGuard guard(m_system);
|
||||||
return PowerPC::debug_interface.Disassemble(&guard, addr);
|
return PowerPC::debug_interface.Disassemble(&guard, addr);
|
||||||
}();
|
}();
|
||||||
|
|
||||||
|
@ -790,8 +792,8 @@ void CodeViewWidget::OnCopyCode()
|
||||||
{
|
{
|
||||||
const u32 addr = GetContextAddress();
|
const u32 addr = GetContextAddress();
|
||||||
|
|
||||||
const std::string text = [addr] {
|
const std::string text = [this, addr] {
|
||||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
Core::CPUThreadGuard guard(m_system);
|
||||||
return PowerPC::debug_interface.Disassemble(&guard, addr);
|
return PowerPC::debug_interface.Disassemble(&guard, addr);
|
||||||
}();
|
}();
|
||||||
|
|
||||||
|
@ -809,7 +811,7 @@ void CodeViewWidget::OnCopyFunction()
|
||||||
std::string text = symbol->name + "\r\n";
|
std::string text = symbol->name + "\r\n";
|
||||||
|
|
||||||
{
|
{
|
||||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
Core::CPUThreadGuard guard(m_system);
|
||||||
|
|
||||||
// we got a function
|
// we got a function
|
||||||
const u32 start = symbol->address;
|
const u32 start = symbol->address;
|
||||||
|
@ -828,8 +830,8 @@ void CodeViewWidget::OnCopyHex()
|
||||||
{
|
{
|
||||||
const u32 addr = GetContextAddress();
|
const u32 addr = GetContextAddress();
|
||||||
|
|
||||||
const u32 instruction = [addr] {
|
const u32 instruction = [this, addr] {
|
||||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
Core::CPUThreadGuard guard(m_system);
|
||||||
return PowerPC::debug_interface.ReadInstruction(guard, addr);
|
return PowerPC::debug_interface.ReadInstruction(guard, addr);
|
||||||
}();
|
}();
|
||||||
|
|
||||||
|
@ -857,7 +859,7 @@ void CodeViewWidget::OnAddFunction()
|
||||||
{
|
{
|
||||||
const u32 addr = GetContextAddress();
|
const u32 addr = GetContextAddress();
|
||||||
|
|
||||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
Core::CPUThreadGuard guard(m_system);
|
||||||
|
|
||||||
g_symbolDB.AddFunction(guard, addr);
|
g_symbolDB.AddFunction(guard, addr);
|
||||||
emit SymbolsChanged();
|
emit SymbolsChanged();
|
||||||
|
@ -882,8 +884,8 @@ void CodeViewWidget::OnFollowBranch()
|
||||||
{
|
{
|
||||||
const u32 addr = GetContextAddress();
|
const u32 addr = GetContextAddress();
|
||||||
|
|
||||||
const u32 branch_addr = [addr] {
|
const u32 branch_addr = [this, addr] {
|
||||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
Core::CPUThreadGuard guard(m_system);
|
||||||
return GetBranchFromAddress(guard, addr);
|
return GetBranchFromAddress(guard, addr);
|
||||||
}();
|
}();
|
||||||
|
|
||||||
|
@ -917,7 +919,7 @@ void CodeViewWidget::OnRenameSymbol()
|
||||||
|
|
||||||
void CodeViewWidget::OnSelectionChanged()
|
void CodeViewWidget::OnSelectionChanged()
|
||||||
{
|
{
|
||||||
if (m_address == PowerPC::ppcState.pc)
|
if (m_address == m_system.GetPPCState().pc)
|
||||||
{
|
{
|
||||||
setStyleSheet(
|
setStyleSheet(
|
||||||
QStringLiteral("QTableView::item:selected {background-color: #00FF00; color: #000000;}"));
|
QStringLiteral("QTableView::item:selected {background-color: #00FF00; color: #000000;}"));
|
||||||
|
@ -946,7 +948,7 @@ void CodeViewWidget::OnSetSymbolSize()
|
||||||
if (!good)
|
if (!good)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
Core::CPUThreadGuard guard(m_system);
|
||||||
|
|
||||||
PPCAnalyst::ReanalyzeFunction(guard, symbol->address, *symbol, size);
|
PPCAnalyst::ReanalyzeFunction(guard, symbol->address, *symbol, size);
|
||||||
emit SymbolsChanged();
|
emit SymbolsChanged();
|
||||||
|
@ -974,7 +976,7 @@ void CodeViewWidget::OnSetSymbolEndAddress()
|
||||||
if (!good)
|
if (!good)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
Core::CPUThreadGuard guard(m_system);
|
||||||
|
|
||||||
PPCAnalyst::ReanalyzeFunction(guard, symbol->address, *symbol, address - symbol->address);
|
PPCAnalyst::ReanalyzeFunction(guard, symbol->address, *symbol, address - symbol->address);
|
||||||
emit SymbolsChanged();
|
emit SymbolsChanged();
|
||||||
|
@ -983,7 +985,7 @@ void CodeViewWidget::OnSetSymbolEndAddress()
|
||||||
|
|
||||||
void CodeViewWidget::OnReplaceInstruction()
|
void CodeViewWidget::OnReplaceInstruction()
|
||||||
{
|
{
|
||||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
Core::CPUThreadGuard guard(m_system);
|
||||||
|
|
||||||
const u32 addr = GetContextAddress();
|
const u32 addr = GetContextAddress();
|
||||||
|
|
||||||
|
@ -1006,7 +1008,7 @@ void CodeViewWidget::OnReplaceInstruction()
|
||||||
|
|
||||||
void CodeViewWidget::OnRestoreInstruction()
|
void CodeViewWidget::OnRestoreInstruction()
|
||||||
{
|
{
|
||||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
Core::CPUThreadGuard guard(m_system);
|
||||||
|
|
||||||
const u32 addr = GetContextAddress();
|
const u32 addr = GetContextAddress();
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,8 @@ class QShowEvent;
|
||||||
namespace Core
|
namespace Core
|
||||||
{
|
{
|
||||||
class CPUThreadGuard;
|
class CPUThreadGuard;
|
||||||
};
|
class System;
|
||||||
|
} // namespace Core
|
||||||
|
|
||||||
struct CodeViewBranch;
|
struct CodeViewBranch;
|
||||||
class BranchDisplayDelegate;
|
class BranchDisplayDelegate;
|
||||||
|
@ -98,6 +99,8 @@ private:
|
||||||
|
|
||||||
void CalculateBranchIndentation();
|
void CalculateBranchIndentation();
|
||||||
|
|
||||||
|
Core::System& m_system;
|
||||||
|
|
||||||
bool m_updating = false;
|
bool m_updating = false;
|
||||||
|
|
||||||
u32 m_address = 0;
|
u32 m_address = 0;
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
#include "DolphinQt/Host.h"
|
#include "DolphinQt/Host.h"
|
||||||
#include "DolphinQt/Settings.h"
|
#include "DolphinQt/Settings.h"
|
||||||
|
|
||||||
CodeWidget::CodeWidget(QWidget* parent) : QDockWidget(parent)
|
CodeWidget::CodeWidget(QWidget* parent) : QDockWidget(parent), m_system(Core::System::GetInstance())
|
||||||
{
|
{
|
||||||
setWindowTitle(tr("Code"));
|
setWindowTitle(tr("Code"));
|
||||||
setObjectName(QStringLiteral("code"));
|
setObjectName(QStringLiteral("code"));
|
||||||
|
@ -51,7 +51,7 @@ CodeWidget::CodeWidget(QWidget* parent) : QDockWidget(parent)
|
||||||
|
|
||||||
connect(Host::GetInstance(), &Host::UpdateDisasmDialog, this, [this] {
|
connect(Host::GetInstance(), &Host::UpdateDisasmDialog, this, [this] {
|
||||||
if (Core::GetState() == Core::State::Paused)
|
if (Core::GetState() == Core::State::Paused)
|
||||||
SetAddress(PowerPC::ppcState.pc, CodeViewWidget::SetAddressUpdate::WithoutUpdate);
|
SetAddress(m_system.GetPPCState().pc, CodeViewWidget::SetAddressUpdate::WithoutUpdate);
|
||||||
Update();
|
Update();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -329,9 +329,9 @@ void CodeWidget::UpdateCallstack()
|
||||||
|
|
||||||
std::vector<Dolphin_Debugger::CallstackEntry> stack;
|
std::vector<Dolphin_Debugger::CallstackEntry> stack;
|
||||||
|
|
||||||
const bool success = [&stack] {
|
const bool success = [this, &stack] {
|
||||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
Core::CPUThreadGuard guard(m_system);
|
||||||
return Dolphin_Debugger::GetCallstack(Core::System::GetInstance(), guard, stack);
|
return Dolphin_Debugger::GetCallstack(m_system, guard, stack);
|
||||||
}();
|
}();
|
||||||
|
|
||||||
if (!success)
|
if (!success)
|
||||||
|
@ -435,8 +435,7 @@ void CodeWidget::UpdateFunctionCallers(const Common::Symbol* symbol)
|
||||||
|
|
||||||
void CodeWidget::Step()
|
void CodeWidget::Step()
|
||||||
{
|
{
|
||||||
auto& system = Core::System::GetInstance();
|
auto& cpu = m_system.GetCPU();
|
||||||
auto& cpu = system.GetCPU();
|
|
||||||
|
|
||||||
if (!cpu.IsStepping())
|
if (!cpu.IsStepping())
|
||||||
return;
|
return;
|
||||||
|
@ -455,21 +454,20 @@ void CodeWidget::Step()
|
||||||
|
|
||||||
void CodeWidget::StepOver()
|
void CodeWidget::StepOver()
|
||||||
{
|
{
|
||||||
auto& system = Core::System::GetInstance();
|
auto& cpu = m_system.GetCPU();
|
||||||
auto& cpu = system.GetCPU();
|
|
||||||
|
|
||||||
if (!cpu.IsStepping())
|
if (!cpu.IsStepping())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const UGeckoInstruction inst = [&] {
|
const UGeckoInstruction inst = [&] {
|
||||||
Core::CPUThreadGuard guard(system);
|
Core::CPUThreadGuard guard(m_system);
|
||||||
return PowerPC::MMU::HostRead_Instruction(guard, PowerPC::ppcState.pc);
|
return PowerPC::MMU::HostRead_Instruction(guard, m_system.GetPPCState().pc);
|
||||||
}();
|
}();
|
||||||
|
|
||||||
if (inst.LK)
|
if (inst.LK)
|
||||||
{
|
{
|
||||||
PowerPC::breakpoints.ClearAllTemporary();
|
PowerPC::breakpoints.ClearAllTemporary();
|
||||||
PowerPC::breakpoints.Add(PowerPC::ppcState.pc + 4, true);
|
PowerPC::breakpoints.Add(m_system.GetPPCState().pc + 4, true);
|
||||||
cpu.EnableStepping(false);
|
cpu.EnableStepping(false);
|
||||||
Core::DisplayMessage(tr("Step over in progress...").toStdString(), 2000);
|
Core::DisplayMessage(tr("Step over in progress...").toStdString(), 2000);
|
||||||
}
|
}
|
||||||
|
@ -480,23 +478,21 @@ void CodeWidget::StepOver()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true on a rfi, blr or on a bclr that evaluates to true.
|
// Returns true on a rfi, blr or on a bclr that evaluates to true.
|
||||||
static bool WillInstructionReturn(UGeckoInstruction inst)
|
static bool WillInstructionReturn(Core::System& system, UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
// Is a rfi instruction
|
// Is a rfi instruction
|
||||||
if (inst.hex == 0x4C000064u)
|
if (inst.hex == 0x4C000064u)
|
||||||
return true;
|
return true;
|
||||||
bool counter =
|
const auto& ppc_state = system.GetPPCState();
|
||||||
(inst.BO_2 >> 2 & 1) != 0 || (CTR(PowerPC::ppcState) != 0) != ((inst.BO_2 >> 1 & 1) != 0);
|
bool counter = (inst.BO_2 >> 2 & 1) != 0 || (CTR(ppc_state) != 0) != ((inst.BO_2 >> 1 & 1) != 0);
|
||||||
bool condition =
|
bool condition = inst.BO_2 >> 4 != 0 || ppc_state.cr.GetBit(inst.BI_2) == (inst.BO_2 >> 3 & 1);
|
||||||
inst.BO_2 >> 4 != 0 || PowerPC::ppcState.cr.GetBit(inst.BI_2) == (inst.BO_2 >> 3 & 1);
|
|
||||||
bool isBclr = inst.OPCD_7 == 0b010011 && (inst.hex >> 1 & 0b10000) != 0;
|
bool isBclr = inst.OPCD_7 == 0b010011 && (inst.hex >> 1 & 0b10000) != 0;
|
||||||
return isBclr && counter && condition && !inst.LK_3;
|
return isBclr && counter && condition && !inst.LK_3;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeWidget::StepOut()
|
void CodeWidget::StepOut()
|
||||||
{
|
{
|
||||||
auto& system = Core::System::GetInstance();
|
auto& cpu = m_system.GetCPU();
|
||||||
auto& cpu = system.GetCPU();
|
|
||||||
|
|
||||||
if (!cpu.IsStepping())
|
if (!cpu.IsStepping())
|
||||||
return;
|
return;
|
||||||
|
@ -505,8 +501,9 @@ void CodeWidget::StepOut()
|
||||||
using clock = std::chrono::steady_clock;
|
using clock = std::chrono::steady_clock;
|
||||||
clock::time_point timeout = clock::now() + std::chrono::seconds(5);
|
clock::time_point timeout = clock::now() + std::chrono::seconds(5);
|
||||||
|
|
||||||
|
auto& ppc_state = m_system.GetPPCState();
|
||||||
{
|
{
|
||||||
Core::CPUThreadGuard guard(system);
|
Core::CPUThreadGuard guard(m_system);
|
||||||
|
|
||||||
PowerPC::breakpoints.ClearAllTemporary();
|
PowerPC::breakpoints.ClearAllTemporary();
|
||||||
|
|
||||||
|
@ -516,10 +513,10 @@ void CodeWidget::StepOut()
|
||||||
// Loop until either the current instruction is a return instruction with no Link flag
|
// Loop until either the current instruction is a return instruction with no Link flag
|
||||||
// or a breakpoint is detected so it can step at the breakpoint. If the PC is currently
|
// or a breakpoint is detected so it can step at the breakpoint. If the PC is currently
|
||||||
// on a breakpoint, skip it.
|
// on a breakpoint, skip it.
|
||||||
UGeckoInstruction inst = PowerPC::MMU::HostRead_Instruction(guard, PowerPC::ppcState.pc);
|
UGeckoInstruction inst = PowerPC::MMU::HostRead_Instruction(guard, ppc_state.pc);
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (WillInstructionReturn(inst))
|
if (WillInstructionReturn(m_system, inst))
|
||||||
{
|
{
|
||||||
PowerPC::SingleStep();
|
PowerPC::SingleStep();
|
||||||
break;
|
break;
|
||||||
|
@ -528,28 +525,27 @@ void CodeWidget::StepOut()
|
||||||
if (inst.LK)
|
if (inst.LK)
|
||||||
{
|
{
|
||||||
// Step over branches
|
// Step over branches
|
||||||
u32 next_pc = PowerPC::ppcState.pc + 4;
|
u32 next_pc = ppc_state.pc + 4;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
PowerPC::SingleStep();
|
PowerPC::SingleStep();
|
||||||
} while (PowerPC::ppcState.pc != next_pc && clock::now() < timeout &&
|
} while (ppc_state.pc != next_pc && clock::now() < timeout &&
|
||||||
!PowerPC::breakpoints.IsAddressBreakPoint(PowerPC::ppcState.pc));
|
!PowerPC::breakpoints.IsAddressBreakPoint(ppc_state.pc));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PowerPC::SingleStep();
|
PowerPC::SingleStep();
|
||||||
}
|
}
|
||||||
|
|
||||||
inst = PowerPC::MMU::HostRead_Instruction(guard, PowerPC::ppcState.pc);
|
inst = PowerPC::MMU::HostRead_Instruction(guard, ppc_state.pc);
|
||||||
} while (clock::now() < timeout &&
|
} while (clock::now() < timeout && !PowerPC::breakpoints.IsAddressBreakPoint(ppc_state.pc));
|
||||||
!PowerPC::breakpoints.IsAddressBreakPoint(PowerPC::ppcState.pc));
|
|
||||||
|
|
||||||
PowerPC::SetMode(old_mode);
|
PowerPC::SetMode(old_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit Host::GetInstance()->UpdateDisasmDialog();
|
emit Host::GetInstance()->UpdateDisasmDialog();
|
||||||
|
|
||||||
if (PowerPC::breakpoints.IsAddressBreakPoint(PowerPC::ppcState.pc))
|
if (PowerPC::breakpoints.IsAddressBreakPoint(ppc_state.pc))
|
||||||
Core::DisplayMessage(tr("Breakpoint encountered! Step out aborted.").toStdString(), 2000);
|
Core::DisplayMessage(tr("Breakpoint encountered! Step out aborted.").toStdString(), 2000);
|
||||||
else if (clock::now() >= timeout)
|
else if (clock::now() >= timeout)
|
||||||
Core::DisplayMessage(tr("Step out timed out!").toStdString(), 2000);
|
Core::DisplayMessage(tr("Step out timed out!").toStdString(), 2000);
|
||||||
|
@ -559,19 +555,19 @@ void CodeWidget::StepOut()
|
||||||
|
|
||||||
void CodeWidget::Skip()
|
void CodeWidget::Skip()
|
||||||
{
|
{
|
||||||
PowerPC::ppcState.pc += 4;
|
m_system.GetPPCState().pc += 4;
|
||||||
ShowPC();
|
ShowPC();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeWidget::ShowPC()
|
void CodeWidget::ShowPC()
|
||||||
{
|
{
|
||||||
m_code_view->SetAddress(PowerPC::ppcState.pc, CodeViewWidget::SetAddressUpdate::WithUpdate);
|
m_code_view->SetAddress(m_system.GetPPCState().pc, CodeViewWidget::SetAddressUpdate::WithUpdate);
|
||||||
Update();
|
Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeWidget::SetPC()
|
void CodeWidget::SetPC()
|
||||||
{
|
{
|
||||||
PowerPC::ppcState.pc = m_code_view->GetAddress();
|
m_system.GetPPCState().pc = m_code_view->GetAddress();
|
||||||
Update();
|
Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,10 @@ namespace Common
|
||||||
{
|
{
|
||||||
struct Symbol;
|
struct Symbol;
|
||||||
}
|
}
|
||||||
|
namespace Core
|
||||||
|
{
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
class CodeWidget : public QDockWidget
|
class CodeWidget : public QDockWidget
|
||||||
{
|
{
|
||||||
|
@ -66,6 +70,8 @@ private:
|
||||||
void closeEvent(QCloseEvent*) override;
|
void closeEvent(QCloseEvent*) override;
|
||||||
void showEvent(QShowEvent* event) override;
|
void showEvent(QShowEvent* event) override;
|
||||||
|
|
||||||
|
Core::System& m_system;
|
||||||
|
|
||||||
CodeDiffDialog* m_diff_dialog = nullptr;
|
CodeDiffDialog* m_diff_dialog = nullptr;
|
||||||
QLineEdit* m_search_address;
|
QLineEdit* m_search_address;
|
||||||
QPushButton* m_code_diff;
|
QPushButton* m_code_diff;
|
||||||
|
|
|
@ -20,7 +20,8 @@
|
||||||
#include "DolphinQt/Host.h"
|
#include "DolphinQt/Host.h"
|
||||||
#include "DolphinQt/Settings.h"
|
#include "DolphinQt/Settings.h"
|
||||||
|
|
||||||
RegisterWidget::RegisterWidget(QWidget* parent) : QDockWidget(parent)
|
RegisterWidget::RegisterWidget(QWidget* parent)
|
||||||
|
: QDockWidget(parent), m_system(Core::System::GetInstance())
|
||||||
{
|
{
|
||||||
setWindowTitle(tr("Registers"));
|
setWindowTitle(tr("Registers"));
|
||||||
setObjectName(QStringLiteral("registers"));
|
setObjectName(QStringLiteral("registers"));
|
||||||
|
@ -295,8 +296,8 @@ void RegisterWidget::AutoStep(const std::string& reg) const
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
const AutoStepResults results = [&trace] {
|
const AutoStepResults results = [this, &trace] {
|
||||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
Core::CPUThreadGuard guard(m_system);
|
||||||
return trace.AutoStepping(guard, true);
|
return trace.AutoStepping(guard, true);
|
||||||
}();
|
}();
|
||||||
|
|
||||||
|
@ -318,18 +319,19 @@ void RegisterWidget::PopulateTable()
|
||||||
{
|
{
|
||||||
// General purpose registers (int)
|
// General purpose registers (int)
|
||||||
AddRegister(
|
AddRegister(
|
||||||
i, 0, RegisterType::gpr, "r" + std::to_string(i), [i] { return PowerPC::ppcState.gpr[i]; },
|
i, 0, RegisterType::gpr, "r" + std::to_string(i),
|
||||||
[i](u64 value) { PowerPC::ppcState.gpr[i] = value; });
|
[this, i] { return m_system.GetPPCState().gpr[i]; },
|
||||||
|
[this, i](u64 value) { m_system.GetPPCState().gpr[i] = value; });
|
||||||
|
|
||||||
// Floating point registers (double)
|
// Floating point registers (double)
|
||||||
AddRegister(
|
AddRegister(
|
||||||
i, 2, RegisterType::fpr, "f" + std::to_string(i),
|
i, 2, RegisterType::fpr, "f" + std::to_string(i),
|
||||||
[i] { return PowerPC::ppcState.ps[i].PS0AsU64(); },
|
[this, i] { return m_system.GetPPCState().ps[i].PS0AsU64(); },
|
||||||
[i](u64 value) { PowerPC::ppcState.ps[i].SetPS0(value); });
|
[this, i](u64 value) { m_system.GetPPCState().ps[i].SetPS0(value); });
|
||||||
|
|
||||||
AddRegister(
|
AddRegister(
|
||||||
i, 4, RegisterType::fpr, "", [i] { return PowerPC::ppcState.ps[i].PS1AsU64(); },
|
i, 4, RegisterType::fpr, "", [this, i] { return m_system.GetPPCState().ps[i].PS1AsU64(); },
|
||||||
[i](u64 value) { PowerPC::ppcState.ps[i].SetPS1(value); });
|
[this, i](u64 value) { m_system.GetPPCState().ps[i].SetPS1(value); });
|
||||||
}
|
}
|
||||||
|
|
||||||
// The IBAT and DBAT registers have a large gap between
|
// The IBAT and DBAT registers have a large gap between
|
||||||
|
@ -340,32 +342,36 @@ void RegisterWidget::PopulateTable()
|
||||||
// IBAT registers
|
// IBAT registers
|
||||||
AddRegister(
|
AddRegister(
|
||||||
i, 5, RegisterType::ibat, "IBAT" + std::to_string(i),
|
i, 5, RegisterType::ibat, "IBAT" + std::to_string(i),
|
||||||
[i] {
|
[this, i] {
|
||||||
return (static_cast<u64>(PowerPC::ppcState.spr[SPR_IBAT0U + i * 2]) << 32) +
|
const auto& ppc_state = m_system.GetPPCState();
|
||||||
PowerPC::ppcState.spr[SPR_IBAT0L + i * 2];
|
return (static_cast<u64>(ppc_state.spr[SPR_IBAT0U + i * 2]) << 32) +
|
||||||
|
ppc_state.spr[SPR_IBAT0L + i * 2];
|
||||||
},
|
},
|
||||||
nullptr);
|
nullptr);
|
||||||
AddRegister(
|
AddRegister(
|
||||||
i + 4, 5, RegisterType::ibat, "IBAT" + std::to_string(4 + i),
|
i + 4, 5, RegisterType::ibat, "IBAT" + std::to_string(4 + i),
|
||||||
[i] {
|
[this, i] {
|
||||||
return (static_cast<u64>(PowerPC::ppcState.spr[SPR_IBAT4U + i * 2]) << 32) +
|
const auto& ppc_state = m_system.GetPPCState();
|
||||||
PowerPC::ppcState.spr[SPR_IBAT4L + i * 2];
|
return (static_cast<u64>(ppc_state.spr[SPR_IBAT4U + i * 2]) << 32) +
|
||||||
|
ppc_state.spr[SPR_IBAT4L + i * 2];
|
||||||
},
|
},
|
||||||
nullptr);
|
nullptr);
|
||||||
|
|
||||||
// DBAT registers
|
// DBAT registers
|
||||||
AddRegister(
|
AddRegister(
|
||||||
i + 8, 5, RegisterType::dbat, "DBAT" + std::to_string(i),
|
i + 8, 5, RegisterType::dbat, "DBAT" + std::to_string(i),
|
||||||
[i] {
|
[this, i] {
|
||||||
return (static_cast<u64>(PowerPC::ppcState.spr[SPR_DBAT0U + i * 2]) << 32) +
|
const auto& ppc_state = m_system.GetPPCState();
|
||||||
PowerPC::ppcState.spr[SPR_DBAT0L + i * 2];
|
return (static_cast<u64>(ppc_state.spr[SPR_DBAT0U + i * 2]) << 32) +
|
||||||
|
ppc_state.spr[SPR_DBAT0L + i * 2];
|
||||||
},
|
},
|
||||||
nullptr);
|
nullptr);
|
||||||
AddRegister(
|
AddRegister(
|
||||||
i + 12, 5, RegisterType::dbat, "DBAT" + std::to_string(4 + i),
|
i + 12, 5, RegisterType::dbat, "DBAT" + std::to_string(4 + i),
|
||||||
[i] {
|
[this, i] {
|
||||||
return (static_cast<u64>(PowerPC::ppcState.spr[SPR_DBAT4U + i * 2]) << 32) +
|
const auto& ppc_state = m_system.GetPPCState();
|
||||||
PowerPC::ppcState.spr[SPR_DBAT4L + i * 2];
|
return (static_cast<u64>(ppc_state.spr[SPR_DBAT4U + i * 2]) << 32) +
|
||||||
|
ppc_state.spr[SPR_DBAT4L + i * 2];
|
||||||
},
|
},
|
||||||
nullptr);
|
nullptr);
|
||||||
}
|
}
|
||||||
|
@ -375,29 +381,30 @@ void RegisterWidget::PopulateTable()
|
||||||
// Graphics quantization registers
|
// Graphics quantization registers
|
||||||
AddRegister(
|
AddRegister(
|
||||||
i + 16, 7, RegisterType::gqr, "GQR" + std::to_string(i),
|
i + 16, 7, RegisterType::gqr, "GQR" + std::to_string(i),
|
||||||
[i] { return PowerPC::ppcState.spr[SPR_GQR0 + i]; }, nullptr);
|
[this, i] { return m_system.GetPPCState().spr[SPR_GQR0 + i]; }, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// HID registers
|
// HID registers
|
||||||
AddRegister(
|
AddRegister(
|
||||||
24, 7, RegisterType::hid, "HID0", [] { return PowerPC::ppcState.spr[SPR_HID0]; },
|
24, 7, RegisterType::hid, "HID0", [this] { return m_system.GetPPCState().spr[SPR_HID0]; },
|
||||||
[](u64 value) { PowerPC::ppcState.spr[SPR_HID0] = static_cast<u32>(value); });
|
[this](u64 value) { m_system.GetPPCState().spr[SPR_HID0] = static_cast<u32>(value); });
|
||||||
AddRegister(
|
AddRegister(
|
||||||
25, 7, RegisterType::hid, "HID1", [] { return PowerPC::ppcState.spr[SPR_HID1]; },
|
25, 7, RegisterType::hid, "HID1", [this] { return m_system.GetPPCState().spr[SPR_HID1]; },
|
||||||
[](u64 value) { PowerPC::ppcState.spr[SPR_HID1] = static_cast<u32>(value); });
|
[this](u64 value) { m_system.GetPPCState().spr[SPR_HID1] = static_cast<u32>(value); });
|
||||||
AddRegister(
|
AddRegister(
|
||||||
26, 7, RegisterType::hid, "HID2", [] { return PowerPC::ppcState.spr[SPR_HID2]; },
|
26, 7, RegisterType::hid, "HID2", [this] { return m_system.GetPPCState().spr[SPR_HID2]; },
|
||||||
[](u64 value) { PowerPC::ppcState.spr[SPR_HID2] = static_cast<u32>(value); });
|
[this](u64 value) { m_system.GetPPCState().spr[SPR_HID2] = static_cast<u32>(value); });
|
||||||
AddRegister(
|
AddRegister(
|
||||||
27, 7, RegisterType::hid, "HID4", [] { return PowerPC::ppcState.spr[SPR_HID4]; },
|
27, 7, RegisterType::hid, "HID4", [this] { return m_system.GetPPCState().spr[SPR_HID4]; },
|
||||||
[](u64 value) { PowerPC::ppcState.spr[SPR_HID4] = static_cast<u32>(value); });
|
[this](u64 value) { m_system.GetPPCState().spr[SPR_HID4] = static_cast<u32>(value); });
|
||||||
|
|
||||||
for (int i = 0; i < 16; i++)
|
for (int i = 0; i < 16; i++)
|
||||||
{
|
{
|
||||||
// SR registers
|
// SR registers
|
||||||
AddRegister(
|
AddRegister(
|
||||||
i, 7, RegisterType::sr, "SR" + std::to_string(i), [i] { return PowerPC::ppcState.sr[i]; },
|
i, 7, RegisterType::sr, "SR" + std::to_string(i),
|
||||||
[i](u64 value) { PowerPC::ppcState.sr[i] = value; });
|
[this, i] { return m_system.GetPPCState().sr[i]; },
|
||||||
|
[this, i](u64 value) { m_system.GetPPCState().sr[i] = value; });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special registers
|
// Special registers
|
||||||
|
@ -406,83 +413,79 @@ void RegisterWidget::PopulateTable()
|
||||||
|
|
||||||
// PC
|
// PC
|
||||||
AddRegister(
|
AddRegister(
|
||||||
17, 5, RegisterType::pc, "PC", [] { return PowerPC::ppcState.pc; },
|
17, 5, RegisterType::pc, "PC", [this] { return m_system.GetPPCState().pc; },
|
||||||
[](u64 value) { PowerPC::ppcState.pc = value; });
|
[this](u64 value) { m_system.GetPPCState().pc = value; });
|
||||||
|
|
||||||
// LR
|
// LR
|
||||||
AddRegister(
|
AddRegister(
|
||||||
18, 5, RegisterType::lr, "LR", [] { return PowerPC::ppcState.spr[SPR_LR]; },
|
18, 5, RegisterType::lr, "LR", [this] { return m_system.GetPPCState().spr[SPR_LR]; },
|
||||||
[](u64 value) { PowerPC::ppcState.spr[SPR_LR] = value; });
|
[this](u64 value) { m_system.GetPPCState().spr[SPR_LR] = value; });
|
||||||
|
|
||||||
// CTR
|
// CTR
|
||||||
AddRegister(
|
AddRegister(
|
||||||
19, 5, RegisterType::ctr, "CTR", [] { return PowerPC::ppcState.spr[SPR_CTR]; },
|
19, 5, RegisterType::ctr, "CTR", [this] { return m_system.GetPPCState().spr[SPR_CTR]; },
|
||||||
[](u64 value) { PowerPC::ppcState.spr[SPR_CTR] = value; });
|
[this](u64 value) { m_system.GetPPCState().spr[SPR_CTR] = value; });
|
||||||
|
|
||||||
// CR
|
// CR
|
||||||
AddRegister(
|
AddRegister(
|
||||||
20, 5, RegisterType::cr, "CR", [] { return PowerPC::ppcState.cr.Get(); },
|
20, 5, RegisterType::cr, "CR", [this] { return m_system.GetPPCState().cr.Get(); },
|
||||||
[](u64 value) { PowerPC::ppcState.cr.Set(value); });
|
[this](u64 value) { m_system.GetPPCState().cr.Set(value); });
|
||||||
|
|
||||||
// XER
|
// XER
|
||||||
AddRegister(
|
AddRegister(
|
||||||
21, 5, RegisterType::xer, "XER", [] { return PowerPC::ppcState.GetXER().Hex; },
|
21, 5, RegisterType::xer, "XER", [this] { return m_system.GetPPCState().GetXER().Hex; },
|
||||||
[](u64 value) { PowerPC::ppcState.SetXER(UReg_XER(value)); });
|
[this](u64 value) { m_system.GetPPCState().SetXER(UReg_XER(value)); });
|
||||||
|
|
||||||
// FPSCR
|
// FPSCR
|
||||||
AddRegister(
|
AddRegister(
|
||||||
22, 5, RegisterType::fpscr, "FPSCR", [] { return PowerPC::ppcState.fpscr.Hex; },
|
22, 5, RegisterType::fpscr, "FPSCR", [this] { return m_system.GetPPCState().fpscr.Hex; },
|
||||||
[](u64 value) { PowerPC::ppcState.fpscr = static_cast<u32>(value); });
|
[this](u64 value) { m_system.GetPPCState().fpscr = static_cast<u32>(value); });
|
||||||
|
|
||||||
// MSR
|
// MSR
|
||||||
AddRegister(
|
AddRegister(
|
||||||
23, 5, RegisterType::msr, "MSR", [] { return PowerPC::ppcState.msr.Hex; },
|
23, 5, RegisterType::msr, "MSR", [this] { return m_system.GetPPCState().msr.Hex; },
|
||||||
[](u64 value) { PowerPC::ppcState.msr.Hex = value; });
|
[this](u64 value) { m_system.GetPPCState().msr.Hex = value; });
|
||||||
|
|
||||||
// SRR 0-1
|
// SRR 0-1
|
||||||
AddRegister(
|
AddRegister(
|
||||||
24, 5, RegisterType::srr, "SRR0", [] { return PowerPC::ppcState.spr[SPR_SRR0]; },
|
24, 5, RegisterType::srr, "SRR0", [this] { return m_system.GetPPCState().spr[SPR_SRR0]; },
|
||||||
[](u64 value) { PowerPC::ppcState.spr[SPR_SRR0] = value; });
|
[this](u64 value) { m_system.GetPPCState().spr[SPR_SRR0] = value; });
|
||||||
AddRegister(
|
AddRegister(
|
||||||
25, 5, RegisterType::srr, "SRR1", [] { return PowerPC::ppcState.spr[SPR_SRR1]; },
|
25, 5, RegisterType::srr, "SRR1", [this] { return m_system.GetPPCState().spr[SPR_SRR1]; },
|
||||||
[](u64 value) { PowerPC::ppcState.spr[SPR_SRR1] = value; });
|
[this](u64 value) { m_system.GetPPCState().spr[SPR_SRR1] = value; });
|
||||||
|
|
||||||
// Exceptions
|
// Exceptions
|
||||||
AddRegister(
|
AddRegister(
|
||||||
26, 5, RegisterType::exceptions, "Exceptions", [] { return PowerPC::ppcState.Exceptions; },
|
26, 5, RegisterType::exceptions, "Exceptions",
|
||||||
[](u64 value) { PowerPC::ppcState.Exceptions = value; });
|
[this] { return m_system.GetPPCState().Exceptions; },
|
||||||
|
[this](u64 value) { m_system.GetPPCState().Exceptions = value; });
|
||||||
|
|
||||||
// Int Mask
|
// Int Mask
|
||||||
AddRegister(
|
AddRegister(
|
||||||
27, 5, RegisterType::int_mask, "Int Mask",
|
27, 5, RegisterType::int_mask, "Int Mask",
|
||||||
[] {
|
[this] { return m_system.GetProcessorInterface().GetMask(); }, nullptr);
|
||||||
auto& system = Core::System::GetInstance();
|
|
||||||
return system.GetProcessorInterface().GetMask();
|
|
||||||
},
|
|
||||||
nullptr);
|
|
||||||
|
|
||||||
// Int Cause
|
// Int Cause
|
||||||
AddRegister(
|
AddRegister(
|
||||||
28, 5, RegisterType::int_cause, "Int Cause",
|
28, 5, RegisterType::int_cause, "Int Cause",
|
||||||
[] {
|
[this] { return m_system.GetProcessorInterface().GetCause(); }, nullptr);
|
||||||
auto& system = Core::System::GetInstance();
|
|
||||||
return system.GetProcessorInterface().GetCause();
|
|
||||||
},
|
|
||||||
nullptr);
|
|
||||||
|
|
||||||
// DSISR
|
// DSISR
|
||||||
AddRegister(
|
AddRegister(
|
||||||
29, 5, RegisterType::dsisr, "DSISR", [] { return PowerPC::ppcState.spr[SPR_DSISR]; },
|
29, 5, RegisterType::dsisr, "DSISR", [this] { return m_system.GetPPCState().spr[SPR_DSISR]; },
|
||||||
[](u64 value) { PowerPC::ppcState.spr[SPR_DSISR] = value; });
|
[this](u64 value) { m_system.GetPPCState().spr[SPR_DSISR] = value; });
|
||||||
// DAR
|
// DAR
|
||||||
AddRegister(
|
AddRegister(
|
||||||
30, 5, RegisterType::dar, "DAR", [] { return PowerPC::ppcState.spr[SPR_DAR]; },
|
30, 5, RegisterType::dar, "DAR", [this] { return m_system.GetPPCState().spr[SPR_DAR]; },
|
||||||
[](u64 value) { PowerPC::ppcState.spr[SPR_DAR] = value; });
|
[this](u64 value) { m_system.GetPPCState().spr[SPR_DAR] = value; });
|
||||||
|
|
||||||
// Hash Mask
|
// Hash Mask
|
||||||
AddRegister(
|
AddRegister(
|
||||||
31, 5, RegisterType::pt_hashmask, "Hash Mask",
|
31, 5, RegisterType::pt_hashmask, "Hash Mask",
|
||||||
[] { return (PowerPC::ppcState.pagetable_hashmask << 6) | PowerPC::ppcState.pagetable_base; },
|
[this] {
|
||||||
|
const auto& ppc_state = m_system.GetPPCState();
|
||||||
|
return (ppc_state.pagetable_hashmask << 6) | ppc_state.pagetable_base;
|
||||||
|
},
|
||||||
nullptr);
|
nullptr);
|
||||||
|
|
||||||
emit RequestTableUpdate();
|
emit RequestTableUpdate();
|
||||||
|
|
|
@ -13,6 +13,10 @@
|
||||||
class QTableWidget;
|
class QTableWidget;
|
||||||
class QCloseEvent;
|
class QCloseEvent;
|
||||||
class QShowEvent;
|
class QShowEvent;
|
||||||
|
namespace Core
|
||||||
|
{
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
class RegisterWidget : public QDockWidget
|
class RegisterWidget : public QDockWidget
|
||||||
{
|
{
|
||||||
|
@ -49,6 +53,8 @@ private:
|
||||||
void AutoStep(const std::string& reg) const;
|
void AutoStep(const std::string& reg) const;
|
||||||
void Update();
|
void Update();
|
||||||
|
|
||||||
|
Core::System& m_system;
|
||||||
|
|
||||||
QTableWidget* m_table;
|
QTableWidget* m_table;
|
||||||
bool m_updating = false;
|
bool m_updating = false;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1699,7 +1699,7 @@ void MenuBar::SearchInstruction()
|
||||||
addr += 4)
|
addr += 4)
|
||||||
{
|
{
|
||||||
const auto ins_name = QString::fromStdString(
|
const auto ins_name = QString::fromStdString(
|
||||||
PPCTables::GetInstructionName(PowerPC::MMU::HostRead_U32(guard, addr)));
|
PPCTables::GetInstructionName(PowerPC::MMU::HostRead_U32(guard, addr), addr));
|
||||||
if (op == ins_name)
|
if (op == ins_name)
|
||||||
{
|
{
|
||||||
NOTICE_LOG_FMT(POWERPC, "Found {} at {:08x}", op.toStdString(), addr);
|
NOTICE_LOG_FMT(POWERPC, "Found {} at {:08x}", op.toStdString(), addr);
|
||||||
|
|
|
@ -637,7 +637,8 @@ void CommandProcessorManager::SetCpClearRegister()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandProcessorManager::HandleUnknownOpcode(u8 cmd_byte, const u8* buffer, bool preprocess)
|
void CommandProcessorManager::HandleUnknownOpcode(Core::System& system, u8 cmd_byte,
|
||||||
|
const u8* buffer, bool preprocess)
|
||||||
{
|
{
|
||||||
const auto& fifo = m_fifo;
|
const auto& fifo = m_fifo;
|
||||||
|
|
||||||
|
@ -665,6 +666,7 @@ void CommandProcessorManager::HandleUnknownOpcode(u8 cmd_byte, const u8* buffer,
|
||||||
// PC and LR are meaningless when using the fifoplayer, and will generally not be helpful if the
|
// PC and LR are meaningless when using the fifoplayer, and will generally not be helpful if the
|
||||||
// unknown opcode is inside of a display list. Also note that the changes in GPFifo.h are not
|
// unknown opcode is inside of a display list. Also note that the changes in GPFifo.h are not
|
||||||
// accurate and may introduce timing issues.
|
// accurate and may introduce timing issues.
|
||||||
|
const auto& ppc_state = system.GetPPCState();
|
||||||
GENERIC_LOG_FMT(
|
GENERIC_LOG_FMT(
|
||||||
Common::Log::LogType::VIDEO, log_level,
|
Common::Log::LogType::VIDEO, log_level,
|
||||||
"FIFO: Unknown Opcode {:#04x} @ {}, preprocessing = {}, CPBase: {:#010x}, CPEnd: "
|
"FIFO: Unknown Opcode {:#04x} @ {}, preprocessing = {}, CPBase: {:#010x}, CPEnd: "
|
||||||
|
@ -686,8 +688,8 @@ void CommandProcessorManager::HandleUnknownOpcode(u8 cmd_byte, const u8* buffer,
|
||||||
fifo.bFF_Breakpoint.load(std::memory_order_relaxed) ? "true" : "false",
|
fifo.bFF_Breakpoint.load(std::memory_order_relaxed) ? "true" : "false",
|
||||||
fifo.bFF_GPLinkEnable.load(std::memory_order_relaxed) ? "true" : "false",
|
fifo.bFF_GPLinkEnable.load(std::memory_order_relaxed) ? "true" : "false",
|
||||||
fifo.bFF_HiWatermarkInt.load(std::memory_order_relaxed) ? "true" : "false",
|
fifo.bFF_HiWatermarkInt.load(std::memory_order_relaxed) ? "true" : "false",
|
||||||
fifo.bFF_LoWatermarkInt.load(std::memory_order_relaxed) ? "true" : "false",
|
fifo.bFF_LoWatermarkInt.load(std::memory_order_relaxed) ? "true" : "false", ppc_state.pc,
|
||||||
PowerPC::ppcState.pc, LR(PowerPC::ppcState));
|
LR(ppc_state));
|
||||||
|
|
||||||
if (!m_is_fifo_error_seen && !suppress_panic_alert)
|
if (!m_is_fifo_error_seen && !suppress_panic_alert)
|
||||||
{
|
{
|
||||||
|
|
|
@ -177,7 +177,7 @@ public:
|
||||||
void SetCpControlRegister(Core::System& system);
|
void SetCpControlRegister(Core::System& system);
|
||||||
void SetCpStatusRegister(Core::System& system);
|
void SetCpStatusRegister(Core::System& system);
|
||||||
|
|
||||||
void HandleUnknownOpcode(u8 cmd_byte, const u8* buffer, bool preprocess);
|
void HandleUnknownOpcode(Core::System& system, u8 cmd_byte, const u8* buffer, bool preprocess);
|
||||||
|
|
||||||
// This one is shared between gfx thread and emulator thread.
|
// This one is shared between gfx thread and emulator thread.
|
||||||
// It is only used by the Fifo and by the CommandProcessor.
|
// It is only used by the Fifo and by the CommandProcessor.
|
||||||
|
|
|
@ -219,8 +219,8 @@ public:
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Core::System::GetInstance().GetCommandProcessor().HandleUnknownOpcode(opcode, data,
|
auto& system = Core::System::GetInstance();
|
||||||
is_preprocess);
|
system.GetCommandProcessor().HandleUnknownOpcode(system, opcode, data, is_preprocess);
|
||||||
m_cycles += 1;
|
m_cycles += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,20 +74,20 @@ private:
|
||||||
std::string m_profile_path;
|
std::string m_profile_path;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void AdvanceAndCheck(u32 idx, int downcount, int expected_lateness = 0,
|
static void AdvanceAndCheck(Core::System& system, u32 idx, int downcount, int expected_lateness = 0,
|
||||||
int cpu_downcount = 0)
|
int cpu_downcount = 0)
|
||||||
{
|
{
|
||||||
s_callbacks_ran_flags = 0;
|
s_callbacks_ran_flags = 0;
|
||||||
s_expected_callback = CB_IDS[idx];
|
s_expected_callback = CB_IDS[idx];
|
||||||
s_lateness = expected_lateness;
|
s_lateness = expected_lateness;
|
||||||
|
|
||||||
PowerPC::ppcState.downcount = cpu_downcount; // Pretend we executed X cycles of instructions.
|
auto& ppc_state = system.GetPPCState();
|
||||||
auto& system = Core::System::GetInstance();
|
ppc_state.downcount = cpu_downcount; // Pretend we executed X cycles of instructions.
|
||||||
auto& core_timing = system.GetCoreTiming();
|
auto& core_timing = system.GetCoreTiming();
|
||||||
core_timing.Advance();
|
core_timing.Advance();
|
||||||
|
|
||||||
EXPECT_EQ(decltype(s_callbacks_ran_flags)().set(idx), s_callbacks_ran_flags);
|
EXPECT_EQ(decltype(s_callbacks_ran_flags)().set(idx), s_callbacks_ran_flags);
|
||||||
EXPECT_EQ(downcount, PowerPC::ppcState.downcount);
|
EXPECT_EQ(downcount, ppc_state.downcount);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(CoreTiming, BasicOrder)
|
TEST(CoreTiming, BasicOrder)
|
||||||
|
@ -97,6 +97,7 @@ TEST(CoreTiming, BasicOrder)
|
||||||
|
|
||||||
auto& system = Core::System::GetInstance();
|
auto& system = Core::System::GetInstance();
|
||||||
auto& core_timing = system.GetCoreTiming();
|
auto& core_timing = system.GetCoreTiming();
|
||||||
|
auto& ppc_state = system.GetPPCState();
|
||||||
|
|
||||||
CoreTiming::EventType* cb_a = core_timing.RegisterEvent("callbackA", CallbackTemplate<0>);
|
CoreTiming::EventType* cb_a = core_timing.RegisterEvent("callbackA", CallbackTemplate<0>);
|
||||||
CoreTiming::EventType* cb_b = core_timing.RegisterEvent("callbackB", CallbackTemplate<1>);
|
CoreTiming::EventType* cb_b = core_timing.RegisterEvent("callbackB", CallbackTemplate<1>);
|
||||||
|
@ -109,21 +110,21 @@ TEST(CoreTiming, BasicOrder)
|
||||||
|
|
||||||
// D -> B -> C -> A -> E
|
// D -> B -> C -> A -> E
|
||||||
core_timing.ScheduleEvent(1000, cb_a, CB_IDS[0]);
|
core_timing.ScheduleEvent(1000, cb_a, CB_IDS[0]);
|
||||||
EXPECT_EQ(1000, PowerPC::ppcState.downcount);
|
EXPECT_EQ(1000, ppc_state.downcount);
|
||||||
core_timing.ScheduleEvent(500, cb_b, CB_IDS[1]);
|
core_timing.ScheduleEvent(500, cb_b, CB_IDS[1]);
|
||||||
EXPECT_EQ(500, PowerPC::ppcState.downcount);
|
EXPECT_EQ(500, ppc_state.downcount);
|
||||||
core_timing.ScheduleEvent(800, cb_c, CB_IDS[2]);
|
core_timing.ScheduleEvent(800, cb_c, CB_IDS[2]);
|
||||||
EXPECT_EQ(500, PowerPC::ppcState.downcount);
|
EXPECT_EQ(500, ppc_state.downcount);
|
||||||
core_timing.ScheduleEvent(100, cb_d, CB_IDS[3]);
|
core_timing.ScheduleEvent(100, cb_d, CB_IDS[3]);
|
||||||
EXPECT_EQ(100, PowerPC::ppcState.downcount);
|
EXPECT_EQ(100, ppc_state.downcount);
|
||||||
core_timing.ScheduleEvent(1200, cb_e, CB_IDS[4]);
|
core_timing.ScheduleEvent(1200, cb_e, CB_IDS[4]);
|
||||||
EXPECT_EQ(100, PowerPC::ppcState.downcount);
|
EXPECT_EQ(100, ppc_state.downcount);
|
||||||
|
|
||||||
AdvanceAndCheck(3, 400);
|
AdvanceAndCheck(system, 3, 400);
|
||||||
AdvanceAndCheck(1, 300);
|
AdvanceAndCheck(system, 1, 300);
|
||||||
AdvanceAndCheck(2, 200);
|
AdvanceAndCheck(system, 2, 200);
|
||||||
AdvanceAndCheck(0, 200);
|
AdvanceAndCheck(system, 0, 200);
|
||||||
AdvanceAndCheck(4, MAX_SLICE_LENGTH);
|
AdvanceAndCheck(system, 4, MAX_SLICE_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace SharedSlotTest
|
namespace SharedSlotTest
|
||||||
|
@ -151,6 +152,7 @@ TEST(CoreTiming, SharedSlot)
|
||||||
|
|
||||||
auto& system = Core::System::GetInstance();
|
auto& system = Core::System::GetInstance();
|
||||||
auto& core_timing = system.GetCoreTiming();
|
auto& core_timing = system.GetCoreTiming();
|
||||||
|
auto& ppc_state = system.GetPPCState();
|
||||||
|
|
||||||
CoreTiming::EventType* cb_a = core_timing.RegisterEvent("callbackA", FifoCallback<0>);
|
CoreTiming::EventType* cb_a = core_timing.RegisterEvent("callbackA", FifoCallback<0>);
|
||||||
CoreTiming::EventType* cb_b = core_timing.RegisterEvent("callbackB", FifoCallback<1>);
|
CoreTiming::EventType* cb_b = core_timing.RegisterEvent("callbackB", FifoCallback<1>);
|
||||||
|
@ -166,14 +168,14 @@ TEST(CoreTiming, SharedSlot)
|
||||||
|
|
||||||
// Enter slice 0
|
// Enter slice 0
|
||||||
core_timing.Advance();
|
core_timing.Advance();
|
||||||
EXPECT_EQ(1000, PowerPC::ppcState.downcount);
|
EXPECT_EQ(1000, ppc_state.downcount);
|
||||||
|
|
||||||
s_callbacks_ran_flags = 0;
|
s_callbacks_ran_flags = 0;
|
||||||
s_counter = 0;
|
s_counter = 0;
|
||||||
s_lateness = 0;
|
s_lateness = 0;
|
||||||
PowerPC::ppcState.downcount = 0;
|
ppc_state.downcount = 0;
|
||||||
core_timing.Advance();
|
core_timing.Advance();
|
||||||
EXPECT_EQ(MAX_SLICE_LENGTH, PowerPC::ppcState.downcount);
|
EXPECT_EQ(MAX_SLICE_LENGTH, ppc_state.downcount);
|
||||||
EXPECT_EQ(0x1FULL, s_callbacks_ran_flags.to_ullong());
|
EXPECT_EQ(0x1FULL, s_callbacks_ran_flags.to_ullong());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,8 +196,8 @@ TEST(CoreTiming, PredictableLateness)
|
||||||
core_timing.ScheduleEvent(100, cb_a, CB_IDS[0]);
|
core_timing.ScheduleEvent(100, cb_a, CB_IDS[0]);
|
||||||
core_timing.ScheduleEvent(200, cb_b, CB_IDS[1]);
|
core_timing.ScheduleEvent(200, cb_b, CB_IDS[1]);
|
||||||
|
|
||||||
AdvanceAndCheck(0, 90, 10, -10); // (100 - 10)
|
AdvanceAndCheck(system, 0, 90, 10, -10); // (100 - 10)
|
||||||
AdvanceAndCheck(1, MAX_SLICE_LENGTH, 50, -50);
|
AdvanceAndCheck(system, 1, MAX_SLICE_LENGTH, 50, -50);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace ChainSchedulingTest
|
namespace ChainSchedulingTest
|
||||||
|
@ -225,6 +227,7 @@ TEST(CoreTiming, ChainScheduling)
|
||||||
|
|
||||||
auto& system = Core::System::GetInstance();
|
auto& system = Core::System::GetInstance();
|
||||||
auto& core_timing = system.GetCoreTiming();
|
auto& core_timing = system.GetCoreTiming();
|
||||||
|
auto& ppc_state = system.GetPPCState();
|
||||||
|
|
||||||
CoreTiming::EventType* cb_a = core_timing.RegisterEvent("callbackA", CallbackTemplate<0>);
|
CoreTiming::EventType* cb_a = core_timing.RegisterEvent("callbackA", CallbackTemplate<0>);
|
||||||
CoreTiming::EventType* cb_b = core_timing.RegisterEvent("callbackB", CallbackTemplate<1>);
|
CoreTiming::EventType* cb_b = core_timing.RegisterEvent("callbackB", CallbackTemplate<1>);
|
||||||
|
@ -239,24 +242,24 @@ TEST(CoreTiming, ChainScheduling)
|
||||||
core_timing.ScheduleEvent(1000, cb_b, CB_IDS[1]);
|
core_timing.ScheduleEvent(1000, cb_b, CB_IDS[1]);
|
||||||
core_timing.ScheduleEvent(2200, cb_c, CB_IDS[2]);
|
core_timing.ScheduleEvent(2200, cb_c, CB_IDS[2]);
|
||||||
core_timing.ScheduleEvent(1000, cb_rs, reinterpret_cast<u64>(cb_rs));
|
core_timing.ScheduleEvent(1000, cb_rs, reinterpret_cast<u64>(cb_rs));
|
||||||
EXPECT_EQ(800, PowerPC::ppcState.downcount);
|
EXPECT_EQ(800, ppc_state.downcount);
|
||||||
|
|
||||||
s_reschedules = 3;
|
s_reschedules = 3;
|
||||||
AdvanceAndCheck(0, 200); // cb_a
|
AdvanceAndCheck(system, 0, 200); // cb_a
|
||||||
AdvanceAndCheck(1, 1000); // cb_b, cb_rs
|
AdvanceAndCheck(system, 1, 1000); // cb_b, cb_rs
|
||||||
EXPECT_EQ(2, s_reschedules);
|
EXPECT_EQ(2, s_reschedules);
|
||||||
|
|
||||||
PowerPC::ppcState.downcount = 0;
|
ppc_state.downcount = 0;
|
||||||
core_timing.Advance(); // cb_rs
|
core_timing.Advance(); // cb_rs
|
||||||
EXPECT_EQ(1, s_reschedules);
|
EXPECT_EQ(1, s_reschedules);
|
||||||
EXPECT_EQ(200, PowerPC::ppcState.downcount);
|
EXPECT_EQ(200, ppc_state.downcount);
|
||||||
|
|
||||||
AdvanceAndCheck(2, 800); // cb_c
|
AdvanceAndCheck(system, 2, 800); // cb_c
|
||||||
|
|
||||||
PowerPC::ppcState.downcount = 0;
|
ppc_state.downcount = 0;
|
||||||
core_timing.Advance(); // cb_rs
|
core_timing.Advance(); // cb_rs
|
||||||
EXPECT_EQ(0, s_reschedules);
|
EXPECT_EQ(0, s_reschedules);
|
||||||
EXPECT_EQ(MAX_SLICE_LENGTH, PowerPC::ppcState.downcount);
|
EXPECT_EQ(MAX_SLICE_LENGTH, ppc_state.downcount);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace ScheduleIntoPastTest
|
namespace ScheduleIntoPastTest
|
||||||
|
@ -284,6 +287,7 @@ TEST(CoreTiming, ScheduleIntoPast)
|
||||||
|
|
||||||
auto& system = Core::System::GetInstance();
|
auto& system = Core::System::GetInstance();
|
||||||
auto& core_timing = system.GetCoreTiming();
|
auto& core_timing = system.GetCoreTiming();
|
||||||
|
auto& ppc_state = system.GetPPCState();
|
||||||
|
|
||||||
s_cb_next = core_timing.RegisterEvent("callbackA", CallbackTemplate<0>);
|
s_cb_next = core_timing.RegisterEvent("callbackA", CallbackTemplate<0>);
|
||||||
CoreTiming::EventType* cb_b = core_timing.RegisterEvent("callbackB", CallbackTemplate<1>);
|
CoreTiming::EventType* cb_b = core_timing.RegisterEvent("callbackB", CallbackTemplate<1>);
|
||||||
|
@ -293,9 +297,9 @@ TEST(CoreTiming, ScheduleIntoPast)
|
||||||
core_timing.Advance();
|
core_timing.Advance();
|
||||||
|
|
||||||
core_timing.ScheduleEvent(1000, cb_chain, CB_IDS[0] + 1);
|
core_timing.ScheduleEvent(1000, cb_chain, CB_IDS[0] + 1);
|
||||||
EXPECT_EQ(1000, PowerPC::ppcState.downcount);
|
EXPECT_EQ(1000, ppc_state.downcount);
|
||||||
|
|
||||||
AdvanceAndCheck(0, MAX_SLICE_LENGTH, 1000); // Run cb_chain into late cb_a
|
AdvanceAndCheck(system, 0, MAX_SLICE_LENGTH, 1000); // Run cb_chain into late cb_a
|
||||||
|
|
||||||
// Schedule late from wrong thread
|
// Schedule late from wrong thread
|
||||||
// The problem with scheduling CPU events from outside the CPU Thread is that g_global_timer
|
// The problem with scheduling CPU events from outside the CPU Thread is that g_global_timer
|
||||||
|
@ -309,14 +313,14 @@ TEST(CoreTiming, ScheduleIntoPast)
|
||||||
core_timing.ScheduleEvent(0, cb_b, CB_IDS[1], CoreTiming::FromThread::NON_CPU);
|
core_timing.ScheduleEvent(0, cb_b, CB_IDS[1], CoreTiming::FromThread::NON_CPU);
|
||||||
core_timing_globals.global_timer += 1000;
|
core_timing_globals.global_timer += 1000;
|
||||||
Core::DeclareAsCPUThread();
|
Core::DeclareAsCPUThread();
|
||||||
AdvanceAndCheck(1, MAX_SLICE_LENGTH, MAX_SLICE_LENGTH + 1000);
|
AdvanceAndCheck(system, 1, MAX_SLICE_LENGTH, MAX_SLICE_LENGTH + 1000);
|
||||||
|
|
||||||
// Schedule directly into the past from the CPU.
|
// Schedule directly into the past from the CPU.
|
||||||
// This shouldn't happen in practice, but it's best if we don't mess up the slice length and
|
// This shouldn't happen in practice, but it's best if we don't mess up the slice length and
|
||||||
// downcount if we do.
|
// downcount if we do.
|
||||||
core_timing.ScheduleEvent(-1000, s_cb_next, CB_IDS[0]);
|
core_timing.ScheduleEvent(-1000, s_cb_next, CB_IDS[0]);
|
||||||
EXPECT_EQ(0, PowerPC::ppcState.downcount);
|
EXPECT_EQ(0, ppc_state.downcount);
|
||||||
AdvanceAndCheck(0, MAX_SLICE_LENGTH, 1000);
|
AdvanceAndCheck(system, 0, MAX_SLICE_LENGTH, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(CoreTiming, Overclocking)
|
TEST(CoreTiming, Overclocking)
|
||||||
|
@ -326,6 +330,7 @@ TEST(CoreTiming, Overclocking)
|
||||||
|
|
||||||
auto& system = Core::System::GetInstance();
|
auto& system = Core::System::GetInstance();
|
||||||
auto& core_timing = system.GetCoreTiming();
|
auto& core_timing = system.GetCoreTiming();
|
||||||
|
auto& ppc_state = system.GetPPCState();
|
||||||
|
|
||||||
CoreTiming::EventType* cb_a = core_timing.RegisterEvent("callbackA", CallbackTemplate<0>);
|
CoreTiming::EventType* cb_a = core_timing.RegisterEvent("callbackA", CallbackTemplate<0>);
|
||||||
CoreTiming::EventType* cb_b = core_timing.RegisterEvent("callbackB", CallbackTemplate<1>);
|
CoreTiming::EventType* cb_b = core_timing.RegisterEvent("callbackB", CallbackTemplate<1>);
|
||||||
|
@ -346,13 +351,13 @@ TEST(CoreTiming, Overclocking)
|
||||||
core_timing.ScheduleEvent(400, cb_c, CB_IDS[2]);
|
core_timing.ScheduleEvent(400, cb_c, CB_IDS[2]);
|
||||||
core_timing.ScheduleEvent(800, cb_d, CB_IDS[3]);
|
core_timing.ScheduleEvent(800, cb_d, CB_IDS[3]);
|
||||||
core_timing.ScheduleEvent(1600, cb_e, CB_IDS[4]);
|
core_timing.ScheduleEvent(1600, cb_e, CB_IDS[4]);
|
||||||
EXPECT_EQ(200, PowerPC::ppcState.downcount);
|
EXPECT_EQ(200, ppc_state.downcount);
|
||||||
|
|
||||||
AdvanceAndCheck(0, 200); // (200 - 100) * 2
|
AdvanceAndCheck(system, 0, 200); // (200 - 100) * 2
|
||||||
AdvanceAndCheck(1, 400); // (400 - 200) * 2
|
AdvanceAndCheck(system, 1, 400); // (400 - 200) * 2
|
||||||
AdvanceAndCheck(2, 800); // (800 - 400) * 2
|
AdvanceAndCheck(system, 2, 800); // (800 - 400) * 2
|
||||||
AdvanceAndCheck(3, 1600); // (1600 - 800) * 2
|
AdvanceAndCheck(system, 3, 1600); // (1600 - 800) * 2
|
||||||
AdvanceAndCheck(4, MAX_SLICE_LENGTH * 2);
|
AdvanceAndCheck(system, 4, MAX_SLICE_LENGTH * 2);
|
||||||
|
|
||||||
// Underclock
|
// Underclock
|
||||||
Config::SetCurrent(Config::MAIN_OVERCLOCK, 0.5f);
|
Config::SetCurrent(Config::MAIN_OVERCLOCK, 0.5f);
|
||||||
|
@ -363,13 +368,13 @@ TEST(CoreTiming, Overclocking)
|
||||||
core_timing.ScheduleEvent(400, cb_c, CB_IDS[2]);
|
core_timing.ScheduleEvent(400, cb_c, CB_IDS[2]);
|
||||||
core_timing.ScheduleEvent(800, cb_d, CB_IDS[3]);
|
core_timing.ScheduleEvent(800, cb_d, CB_IDS[3]);
|
||||||
core_timing.ScheduleEvent(1600, cb_e, CB_IDS[4]);
|
core_timing.ScheduleEvent(1600, cb_e, CB_IDS[4]);
|
||||||
EXPECT_EQ(50, PowerPC::ppcState.downcount);
|
EXPECT_EQ(50, ppc_state.downcount);
|
||||||
|
|
||||||
AdvanceAndCheck(0, 50); // (200 - 100) / 2
|
AdvanceAndCheck(system, 0, 50); // (200 - 100) / 2
|
||||||
AdvanceAndCheck(1, 100); // (400 - 200) / 2
|
AdvanceAndCheck(system, 1, 100); // (400 - 200) / 2
|
||||||
AdvanceAndCheck(2, 200); // (800 - 400) / 2
|
AdvanceAndCheck(system, 2, 200); // (800 - 400) / 2
|
||||||
AdvanceAndCheck(3, 400); // (1600 - 800) / 2
|
AdvanceAndCheck(system, 3, 400); // (1600 - 800) / 2
|
||||||
AdvanceAndCheck(4, MAX_SLICE_LENGTH / 2);
|
AdvanceAndCheck(system, 4, MAX_SLICE_LENGTH / 2);
|
||||||
|
|
||||||
// Try switching the clock mid-emulation
|
// Try switching the clock mid-emulation
|
||||||
Config::SetCurrent(Config::MAIN_OVERCLOCK, 1.0f);
|
Config::SetCurrent(Config::MAIN_OVERCLOCK, 1.0f);
|
||||||
|
@ -380,14 +385,14 @@ TEST(CoreTiming, Overclocking)
|
||||||
core_timing.ScheduleEvent(400, cb_c, CB_IDS[2]);
|
core_timing.ScheduleEvent(400, cb_c, CB_IDS[2]);
|
||||||
core_timing.ScheduleEvent(800, cb_d, CB_IDS[3]);
|
core_timing.ScheduleEvent(800, cb_d, CB_IDS[3]);
|
||||||
core_timing.ScheduleEvent(1600, cb_e, CB_IDS[4]);
|
core_timing.ScheduleEvent(1600, cb_e, CB_IDS[4]);
|
||||||
EXPECT_EQ(100, PowerPC::ppcState.downcount);
|
EXPECT_EQ(100, ppc_state.downcount);
|
||||||
|
|
||||||
AdvanceAndCheck(0, 100); // (200 - 100)
|
AdvanceAndCheck(system, 0, 100); // (200 - 100)
|
||||||
Config::SetCurrent(Config::MAIN_OVERCLOCK, 2.0f);
|
Config::SetCurrent(Config::MAIN_OVERCLOCK, 2.0f);
|
||||||
AdvanceAndCheck(1, 400); // (400 - 200) * 2
|
AdvanceAndCheck(system, 1, 400); // (400 - 200) * 2
|
||||||
AdvanceAndCheck(2, 800); // (800 - 400) * 2
|
AdvanceAndCheck(system, 2, 800); // (800 - 400) * 2
|
||||||
Config::SetCurrent(Config::MAIN_OVERCLOCK, 0.1f);
|
Config::SetCurrent(Config::MAIN_OVERCLOCK, 0.1f);
|
||||||
AdvanceAndCheck(3, 80); // (1600 - 800) / 10
|
AdvanceAndCheck(system, 3, 80); // (1600 - 800) / 10
|
||||||
Config::SetCurrent(Config::MAIN_OVERCLOCK, 1.0f);
|
Config::SetCurrent(Config::MAIN_OVERCLOCK, 1.0f);
|
||||||
AdvanceAndCheck(4, MAX_SLICE_LENGTH);
|
AdvanceAndCheck(system, 4, MAX_SLICE_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,10 +34,12 @@ public:
|
||||||
const u8* raw_fprf_double = GetCodePtr();
|
const u8* raw_fprf_double = GetCodePtr();
|
||||||
GenerateFPRF(false);
|
GenerateFPRF(false);
|
||||||
|
|
||||||
|
auto& ppc_state = system.GetPPCState();
|
||||||
|
|
||||||
fprf_single = Common::BitCast<void (*)(u32)>(GetCodePtr());
|
fprf_single = Common::BitCast<void (*)(u32)>(GetCodePtr());
|
||||||
MOV(ARM64Reg::X15, ARM64Reg::X30);
|
MOV(ARM64Reg::X15, ARM64Reg::X30);
|
||||||
MOV(ARM64Reg::X14, PPC_REG);
|
MOV(ARM64Reg::X14, PPC_REG);
|
||||||
MOVP2R(PPC_REG, &PowerPC::ppcState);
|
MOVP2R(PPC_REG, &ppc_state);
|
||||||
BL(raw_fprf_single);
|
BL(raw_fprf_single);
|
||||||
MOV(ARM64Reg::X30, ARM64Reg::X15);
|
MOV(ARM64Reg::X30, ARM64Reg::X15);
|
||||||
MOV(PPC_REG, ARM64Reg::X14);
|
MOV(PPC_REG, ARM64Reg::X14);
|
||||||
|
@ -46,7 +48,7 @@ public:
|
||||||
fprf_double = Common::BitCast<void (*)(u64)>(GetCodePtr());
|
fprf_double = Common::BitCast<void (*)(u64)>(GetCodePtr());
|
||||||
MOV(ARM64Reg::X15, ARM64Reg::X30);
|
MOV(ARM64Reg::X15, ARM64Reg::X30);
|
||||||
MOV(ARM64Reg::X14, PPC_REG);
|
MOV(ARM64Reg::X14, PPC_REG);
|
||||||
MOVP2R(PPC_REG, &PowerPC::ppcState);
|
MOVP2R(PPC_REG, &ppc_state);
|
||||||
BL(raw_fprf_double);
|
BL(raw_fprf_double);
|
||||||
MOV(ARM64Reg::X30, ARM64Reg::X15);
|
MOV(ARM64Reg::X30, ARM64Reg::X15);
|
||||||
MOV(PPC_REG, ARM64Reg::X14);
|
MOV(PPC_REG, ARM64Reg::X14);
|
||||||
|
@ -59,29 +61,31 @@ public:
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
static u32 RunUpdateFPRF(const std::function<void()>& f)
|
static u32 RunUpdateFPRF(PowerPC::PowerPCState& ppc_state, const std::function<void()>& f)
|
||||||
{
|
{
|
||||||
PowerPC::ppcState.fpscr.Hex = 0x12345678;
|
ppc_state.fpscr.Hex = 0x12345678;
|
||||||
f();
|
f();
|
||||||
return PowerPC::ppcState.fpscr.Hex;
|
return ppc_state.fpscr.Hex;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(JitArm64, FPRF)
|
TEST(JitArm64, FPRF)
|
||||||
{
|
{
|
||||||
TestFPRF test(Core::System::GetInstance());
|
auto& system = Core::System::GetInstance();
|
||||||
|
auto& ppc_state = system.GetPPCState();
|
||||||
|
TestFPRF test(system);
|
||||||
|
|
||||||
for (const u64 double_input : double_test_values)
|
for (const u64 double_input : double_test_values)
|
||||||
{
|
{
|
||||||
const u32 expected_double = RunUpdateFPRF(
|
const u32 expected_double = RunUpdateFPRF(
|
||||||
[&] { PowerPC::ppcState.UpdateFPRFDouble(Common::BitCast<double>(double_input)); });
|
ppc_state, [&] { ppc_state.UpdateFPRFDouble(Common::BitCast<double>(double_input)); });
|
||||||
const u32 actual_double = RunUpdateFPRF([&] { test.fprf_double(double_input); });
|
const u32 actual_double = RunUpdateFPRF(ppc_state, [&] { test.fprf_double(double_input); });
|
||||||
EXPECT_EQ(expected_double, actual_double);
|
EXPECT_EQ(expected_double, actual_double);
|
||||||
|
|
||||||
const u32 single_input = ConvertToSingle(double_input);
|
const u32 single_input = ConvertToSingle(double_input);
|
||||||
|
|
||||||
const u32 expected_single = RunUpdateFPRF(
|
const u32 expected_single = RunUpdateFPRF(
|
||||||
[&] { PowerPC::ppcState.UpdateFPRFSingle(Common::BitCast<float>(single_input)); });
|
ppc_state, [&] { ppc_state.UpdateFPRFSingle(Common::BitCast<float>(single_input)); });
|
||||||
const u32 actual_single = RunUpdateFPRF([&] { test.fprf_single(single_input); });
|
const u32 actual_single = RunUpdateFPRF(ppc_state, [&] { test.fprf_single(single_input); });
|
||||||
EXPECT_EQ(expected_single, actual_single);
|
EXPECT_EQ(expected_single, actual_single);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ public:
|
||||||
fres = Common::BitCast<u64 (*)(u64)>(GetCodePtr());
|
fres = Common::BitCast<u64 (*)(u64)>(GetCodePtr());
|
||||||
MOV(ARM64Reg::X15, ARM64Reg::X30);
|
MOV(ARM64Reg::X15, ARM64Reg::X30);
|
||||||
MOV(ARM64Reg::X14, PPC_REG);
|
MOV(ARM64Reg::X14, PPC_REG);
|
||||||
MOVP2R(PPC_REG, &PowerPC::ppcState);
|
MOVP2R(PPC_REG, &system.GetPPCState());
|
||||||
MOV(ARM64Reg::X1, ARM64Reg::X0);
|
MOV(ARM64Reg::X1, ARM64Reg::X0);
|
||||||
m_float_emit.FMOV(ARM64Reg::D0, ARM64Reg::X0);
|
m_float_emit.FMOV(ARM64Reg::D0, ARM64Reg::X0);
|
||||||
m_float_emit.FRECPE(ARM64Reg::D0, ARM64Reg::D0);
|
m_float_emit.FRECPE(ARM64Reg::D0, ARM64Reg::D0);
|
||||||
|
|
|
@ -34,7 +34,7 @@ public:
|
||||||
frsqrte = Common::BitCast<u64 (*)(u64)>(GetCodePtr());
|
frsqrte = Common::BitCast<u64 (*)(u64)>(GetCodePtr());
|
||||||
MOV(ARM64Reg::X15, ARM64Reg::X30);
|
MOV(ARM64Reg::X15, ARM64Reg::X30);
|
||||||
MOV(ARM64Reg::X14, PPC_REG);
|
MOV(ARM64Reg::X14, PPC_REG);
|
||||||
MOVP2R(PPC_REG, &PowerPC::ppcState);
|
MOVP2R(PPC_REG, &system.GetPPCState());
|
||||||
MOV(ARM64Reg::X1, ARM64Reg::X0);
|
MOV(ARM64Reg::X1, ARM64Reg::X0);
|
||||||
m_float_emit.FMOV(ARM64Reg::D0, ARM64Reg::X0);
|
m_float_emit.FMOV(ARM64Reg::D0, ARM64Reg::X0);
|
||||||
m_float_emit.FRSQRTE(ARM64Reg::D0, ARM64Reg::D0);
|
m_float_emit.FRSQRTE(ARM64Reg::D0, ARM64Reg::D0);
|
||||||
|
|
Loading…
Reference in New Issue