mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-22 05:45:38 +00:00
CPU: Add disassembly of GTE instructions
This commit is contained in:
parent
e08f888e72
commit
cffb383c10
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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] : "";
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue