mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 10:19:47 -04:00
2fd4625d74
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
137 lines
6.4 KiB
C++
137 lines
6.4 KiB
C++
#include "psx_disasm.h"
|
|
#include "mips_decoder.h"
|
|
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
|
|
/* C-linkage bridge so the C debug server can use the C++ MIPS decoder that the
|
|
* recompiler already ships (recompiler/src/mips_decoder.cpp). */
|
|
|
|
/* GTE data registers (COP2 rd index) — psx-spx. */
|
|
static const char* const kCop2Data[32] = {
|
|
"VXY0", "VZ0", "VXY1", "VZ1", "VXY2", "VZ2", "RGB", "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"
|
|
};
|
|
|
|
/* GTE control registers (COP2 rd index) — psx-spx. */
|
|
static const char* const kCop2Ctrl[32] = {
|
|
"RT11RT12", "RT13RT21", "RT22RT23", "RT31RT32", "RT33", "TRX", "TRY", "TRZ",
|
|
"L11L12", "L13L21", "L22L23", "L31L32", "L33", "RBK", "GBK", "BBK",
|
|
"LR1LR2", "LR3LG1", "LG2LG3", "LB1LB2", "LB3", "RFC", "GFC", "BFC",
|
|
"OFX", "OFY", "H", "DQA", "DQB", "ZSF3", "ZSF4", "FLAG"
|
|
};
|
|
|
|
static const char* gte_cmd_name(uint32_t raw) {
|
|
switch (raw & 0x3Fu) {
|
|
case 0x01: return "RTPS";
|
|
case 0x06: return "NCLIP";
|
|
case 0x0C: return "OP";
|
|
case 0x10: return "DPCS";
|
|
case 0x11: return "INTPL";
|
|
case 0x12: return "MVMVA";
|
|
case 0x13: return "NCDS";
|
|
case 0x14: return "CDP";
|
|
case 0x16: return "NCDT";
|
|
case 0x1B: return "NCCS";
|
|
case 0x1C: return "CC";
|
|
case 0x1E: return "NCS";
|
|
case 0x20: return "NCT";
|
|
case 0x28: return "SQR";
|
|
case 0x29: return "DCPL";
|
|
case 0x2A: return "DPCT";
|
|
case 0x2D: return "AVSZ3";
|
|
case 0x2E: return "AVSZ4";
|
|
case 0x30: return "RTPT";
|
|
case 0x3D: return "GPF";
|
|
case 0x3E: return "GPL";
|
|
case 0x3F: return "NCCT";
|
|
default: return "GTE";
|
|
}
|
|
}
|
|
|
|
extern "C" int psx_disasm_one(uint32_t word, uint32_t addr, char* out, int cap) {
|
|
if (!out || cap <= 0) return 0;
|
|
using PSXRecomp::DecodedInstruction;
|
|
using PSXRecomp::InstrFormat;
|
|
using PSXRecomp::MipsDecoder;
|
|
|
|
DecodedInstruction d = MipsDecoder::decode(word, addr);
|
|
const char* m = d.mnemonic ? d.mnemonic : "???";
|
|
auto rn = [](uint8_t r) { return MipsDecoder::register_name(r); };
|
|
uint8_t cop = d.rd & 0x1F;
|
|
|
|
int n;
|
|
if (d.format == InstrFormat::UNKNOWN) {
|
|
n = std::snprintf(out, (size_t)cap, ".word 0x%08X", word);
|
|
} else if (word == 0u) {
|
|
n = std::snprintf(out, (size_t)cap, "NOP");
|
|
} else if (std::strcmp(m, "JR") == 0) {
|
|
n = std::snprintf(out, (size_t)cap, "%-8s %s", m, rn(d.rs));
|
|
} else if (std::strcmp(m, "JALR") == 0) {
|
|
n = std::snprintf(out, (size_t)cap, "%-8s %s, %s", m, rn(d.rd), rn(d.rs));
|
|
} else if (std::strcmp(m, "SLL") == 0 || std::strcmp(m, "SRL") == 0 ||
|
|
std::strcmp(m, "SRA") == 0) {
|
|
n = std::snprintf(out, (size_t)cap, "%-8s %s, %s, %d", m, rn(d.rd), rn(d.rt),
|
|
d.shamt);
|
|
} else if (std::strcmp(m, "MFHI") == 0 || std::strcmp(m, "MFLO") == 0) {
|
|
n = std::snprintf(out, (size_t)cap, "%-8s %s", m, rn(d.rd));
|
|
} else if (std::strcmp(m, "MTHI") == 0 || std::strcmp(m, "MTLO") == 0) {
|
|
n = std::snprintf(out, (size_t)cap, "%-8s %s", m, rn(d.rs));
|
|
} else if (std::strcmp(m, "SYSCALL") == 0 || std::strcmp(m, "BREAK") == 0) {
|
|
n = std::snprintf(out, (size_t)cap, "%s", m);
|
|
} else if (std::strcmp(m, "MULT") == 0 || std::strcmp(m, "MULTU") == 0 ||
|
|
std::strcmp(m, "DIV") == 0 || std::strcmp(m, "DIVU") == 0) {
|
|
n = std::snprintf(out, (size_t)cap, "%-8s %s, %s", m, rn(d.rs), rn(d.rt));
|
|
} else if (std::strcmp(m, "SLLV") == 0 || std::strcmp(m, "SRLV") == 0 ||
|
|
std::strcmp(m, "SRAV") == 0) {
|
|
n = std::snprintf(out, (size_t)cap, "%-8s %s, %s, %s", m, rn(d.rd), rn(d.rt), rn(d.rs));
|
|
} else if (d.format == InstrFormat::COP0) {
|
|
if (std::strcmp(m, "MFC0") == 0 || std::strcmp(m, "MTC0") == 0)
|
|
n = std::snprintf(out, (size_t)cap, "%-8s %s, $%u", m, rn(d.rt), (unsigned)cop);
|
|
else if (std::strcmp(m, "RFE") == 0)
|
|
n = std::snprintf(out, (size_t)cap, "%s", m);
|
|
else
|
|
n = std::snprintf(out, (size_t)cap, ".word 0x%08X", word);
|
|
} else if (d.format == InstrFormat::COP2) {
|
|
if (std::strcmp(m, "MFC2") == 0 || std::strcmp(m, "MTC2") == 0) {
|
|
n = std::snprintf(out, (size_t)cap, "%-8s %s, $%s", m, rn(d.rt),
|
|
kCop2Data[cop]);
|
|
} else if (std::strcmp(m, "CFC2") == 0 || std::strcmp(m, "CTC2") == 0) {
|
|
n = std::snprintf(out, (size_t)cap, "%-8s %s, $%s", m, rn(d.rt),
|
|
kCop2Ctrl[cop]);
|
|
} else if (d.rs & 0x10) { /* GTE command word */
|
|
n = std::snprintf(out, (size_t)cap, "%-8s 0x%07X", gte_cmd_name(d.raw),
|
|
d.raw & 0x1FFFFFFu);
|
|
} else {
|
|
n = std::snprintf(out, (size_t)cap, ".word 0x%08X", word);
|
|
}
|
|
} else if (d.format == InstrFormat::J) {
|
|
n = std::snprintf(out, (size_t)cap, "%-8s 0x%08X", m, d.jump_target);
|
|
} else if (d.is_branch && d.opcode != 0x04 && d.opcode != 0x05) {
|
|
n = std::snprintf(out, (size_t)cap, "%-8s %s, 0x%08X", m, rn(d.rs), d.branch_target);
|
|
} else if (d.is_branch) {
|
|
n = std::snprintf(out, (size_t)cap, "%-8s %s, %s, 0x%08X", m, rn(d.rs),
|
|
rn(d.rt), d.branch_target);
|
|
} else if (d.opcode == 0x0F) { /* LUI */
|
|
n = std::snprintf(out, (size_t)cap, "%-8s %s, 0x%04X", m, rn(d.rt),
|
|
(unsigned)d.uimm16);
|
|
} else if (d.is_load || d.is_store) {
|
|
const char* reg = (d.opcode == 0x32 || d.opcode == 0x3A) ? kCop2Data[d.rt & 31] : rn(d.rt);
|
|
const char* prefix = (d.opcode == 0x32 || d.opcode == 0x3A) ? "$" : "";
|
|
n = std::snprintf(out, (size_t)cap, "%-8s %s%s, %d(%s)", m, prefix, reg,
|
|
(int)d.imm16, rn(d.rs));
|
|
} else if (d.format == InstrFormat::R || d.format == InstrFormat::SPECIAL) {
|
|
n = std::snprintf(out, (size_t)cap, "%-8s %s, %s, %s", m, rn(d.rd), rn(d.rs),
|
|
rn(d.rt));
|
|
} else if (d.opcode >= 0x0C && d.opcode <= 0x0E) {
|
|
n = std::snprintf(out, (size_t)cap, "%-8s %s, %s, 0x%04X", m, rn(d.rt), rn(d.rs), (unsigned)d.uimm16);
|
|
} else {
|
|
n = std::snprintf(out, (size_t)cap, "%-8s %s, %s, %d", m, rn(d.rt), rn(d.rs),
|
|
(int)d.imm16);
|
|
}
|
|
if (n < 0) { out[0] = '\0'; return 0; }
|
|
return (n < cap) ? n : (cap - 1);
|
|
}
|