CPU: Add disassembly of GTE instructions

This commit is contained in:
Stenzek 2023-12-17 00:37:06 +10:00
parent e08f888e72
commit cffb383c10
No known key found for this signature in database
4 changed files with 134 additions and 22 deletions

View file

@ -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<std::pair<CopCommonInstruction, const char*>, 4> s_cop_c
static const std::array<std::pair<Cop0Instruction, const char*>, 1> s_cop0_table = {{{Cop0Instruction::rfe, "rfe"}}};
static constexpr const std::array<const char*, 64> 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<GTEInstructionTable, 64> 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<u8>(inst.r.rd.GetValue())));
if (inst.IsCop2Instruction())
dest->append(GetGTERegisterName(static_cast<u8>(inst.r.rd.GetValue())));
else
dest->append_format("{}", ZeroExtend32(static_cast<u8>(inst.r.rd.GetValue())));
str += 5;
}
else if (std::strncmp(str, "coprt", 5) == 0)
{
dest->append_format("{}", ZeroExtend32(static_cast<u8>(inst.r.rt.GetValue())));
if (inst.IsCop2Instruction())
dest->append(GetGTERegisterName(static_cast<u8>(inst.r.rt.GetValue())));
else
dest->append_format("{}", ZeroExtend32(static_cast<u8>(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<u8>(inst.r.rs.GetValue())]);
regs->r[static_cast<u8>(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<u8>(inst.r.rt.GetValue())]);
regs->r[static_cast<u8>(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<u8>(inst.r.rd.GetValue())]);
regs->r[static_cast<u8>(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<s32>(inst.i.imm_sext32());
dest->append_format("{}addr={:08X}", dest->empty() ? "" : ", ",
regs->r[static_cast<u8>(inst.i.rs.GetValue())] + offset);
regs->r[static_cast<u8>(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<u8>(gi.mvmva_multiply_matrix),
static_cast<u8>(gi.mvmva_multiply_vector), static_cast<u8>(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

View file

@ -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

View file

@ -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<const char*, 64> 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] : "";
}

View file

@ -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