CPU: Support printing instruction operands when tracing

This commit is contained in:
Connor McLaughlin 2019-09-30 17:32:58 +10:00
parent 65c9dfa4fd
commit 8b4ec87055
4 changed files with 135 additions and 86 deletions

View file

@ -6,7 +6,7 @@
Log_SetChannel(CPU::Core);
namespace CPU {
bool TRACE_EXECUTION = false;
u32 TRACE_EXECUTION = 0;
Core::Core() = default;
@ -427,10 +427,10 @@ void Core::WriteCacheControl(u32 value)
m_cache_control = value;
}
static void PrintInstruction(u32 bits, u32 pc)
static void PrintInstruction(u32 bits, u32 pc, Core* state)
{
TinyString instr;
DisassembleInstruction(&instr, pc, bits);
DisassembleInstruction(&instr, pc, bits, state);
std::printf("%08x: %08x %s\n", pc, bits, instr.GetCharArray());
}
@ -449,7 +449,7 @@ void Core::DisassembleAndPrint(u32 addr)
{
u32 bits = 0;
DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(addr, bits);
PrintInstruction(bits, addr);
PrintInstruction(bits, addr, this);
}
void Core::Execute()
@ -512,8 +512,8 @@ void Core::ExecuteInstruction(Instruction inst)
}
#endif
if (TRACE_EXECUTION)
PrintInstruction(inst.bits, m_current_instruction_pc);
if (TRACE_EXECUTION == 1)
PrintInstruction(inst.bits, m_current_instruction_pc, nullptr);
switch (inst.op)
{
@ -1109,6 +1109,9 @@ void Core::ExecuteInstruction(Instruction inst)
UnreachableCode();
break;
}
if (TRACE_EXECUTION == 2)
PrintInstruction(inst.bits, m_current_instruction_pc, this);
}
void Core::ExecuteCop0Instruction(Instruction inst)

View file

@ -137,7 +137,7 @@ private:
GTE::Core m_cop2;
};
extern bool TRACE_EXECUTION;
extern u32 TRACE_EXECUTION;
} // namespace CPU

View file

