From cffb383c100e449707562380d60fb0178c15bcdb Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sun, 17 Dec 2023 00:37:06 +1000 Subject: [PATCH] CPU: Add disassembly of GTE instructions --- src/core/cpu_disasm.cpp | 138 +++++++++++++++++++++++++++++++++++++--- src/core/cpu_disasm.h | 4 ++ src/core/gte.cpp | 12 ---- src/core/gte.h | 2 - 4 files changed, 134 insertions(+), 22 deletions(-) diff --git a/src/core/cpu_disasm.cpp b/src/core/cpu_disasm.cpp index dd4c29c91..02c791327 100644 --- a/src/core/cpu_disasm.cpp +++ b/src/core/cpu_disasm.cpp @@ -3,6 +3,7 @@ #include "cpu_disasm.h" #include "cpu_core.h" +#include "cpu_types.h" #include "common/assert.h" #include "common/small_string.h" @@ -172,6 +173,89 @@ static const std::array, 4> s_cop_c static const std::array, 1> s_cop0_table = {{{Cop0Instruction::rfe, "rfe"}}}; +static constexpr const std::array s_gte_register_names = { + {"v0_xy", "v0_z", "v1_xy", "v1_z", "v2_xy", "v2_z", "rgbc", "otz", "ir0", "ir1", "ir2", "ir3", "sxy0", + "sxy1", "sxy2", "sxyp", "sz0", "sz1", "sz2", "sz3", "rgb0", "rgb1", "rgb2", "res1", "mac0", "mac1", + "mac2", "mac3", "irgb", "orgb", "lzcs", "lzcr", "rt_0", "rt_1", "rt_2", "rt_3", "rt_4", "trx", "try", + "trz", "llm_0", "llm_1", "llm_2", "llm_3", "llm_4", "rbk", "gbk", "bbk", "lcm_0", "lcm_1", "lcm_2", "lcm_3", + "lcm_4", "rfc", "gfc", "bfc", "ofx", "ofy", "h", "dqa", "dqb", "zsf3", "zsf4", "flag"}}; + +namespace { +struct GTEInstructionTable +{ + const char* name; + bool sf; + bool lm; + bool mvmva; +}; +} // namespace +static constexpr const std::array s_gte_instructions = {{ + {"rtps", true, true, false}, // 0x00 + {"nclip", false, false, false}, // 0x01 + {"UNKNOWN", false, false, false}, // 0x02 + {"UNKNOWN", false, false, false}, // 0x03 + {"UNKNOWN", false, false, false}, // 0x04 + {"UNKNOWN", false, false, false}, // 0x05 + {"UNKNOWN", false, false, false}, // 0x06 + {"UNKNOWN", false, false, false}, // 0x07 + {"UNKNOWN", false, false, false}, // 0x08 + {"UNKNOWN", false, false, false}, // 0x09 + {"UNKNOWN", false, false, false}, // 0x0A + {"UNKNOWN", false, false, false}, // 0x0B + {"op", true, true, false}, // 0x0C + {"UNKNOWN", false, false, false}, // 0x0D + {"UNKNOWN", false, false, false}, // 0x0E + {"UNKNOWN", false, false, false}, // 0x0F + {"dpcs", true, true, false}, // 0x10 + {"intpl", true, true, false}, // 0x11 + {"mvmva", true, true, true}, // 0x12 + {"ncds", true, true, false}, // 0x13 + {"cdp", true, true, false}, // 0x14 + {"UNKNOWN", false, false, false}, // 0x15 + {"ncdt", true, true, false}, // 0x16 + {"UNKNOWN", false, false, false}, // 0x17 + {"UNKNOWN", false, false, false}, // 0x18 + {"UNKNOWN", false, false, false}, // 0x19 + {"UNKNOWN", false, false, false}, // 0x1A + {"nccs", true, true, false}, // 0x1B + {"cc", true, true, false}, // 0x1C + {"UNKNOWN", false, false, false}, // 0x1D + {"ncs", true, true, false}, // 0x1E + {"UNKNOWN", false, false, false}, // 0x1F + {"nct", true, true, false}, // 0x20 + {"UNKNOWN", false, false, false}, // 0x21 + {"UNKNOWN", false, false, false}, // 0x22 + {"UNKNOWN", false, false, false}, // 0x23 + {"UNKNOWN", false, false, false}, // 0x24 + {"UNKNOWN", false, false, false}, // 0x25 + {"UNKNOWN", false, false, false}, // 0x26 + {"UNKNOWN", false, false, false}, // 0x27 + {"sqr", true, true, false}, // 0x28 + {"dcpl", true, true, false}, // 0x29 + {"dpct", true, true, false}, // 0x2A + {"UNKNOWN", false, false, false}, // 0x2B + {"UNKNOWN", false, false, false}, // 0x2C + {"avsz3", false, false, false}, // 0x2D + {"avsz4", false, false, false}, // 0x2E + {"UNKNOWN", false, false, false}, // 0x2F + {"rtpt", true, true, false}, // 0x30 + {"UNKNOWN", false, false, false}, // 0x31 + {"UNKNOWN", false, false, false}, // 0x32 + {"UNKNOWN", false, false, false}, // 0x33 + {"UNKNOWN", false, false, false}, // 0x34 + {"UNKNOWN", false, false, false}, // 0x35 + {"UNKNOWN", false, false, false}, // 0x36 + {"UNKNOWN", false, false, false}, // 0x37 + {"UNKNOWN", false, false, false}, // 0x38 + {"UNKNOWN", false, false, false}, // 0x39 + {"UNKNOWN", false, false, false}, // 0x3A + {"UNKNOWN", false, false, false}, // 0x3B + {"UNKNOWN", false, false, false}, // 0x3C + {"gpf", true, true, false}, // 0x3D + {"gpl", true, true, false}, // 0x3E + {"ncct", true, true, false}, // 0x3F +}}; + static void FormatInstruction(SmallStringBase* dest, const Instruction inst, u32 pc, const char* format) { dest->clear(); @@ -242,12 +326,18 @@ static void FormatInstruction(SmallStringBase* dest, const Instruction inst, u32 } else if (std::strncmp(str, "coprd", 5) == 0) { - dest->append_format("{}", ZeroExtend32(static_cast(inst.r.rd.GetValue()))); + if (inst.IsCop2Instruction()) + dest->append(GetGTERegisterName(static_cast(inst.r.rd.GetValue()))); + else + dest->append_format("{}", ZeroExtend32(static_cast(inst.r.rd.GetValue()))); str += 5; } else if (std::strncmp(str, "coprt", 5) == 0) { - dest->append_format("{}", ZeroExtend32(static_cast(inst.r.rt.GetValue()))); + if (inst.IsCop2Instruction()) + dest->append(GetGTERegisterName(static_cast(inst.r.rt.GetValue()))); + else + dest->append_format("{}", ZeroExtend32(static_cast(inst.r.rt.GetValue()))); str += 5; } else if (std::strncmp(str, "cop", 3) == 0) @@ -274,20 +364,20 @@ static void FormatComment(SmallStringBase* dest, const Instruction inst, u32 pc, if (std::strncmp(str, "rs", 2) == 0) { dest->append_format("{}{}=0x{:08X}", dest->empty() ? "" : ", ", GetRegName(inst.r.rs), - regs->r[static_cast(inst.r.rs.GetValue())]); + regs->r[static_cast(inst.r.rs.GetValue())]); str += 2; } else if (std::strncmp(str, "rt", 2) == 0) { dest->append_format("{}{}=0x{:08X}", dest->empty() ? "" : ", ", GetRegName(inst.r.rt), - regs->r[static_cast(inst.r.rt.GetValue())]); + regs->r[static_cast(inst.r.rt.GetValue())]); str += 2; } else if (std::strncmp(str, "rd", 2) == 0) { dest->append_format("{}{}=0x{:08X}", dest->empty() ? "" : ", ", GetRegName(inst.r.rd), - regs->r[static_cast(inst.r.rd.GetValue())]); + regs->r[static_cast(inst.r.rd.GetValue())]); str += 2; } else if (std::strncmp(str, "shamt", 5) == 0) @@ -310,7 +400,7 @@ static void FormatComment(SmallStringBase* dest, const Instruction inst, u32 pc, { const s32 offset = static_cast(inst.i.imm_sext32()); dest->append_format("{}addr={:08X}", dest->empty() ? "" : ", ", - regs->r[static_cast(inst.i.rs.GetValue())] + offset); + regs->r[static_cast(inst.i.rs.GetValue())] + offset); str += 8; } else if (std::strncmp(str, "jt", 2) == 0) @@ -370,6 +460,25 @@ static void FormatCopComment(SmallStringBase* dest, u32 pc, Registers* regs, con } } +static void FormatGTEInstruction(SmallStringBase* dest, u32 pc, const Instruction inst) +{ + const GTE::Instruction gi{inst.bits}; + const GTEInstructionTable& t = s_gte_instructions[gi.command]; + dest->append(t.name); + + if (t.sf && gi.sf) + dest->append(" sf"); + + if (t.lm && gi.lm) + dest->append(" lm"); + + if (t.mvmva) + { + dest->append_format(" m={} v={} t={}", static_cast(gi.mvmva_multiply_matrix), + static_cast(gi.mvmva_multiply_vector), static_cast(gi.mvmva_translation_vector)); + } +} + void DisassembleInstruction(SmallStringBase* dest, u32 pc, u32 bits) { const Instruction inst{bits}; @@ -398,8 +507,13 @@ void DisassembleInstruction(SmallStringBase* dest, u32 pc, u32 bits) } break; - case InstructionOp::cop1: case InstructionOp::cop2: + { + FormatGTEInstruction(dest, pc, inst); + } + break; + + case InstructionOp::cop1: case InstructionOp::cop3: default: { @@ -459,8 +573,11 @@ void DisassembleInstructionComment(SmallStringBase* dest, u32 pc, u32 bits, Regi } break; - case InstructionOp::cop1: case InstructionOp::cop2: + // TODO: Show GTE regs? + break; + + case InstructionOp::cop1: case InstructionOp::cop3: default: { @@ -491,4 +608,9 @@ void DisassembleInstructionComment(SmallStringBase* dest, u32 pc, u32 bits, Regi } } +const char* CPU::GetGTERegisterName(u32 index) +{ + return (index < s_gte_register_names.size()) ? s_gte_register_names[index] : ""; +} + } // namespace CPU \ No newline at end of file diff --git a/src/core/cpu_disasm.h b/src/core/cpu_disasm.h index b3968bffa..9cff8ed71 100644 --- a/src/core/cpu_disasm.h +++ b/src/core/cpu_disasm.h @@ -7,6 +7,10 @@ class SmallStringBase; namespace CPU { + void DisassembleInstruction(SmallStringBase* dest, u32 pc, u32 bits); void DisassembleInstructionComment(SmallStringBase* dest, u32 pc, u32 bits, Registers* regs); + +const char* GetGTERegisterName(u32 index); + } // namespace CPU diff --git a/src/core/gte.cpp b/src/core/gte.cpp index 226b93771..3582429dd 100644 --- a/src/core/gte.cpp +++ b/src/core/gte.cpp @@ -1401,15 +1401,3 @@ GTE::InstructionImpl GTE::GetInstructionImpl(u32 inst_bits, TickCount* ticks) Panic("Missing handler"); } } - -const char* GTE::GetRegisterName(u32 index) -{ - static constexpr std::array names = { - {"V0_XY", "V0_Z", "V1_XY", "V1_Z", "V2_XY", "V2_Z", "RGBC", "OTZ", "IR0", "IR1", "IR2", "IR3", "SXY0", - "SXY1", "SXY2", "SXYP", "SZ0", "SZ1", "SZ2", "SZ3", "RGB0", "RGB1", "RGB2", "RES1", "MAC0", "MAC1", - "MAC2", "MAC3", "IRGB", "ORGB", "LZCS", "LZCR", "RT_0", "RT_1", "RT_2", "RT_3", "RT_4", "TRX", "TRY", - "TRZ", "LLM_0", "LLM_1", "LLM_2", "LLM_3", "LLM_4", "RBK", "GBK", "BBK", "LCM_0", "LCM_1", "LCM_2", "LCM_3", - "LCM_4", "RFC", "GFC", "BFC", "OFX", "OFY", "H", "DQA", "DQB", "ZSF3", "ZSF4", "FLAG"}}; - - return (index < names.size()) ? names[index] : ""; -} diff --git a/src/core/gte.h b/src/core/gte.h index 67165c9d8..c2249dd01 100644 --- a/src/core/gte.h +++ b/src/core/gte.h @@ -25,6 +25,4 @@ void ExecuteInstruction(u32 inst_bits); using InstructionImpl = void (*)(Instruction); InstructionImpl GetInstructionImpl(u32 inst_bits, TickCount* ticks); -const char* GetRegisterName(u32 index); - } // namespace GTE