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

View file

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

View file

@ -1,4 +1,5 @@
#include "cpu_disasm.h" #include "cpu_disasm.h"
#include "cpu_core.h"
#include <array> #include <array>
namespace CPU { namespace CPU {
@ -75,18 +76,18 @@ static const std::array<const char*, 64> s_base_table = {{
"UNKNOWN", // 45 "UNKNOWN", // 45
"swr $rt, $offsetrs", // 46 "swr $rt, $offsetrs", // 46
"UNKNOWN", // 47 "UNKNOWN", // 47
"UNKNOWN", // 48 "lwc0 $coprt, $offsetrs", // 48
"UNKNOWN", // 49 "lwc1 $coprt, $offsetrs", // 49
"UNKNOWN", // 50 "lwc2 $coprt, $offsetrs", // 50
"UNKNOWN", // 51 "lwc3 $coprt, $offsetrs", // 51
"UNKNOWN", // 52 "UNKNOWN", // 52
"UNKNOWN", // 53 "UNKNOWN", // 53
"UNKNOWN", // 54 "UNKNOWN", // 54
"UNKNOWN", // 55 "UNKNOWN", // 55
"UNKNOWN", // 56 "swc0 $coprt, $offsetrs", // 56
"UNKNOWN", // 57 "swc1 $coprt, $offsetrs", // 57
"UNKNOWN", // 58 "swc2 $coprt, $offsetrs", // 58
"UNKNOWN", // 59 "swc3 $coprt, $offsetrs", // 59
"UNKNOWN", // 60 "UNKNOWN", // 60
"UNKNOWN", // 61 "UNKNOWN", // 61
"UNKNOWN", // 62 "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 = { static const std::array<std::pair<CopCommonInstruction, const char*>, 5> s_cop_common_table = {
{{CopCommonInstruction::mfcn, "mfc$cop $rt, $coprd"}, {{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::mtcn, "mtc$cop $rt, $coprd"},
{CopCommonInstruction::ctcn, "ctc$cop $rt, $copcr"}, {CopCommonInstruction::ctcn, "ctc$cop $rt, $coprd"},
{CopCommonInstruction::bcnc, "bc$cop$copcc $rel"}}}; {CopCommonInstruction::bcnc, "bc$cop$copcc $rel"}}};
static const std::array<std::pair<Cop0Instruction, const char*>, 1> s_cop0_table = {{{Cop0Instruction::rfe, "rfe"}}}; 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(); dest->Clear();
TinyString comment;
const char* str = format; const char* str = format;
while (*str != '\0') 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) if (std::strncmp(str, "rs", 2) == 0)
{ {
dest->AppendString(s_reg_names[static_cast<u8>(inst.r.rs.GetValue())]); 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; str += 2;
} }
else if (std::strncmp(str, "rt", 2) == 0) else if (std::strncmp(str, "rt", 2) == 0)
{ {
dest->AppendString(s_reg_names[static_cast<u8>(inst.r.rt.GetValue())]); 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; str += 2;
} }
else if (std::strncmp(str, "rd", 2) == 0) else if (std::strncmp(str, "rd", 2) == 0)
{ {
dest->AppendString(s_reg_names[static_cast<u8>(inst.r.rd.GetValue())]); 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; str += 2;
} }
else if (std::strncmp(str, "shamt", 5) == 0) 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()); 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())]); 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; str += 8;
} }
else if (std::strncmp(str, "jt", 2) == 0) 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'); dest->AppendCharacter(((inst.bits & (UINT32_C(1) << 24)) != 0) ? 't' : 'f');
str += 5; 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()))); dest->AppendFormattedString("%u", ZeroExtend32(static_cast<u8>(inst.r.rd.GetValue())));
str += 5; 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) else if (std::strncmp(str, "cop", 3) == 0)
{ {
dest->AppendFormattedString("%u", static_cast<u8>(inst.op.GetValue()) & INSTRUCTION_COP_N_MASK); 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"); Panic("Unknown operand");
} }
} }
if (!comment.IsEmpty())
{
for (u32 i = dest->GetLength(); i < 30; i++)
dest->AppendCharacter(' ');
dest->AppendString("; ");
dest->AppendString(comment);
}
} }
template<typename T> template<typename T>
void FormatCopInstruction(String* dest, u32 pc, const Instruction inst, const std::pair<T, const char*>* table, void FormatCopInstruction(String* dest, u32 pc, Core* state, const Instruction inst,
size_t table_size, T table_key) const std::pair<T, const char*>* table, size_t table_size, T table_key)
{ {
for (size_t i = 0; i < table_size; i++) for (size_t i = 0; i < table_size; i++)
{ {
if (table[i].first == table_key) if (table[i].first == table_key)
{ {
FormatInstruction(dest, inst, pc, table[i].second); FormatInstruction(dest, inst, pc, state, table[i].second);
return; 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()); 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}; const Instruction inst{bits};
switch (inst.op) switch (inst.op)
{ {
case InstructionOp::funct: 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; return;
case InstructionOp::cop0: case InstructionOp::cop0:
@ -286,7 +329,8 @@ void DisassembleInstruction(String* dest, u32 pc, u32 bits)
{ {
if (inst.cop.IsCommonInstruction()) 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 else
{ {
@ -294,7 +338,7 @@ void DisassembleInstruction(String* dest, u32 pc, u32 bits)
{ {
case InstructionOp::cop0: 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; break;
@ -318,14 +362,14 @@ void DisassembleInstruction(String* dest, u32 pc, u32 bits)
const bool bgez = ConvertToBoolUnchecked(rt & u8(1)); const bool bgez = ConvertToBoolUnchecked(rt & u8(1));
const bool link = ConvertToBoolUnchecked((rt >> 4) & u8(1)); const bool link = ConvertToBoolUnchecked((rt >> 4) & u8(1));
if (link) 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 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; break;
default: 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; break;
} }
} }

View file

@ -3,5 +3,7 @@
#include "cpu_types.h" #include "cpu_types.h"
namespace CPU { 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 } // namespace CPU