@ -1,4 +1,5 @@
#include "cpu_disasm.h"
#include "cpu_core.h"
#include <array>
namespace CPU {
@ -75,18 +76,18 @@ static const std::array<const char*, 64> s_base_table = {{
"UNKNOWN", // 45
"swr $rt, $offsetrs", // 46
"UNKNOWN", // 47
"UNKNOWN", // 48
"UNKNOWN", // 49
"UNKNOWN", // 50
"UNKNOWN", // 51
"lwc0 $coprt, $offsetrs", // 48
"lwc1 $coprt, $offsetrs", // 49
"lwc2 $coprt, $offsetrs", // 50
"lwc3 $coprt, $offsetrs", // 51
"UNKNOWN", // 52
"UNKNOWN", // 53
"UNKNOWN", // 54
"UNKNOWN", // 55
"UNKNOWN", // 56
"UNKNOWN", // 57
"UNKNOWN", // 58
"UNKNOWN", // 59
"swc0 $coprt, $offsetrs", // 56
"swc1 $coprt, $offsetrs", // 57
"swc2 $coprt, $offsetrs", // 58
"swc3 $coprt, $offsetrs", // 59
"UNKNOWN", // 60
"UNKNOWN", // 61
"UNKNOWN", // 62
@ -162,17 +163,19 @@ static const std::array<const char*, 64> s_special_table = {{
static const std::array<std::pair<CopCommonInstruction, const char*>, 5> s_cop_common_table = {
{{CopCommonInstruction::mfcn, "mfc$cop $rt, $coprd"},
{CopCommonInstruction::cfcn, "cfc$cop $rt, $copcr"},
{CopCommonInstruction::cfcn, "cfc$cop $rt, $coprd"},
{CopCommonInstruction::mtcn, "mtc$cop $rt, $coprd"},
{CopCommonInstruction::ctcn, "ctc$cop $rt, $copcr"},
{CopCommonInstruction::ctcn, "ctc$cop $rt, $coprd"},
{CopCommonInstruction::bcnc, "bc$cop$copcc $rel"}}};
static const std::array<std::pair<Cop0Instruction, const char*>, 1> s_cop0_table = {{{Cop0Instruction::rfe, "rfe"}}};
static void FormatInstruction(String* dest, const Instruction inst, u32 pc, const char* format)
static void FormatInstruction(String* dest, const Instruction inst, u32 pc, Core* state, const char* format)
{
dest->Clear();
TinyString comment;
const char* str = format;
while (*str != '\0')
{
@ -186,16 +189,37 @@ static void FormatInstruction(String* dest, const Instruction inst, u32 pc, cons
if (std::strncmp(str, "rs", 2) == 0)
{
dest->AppendString(s_reg_names[static_cast<u8>(inst.r.rs.GetValue())]);
if (state)
{
comment.AppendFormattedString("%s%s=0x%08X", comment.IsEmpty() ? "" : ", ",
s_reg_names[static_cast<u8>(inst.r.rs.GetValue())],
state->GetRegs().r[static_cast<u8>(inst.r.rs.GetValue())]);
}
str += 2;
}
else if (std::strncmp(str, "rt", 2) == 0)
{
dest->AppendString(s_reg_names[static_cast<u8>(inst.r.rt.GetValue())]);
if (state)
{
comment.AppendFormattedString("%s%s=0x%08X", comment.IsEmpty() ? "" : ", ",
s_reg_names[static_cast<u8>(inst.r.rt.GetValue())],
state->GetRegs().r[static_cast<u8>(inst.r.rt.GetValue())]);
}
str += 2;
}
else if (std::strncmp(str, "rd", 2) == 0)
{
dest->AppendString(s_reg_names[static_cast<u8>(inst.r.rd.GetValue())]);
if (state)
{
comment.AppendFormattedString("%s%s=0x%08X", comment.IsEmpty() ? "" : ", ",
s_reg_names[static_cast<u8>(inst.r.rd.GetValue())],
state->GetRegs().r[static_cast<u8>(inst.r.rd.GetValue())]);
}
str += 2;
}
else if (std::strncmp(str, "shamt", 5) == 0)
@ -224,6 +248,12 @@ static void FormatInstruction(String* dest, const Instruction inst, u32 pc, cons
{
const s32 offset = static_cast<s32>(inst.i.imm_sext32());
dest->AppendFormattedString("%d(%s)", offset, s_reg_names[static_cast<u8>(inst.i.rs.GetValue())]);
if (state)
{
comment.AppendFormattedString("%saddr=0x%08X", comment.IsEmpty() ? "" : ", ",
state->GetRegs().r[static_cast<u8>(inst.i.rs.GetValue())] + offset);
}
str += 8;
}
else if (std::strncmp(str, "jt", 2) == 0)
@ -237,11 +267,16 @@ static void FormatInstruction(String* dest, const Instruction inst, u32 pc, cons
dest->AppendCharacter(((inst.bits & (UINT32_C(1) << 24)) != 0) ? 't' : 'f');
str += 5;
}
else if (std::strncmp(str, "coprd", 5) == 0 || std::strncmp(str, "copcr", 5) == 0)
else if (std::strncmp(str, "coprd", 5) == 0)
{
dest->AppendFormattedString("%u", ZeroExtend32(static_cast<u8>(inst.r.rd.GetValue())));
str += 5;
}
else if (std::strncmp(str, "coprt", 5) == 0)
{
dest->AppendFormattedString("%u", ZeroExtend32(static_cast<u8>(inst.r.rt.GetValue())));
str += 5;
}
else if (std::strncmp(str, "cop", 3) == 0)
{
dest->AppendFormattedString("%u", static_cast<u8>(inst.op.GetValue()) & INSTRUCTION_COP_N_MASK);
@ -252,17 +287,25 @@ static void FormatInstruction(String* dest, const Instruction inst, u32 pc, cons
Panic("Unknown operand");
}
}
if (!comment.IsEmpty())
{
for (u32 i = dest->GetLength(); i < 30; i++)
dest->AppendCharacter(' ');
dest->AppendString("; ");
dest->AppendString(comment);
}
}
template<typename T>
void FormatCopInstruction(String* dest, u32 pc, const Instruction inst, const std::pair<T, const char*>* table,
size_t table_size, T table_key)
void FormatCopInstruction(String* dest, u32 pc, Core* state, const Instruction inst,
const std::pair<T, const char*>* table, size_t table_size, T table_key)
{
for (size_t i = 0; i < table_size; i++)
{
if (table[i].first == table_key)
{
FormatInstruction(dest, inst, pc, table[i].second);
FormatInstruction(dest, inst, pc, state, table[i].second);
return;
}
}
@ -270,13 +313,13 @@ void FormatCopInstruction(String* dest, u32 pc, const Instruction inst, const st
dest->Format("<cop%u 0x%08X>", ZeroExtend32(inst.cop.cop_n.GetValue()), inst.cop.imm25.GetValue());
}
void DisassembleInstruction(String* dest, u32 pc, u32 bits)
void DisassembleInstruction(String* dest, u32 pc, u32 bits, Core* state)
{
const Instruction inst{bits};
switch (inst.op)
{
case InstructionOp::funct:
FormatInstruction(dest, inst, pc, s_special_table[static_cast<u8>(inst.r.funct.GetValue())]);
FormatInstruction(dest, inst, pc, state, s_special_table[static_cast<u8>(inst.r.funct.GetValue())]);
return;
case InstructionOp::cop0:
@ -286,7 +329,8 @@ void DisassembleInstruction(String* dest, u32 pc, u32 bits)
{
if (inst.cop.IsCommonInstruction())
{
FormatCopInstruction(dest, pc, inst, s_cop_common_table.data(), s_cop_common_table.size(), inst.cop.CommonOp());
FormatCopInstruction(dest, pc, state, inst, s_cop_common_table.data(), s_cop_common_table.size(),
inst.cop.CommonOp());
}
else
{
@ -294,7 +338,7 @@ void DisassembleInstruction(String* dest, u32 pc, u32 bits)
{
case InstructionOp::cop0:
{
FormatCopInstruction(dest, pc, inst, s_cop0_table.data(), s_cop0_table.size(), inst.cop.Cop0Op());
FormatCopInstruction(dest, pc, state, inst, s_cop0_table.data(), s_cop0_table.size(), inst.cop.Cop0Op());
}
break;
@ -318,14 +362,14 @@ void DisassembleInstruction(String* dest, u32 pc, u32 bits)
const bool bgez = ConvertToBoolUnchecked(rt & u8(1));
const bool link = ConvertToBoolUnchecked((rt >> 4) & u8(1));
if (link)
FormatInstruction(dest, inst, pc, bgez ? "bgezal $rs, $rel" : "bltzal $rs, $rel");
FormatInstruction(dest, inst, pc, state, bgez ? "bgezal $rs, $rel" : "bltzal $rs, $rel");
else
FormatInstruction(dest, inst, pc, bgez ? "bgez $rs, $rel" : "bltz $rs, $rel");
FormatInstruction(dest, inst, pc, state, bgez ? "bgez $rs, $rel" : "bltz $rs, $rel");
}
break;
default:
FormatInstruction(dest, inst, pc, s_base_table[static_cast<u8>(inst.op.GetValue())]);
FormatInstruction(dest, inst, pc, state, s_base_table[static_cast<u8>(inst.op.GetValue())]);
break;
}
}

View file

@ -3,5 +3,7 @@
#include "cpu_types.h"
namespace CPU {
void DisassembleInstruction(String* dest, u32 pc, u32 bits);
class Core;
void DisassembleInstruction(String* dest, u32 pc, u32 bits, Core* state = nullptr);
} // namespace CPU