rpcs3/rpcs3/Emu/Cell/SPUDisAsm.h
2023-02-15 08:58:02 +01:00

1070 lines
29 KiB
C++

#pragma once
#include "PPCDisAsm.h"
#include "SPUOpcodes.h"
#include "util/v128.hpp"
enum spu_stop_syscall : u32;
static constexpr const char* spu_reg_name[128] =
{
"lr", "sp", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
"r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
"r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",
"r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47",
"r48", "r49", "r50", "r51", "r52", "r53", "r54", "r55",
"r56", "r57", "r58", "r59", "r60", "r61", "r62", "r63",
"r64", "r65", "r66", "r67", "r68", "r69", "r70", "r71",
"r72", "r73", "r74", "r75", "r76", "r77", "r78", "r79",
"r80", "r81", "r82", "r83", "r84", "r85", "r86", "r87",
"r88", "r89", "r90", "r91", "r92", "r93", "r94", "r95",
"r96", "r97", "r98", "r99", "r100", "r101", "r102", "r103",
"r104", "r105", "r106", "r107", "r108", "r109", "r110", "r111",
"r112", "r113", "r114", "r115", "r116", "r117", "r118", "r119",
"r120", "r121", "r122", "r123", "r124", "r125", "r126", "r127",
};
static constexpr const char* spu_spreg_name[128] =
{
"spr0", "spr1", "spr2", "spr3", "spr4", "spr5", "spr6", "spr7",
"spr8", "spr9", "spr10", "spr11", "spr12", "spr13", "spr14", "spr15",
"spr16", "spr17", "spr18", "spr19", "spr20", "spr21", "spr22", "spr23",
"spr24", "spr25", "spr26", "spr27", "spr28", "spr29", "spr30", "spr31",
"spr32", "spr33", "spr34", "spr35", "spr36", "spr37", "spr38", "spr39",
"spr40", "spr41", "spr42", "spr43", "spr44", "spr45", "spr46", "spr47",
"spr48", "spr49", "spr50", "spr51", "spr52", "spr53", "spr54", "spr55",
"spr56", "spr57", "spr58", "spr59", "spr60", "spr61", "spr62", "spr63",
"spr64", "spr65", "spr66", "spr67", "spr68", "spr69", "spr70", "spr71",
"spr72", "spr73", "spr74", "spr75", "spr76", "spr77", "spr78", "spr79",
"spr80", "spr81", "spr82", "spr83", "spr84", "spr85", "spr86", "spr87",
"spr88", "spr89", "spr90", "spr91", "spr92", "spr93", "spr94", "spr95",
"spr96", "spr97", "spr98", "spr99", "spr100", "spr101", "spr102", "spr103",
"spr104", "spr105", "spr106", "spr107", "spr108", "spr109", "spr110", "spr111",
"spr112", "spr113", "spr114", "spr115", "spr116", "spr117", "spr118", "spr119",
"spr120", "spr121", "spr122", "spr123", "spr124", "spr125", "spr126", "spr127",
};
static constexpr const char* spu_ch_name[128] =
{
"SPU_RdEventStat", "SPU_WrEventMask", "SPU_WrEventAck", "SPU_RdSigNotify1",
"SPU_RdSigNotify2", "ch5", "ch6", "SPU_WrDec", "SPU_RdDec",
"MFC_WrMSSyncReq", "ch10", "SPU_RdEventMask", "MFC_RdTagMask", "SPU_RdMachStat",
"SPU_WrSRR0", "SPU_RdSRR0", "MFC_LSA", "MFC_EAH", "MFC_EAL", "MFC_Size",
"MFC_TagID", "MFC_Cmd", "MFC_WrTagMask", "MFC_WrTagUpdate", "MFC_RdTagStat",
"MFC_RdListStallStat", "MFC_WrListStallAck", "MFC_RdAtomicStat",
"SPU_WrOutMbox", "SPU_RdInMbox", "SPU_WrOutIntrMbox", "ch31", "ch32",
"ch33", "ch34", "ch35", "ch36", "ch37", "ch38", "ch39", "ch40",
"ch41", "ch42", "ch43", "ch44", "ch45", "ch46", "ch47", "ch48",
"ch49", "ch50", "ch51", "ch52", "ch53", "ch54", "ch55", "ch56",
"ch57", "ch58", "ch59", "ch60", "ch61", "ch62", "ch63", "ch64",
"ch65", "ch66", "ch67", "ch68", "SPU_Set_Bkmk_Tag", "SPU_PM_Start_Ev", "SPU_PM_Stop_Ev", "ch72",
"ch73", "ch74", "ch75", "ch76", "ch77", "ch78", "ch79", "ch80",
"ch81", "ch82", "ch83", "ch84", "ch85", "ch86", "ch87", "ch88",
"ch89", "ch90", "ch91", "ch92", "ch93", "ch94", "ch95", "ch96",
"ch97", "ch98", "ch99", "ch100", "ch101", "ch102", "ch103", "ch104",
"ch105", "ch106", "ch107", "ch108", "ch109", "ch110", "ch111", "ch112",
"ch113", "ch114", "ch115", "ch116", "ch117", "ch118", "ch119", "ch120",
"ch121", "ch122", "ch123", "ch124", "ch125", "ch126", "ch127",
};
namespace utils
{
class shm;
}
void comment_constant(std::string& last_opocde, u64 value, bool print_float = true);
class SPUDisAsm final : public PPCDisAsm
{
std::shared_ptr<utils::shm> m_shm;
public:
SPUDisAsm(cpu_disasm_mode mode, const u8* offset, u32 start_pc = 0) : PPCDisAsm(mode, offset, start_pc)
{
}
~SPUDisAsm() = default;
void set_shm(std::shared_ptr<utils::shm> shm)
{
m_shm = std::move(shm);
}
private:
virtual u32 DisAsmBranchTarget(const s32 imm) override
{
return spu_branch_target(dump_pc, imm);
}
static char BrIndirectSuffix(u32 de)
{
switch (de)
{
case 0b01: return 'e';
case 0b10: return 'd';
case 0b11: return '!';
default: return '\0';
}
}
void DisAsm(const char* op)
{
last_opcode += op;
}
void DisAsm(std::string_view op, u32 a1)
{
fmt::append(last_opcode, "%-*s 0x%x", PadOp(), op, a1);
}
void DisAsm(std::string_view op, const char* a1)
{
fmt::append(last_opcode, "%-*s %s", PadOp(), op, a1);
}
void DisAsm(std::string_view op, const char* a1, const char* a2)
{
fmt::append(last_opcode, "%-*s %s,%s", PadOp(), op, a1, a2);
}
void DisAsm(std::string_view op, int a1, const char* a2)
{
fmt::append(last_opcode, "%-*s 0x%x,%s", PadOp(), op, a1, a2);
}
void DisAsm(std::string_view op, const char* a1, int a2)
{
fmt::append(last_opcode, "%-*s %s,%s", PadOp(), op, a1, SignedHex(a2));
}
void DisAsm(std::string_view op, int a1, int a2)
{
fmt::append(last_opcode, "%-*s 0x%x,0x%x", PadOp(), op, a1, a2);
}
void DisAsm(std::string_view op, const char* a1, const char* a2, const char* a3)
{
fmt::append(last_opcode, "%-*s %s,%s,%s", PadOp(), op, a1, a2, a3);
}
void DisAsm(std::string_view op, const char* a1, int a2, const char* a3)
{
fmt::append(last_opcode, "%-*s %s,%s(%s)", PadOp(), op, a1, SignedHex(a2), a3);
}
void DisAsm(std::string_view op, const char* a1, const char* a2, int a3)
{
fmt::append(last_opcode, "%-*s %s,%s,%s", PadOp(), op, a1, a2, SignedHex(a3));
}
void DisAsm(std::string_view op, const char* a1, const char* a2, const char* a3, const char* a4)
{
fmt::append(last_opcode, "%-*s %s,%s,%s,%s", PadOp(), op, a1, a2, a3, a4);
}
using field_de_t = decltype(spu_opcode_t::de);
void DisAsm(std::string_view op, field_de_t de, const char* a1)
{
const char c = BrIndirectSuffix(de);
if (c == '!')
{
// Invalid
fmt::append(last_opcode, "?? ?? (%s)", op);
return;
}
fmt::append(last_opcode, "%-*s %s", PadOp(op, c ? 1 : 0), op, a1);
insert_char_if(op, !!c, c);
}
void DisAsm(std::string_view op, field_de_t de, const char* a1, const char* a2)
{
const char c = BrIndirectSuffix(de);
if (c == '!')
{
fmt::append(last_opcode, "?? ?? (%s)", op);
return;
}
fmt::append(last_opcode, "%-*s %s,%s", PadOp(op, c ? 1 : 0), op, a1, a2);
insert_char_if(op, !!c, c);
}
public:
u32 disasm(u32 pc) override;
std::pair<const void*, usz> get_memory_span() const override;
std::unique_ptr<CPUDisAsm> copy_type_erased() const override;
std::pair<bool, v128> try_get_const_value(u32 reg, u32 pc = -1, u32 TTL = 10) const;
// Get constant value if the original array is made of only repetitions of the same value
template <typename T> requires (sizeof(T) < sizeof(v128) && !(sizeof(v128) % sizeof(T)))
std::pair<bool, T> try_get_const_equal_value_array(u32 reg, u32 pc = -1, u32 TTL = 10) const
{
auto [ok, res] = try_get_const_value(reg, pc, TTL);
if (!ok)
{
return {};
}
v128 test_value{};
T sample{};
std::memcpy(&sample, res._bytes, sizeof(T));
for (u32 i = 0; i < sizeof(v128); i += sizeof(T))
{
std::memcpy(test_value._bytes + i, &sample, sizeof(T));
}
if (test_value != res)
{
return {};
}
return {ok, sample};
}
struct insert_mask_info
{
u32 type_size;
u32 dst_index;
u32 src_index;
};
static insert_mask_info try_get_insert_mask_info(const v128& mask);
//0 - 10
void STOP(spu_opcode_t op)
{
op.rb ? UNK(op) : DisAsm("stop", fmt::format("0x%x #%s", op.opcode & 0x3fff, spu_stop_syscall{op.opcode & 0x3fff}).c_str());
}
void LNOP(spu_opcode_t /*op*/)
{
DisAsm("lnop");
}
void SYNC(spu_opcode_t op)
{
DisAsm(op.c ? "syncc" : "sync");
}
void DSYNC(spu_opcode_t /*op*/)
{
DisAsm("dsync");
}
void MFSPR(spu_opcode_t op)
{
DisAsm("mfspr", spu_reg_name[op.rt], spu_spreg_name[op.ra]);
}
void RDCH(spu_opcode_t op)
{
DisAsm("rdch", spu_reg_name[op.rt], spu_ch_name[op.ra]);
}
void RCHCNT(spu_opcode_t op)
{
DisAsm("rchcnt", spu_reg_name[op.rt], spu_ch_name[op.ra]);
}
void SF(spu_opcode_t op)
{
DisAsm("sf", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void OR(spu_opcode_t op)
{
DisAsm("or", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void BG(spu_opcode_t op)
{
DisAsm("bg", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void SFH(spu_opcode_t op)
{
DisAsm("sfh", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void NOR(spu_opcode_t op)
{
DisAsm("nor", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void ABSDB(spu_opcode_t op)
{
DisAsm("absdb", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void ROT(spu_opcode_t op)
{
DisAsm("rot", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void ROTM(spu_opcode_t op)
{
DisAsm("rotm", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void ROTMA(spu_opcode_t op)
{
DisAsm("rotma", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void SHL(spu_opcode_t op)
{
DisAsm("shl", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void ROTH(spu_opcode_t op)
{
DisAsm("roth", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void ROTHM(spu_opcode_t op)
{
DisAsm("rothm", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void ROTMAH(spu_opcode_t op)
{
DisAsm("rotmah", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void SHLH(spu_opcode_t op)
{
DisAsm("shlh", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void ROTI(spu_opcode_t op)
{
DisAsm("roti", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si7);
}
void ROTMI(spu_opcode_t op)
{
DisAsm("rotmi", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si7);
}
void ROTMAI(spu_opcode_t op)
{
DisAsm("rotmai", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si7);
}
void SHLI(spu_opcode_t op)
{
DisAsm("shli", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si7);
}
void ROTHI(spu_opcode_t op)
{
DisAsm("rothi", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si7);
}
void ROTHMI(spu_opcode_t op)
{
DisAsm("rothmi", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si7);
}
void ROTMAHI(spu_opcode_t op)
{
DisAsm("rotmahi", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si7);
}
void SHLHI(spu_opcode_t op)
{
DisAsm("shlhi", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si7);
}
void A(spu_opcode_t op)
{
DisAsm("a", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void AND(spu_opcode_t op)
{
DisAsm("and", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void CG(spu_opcode_t op)
{
DisAsm("cg", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void AH(spu_opcode_t op)
{
DisAsm("ah", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void NAND(spu_opcode_t op)
{
DisAsm("nand", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void AVGB(spu_opcode_t op)
{
DisAsm("avgb", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void MTSPR(spu_opcode_t op)
{
DisAsm("mtspr", spu_spreg_name[op.ra], spu_reg_name[op.rt]);
}
void WRCH(spu_opcode_t op);
void BIZ(spu_opcode_t op)
{
DisAsm("biz", op.de, spu_reg_name[op.rt], spu_reg_name[op.ra]);
}
void BINZ(spu_opcode_t op)
{
DisAsm("binz", op.de, spu_reg_name[op.rt], spu_reg_name[op.ra]);
}
void BIHZ(spu_opcode_t op)
{
DisAsm("bihz", op.de, spu_reg_name[op.rt], spu_reg_name[op.ra]);
}
void BIHNZ(spu_opcode_t op)
{
DisAsm("bihnz", op.de, spu_reg_name[op.rt], spu_reg_name[op.ra]);
}
void STOPD(spu_opcode_t op)
{
DisAsm("stopd", spu_reg_name[op.rc], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void STQX(spu_opcode_t op)
{
DisAsm("stqx", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void BI(spu_opcode_t op)
{
DisAsm("bi", op.de, spu_reg_name[op.ra]);
}
void BISL(spu_opcode_t op)
{
DisAsm("bisl", op.de, spu_reg_name[op.rt], spu_reg_name[op.ra]);
}
void IRET(spu_opcode_t op)
{
DisAsm("iret", op.de, spu_reg_name[op.ra]);
}
void BISLED(spu_opcode_t op)
{
DisAsm("bisled", op.de, spu_reg_name[op.rt], spu_reg_name[op.ra]);
}
void HBR(spu_opcode_t op)
{
DisAsm(op.c ? "hbrp" : "hbr", DisAsmBranchTarget((op.roh << 7) | op.rt), spu_reg_name[op.ra]);
}
void GB(spu_opcode_t op)
{
DisAsm("gb", spu_reg_name[op.rt], spu_reg_name[op.ra]);
}
void GBH(spu_opcode_t op)
{
DisAsm("gbh", spu_reg_name[op.rt], spu_reg_name[op.ra]);
}
void GBB(spu_opcode_t op)
{
DisAsm("gbb", spu_reg_name[op.rt], spu_reg_name[op.ra]);
}
void FSM(spu_opcode_t op)
{
DisAsm("fsm", spu_reg_name[op.rt], spu_reg_name[op.ra]);
}
void FSMH(spu_opcode_t op)
{
DisAsm("fsmh", spu_reg_name[op.rt], spu_reg_name[op.ra]);
}
void FSMB(spu_opcode_t op)
{
DisAsm("fsmb", spu_reg_name[op.rt], spu_reg_name[op.ra]);
}
void FREST(spu_opcode_t op)
{
DisAsm("frest", spu_reg_name[op.rt], spu_reg_name[op.ra]);
}
void FRSQEST(spu_opcode_t op)
{
DisAsm("frsqest", spu_reg_name[op.rt], spu_reg_name[op.ra]);
}
void LQX(spu_opcode_t op)
{
DisAsm("lqx", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void ROTQBYBI(spu_opcode_t op)
{
DisAsm("rotqbybi", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void ROTQMBYBI(spu_opcode_t op)
{
DisAsm("rotqmbybi", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void SHLQBYBI(spu_opcode_t op)
{
DisAsm("shlqbybi", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void CBX(spu_opcode_t op)
{
DisAsm("cbx", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void CHX(spu_opcode_t op)
{
DisAsm("chx", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void CWX(spu_opcode_t op)
{
DisAsm("cwx", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void CDX(spu_opcode_t op)
{
DisAsm("cdx", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void ROTQBI(spu_opcode_t op)
{
DisAsm("rotqbi", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void ROTQMBI(spu_opcode_t op)
{
DisAsm("rotqmbi", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void SHLQBI(spu_opcode_t op)
{
DisAsm("shlqbi", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void ROTQBY(spu_opcode_t op)
{
DisAsm("rotqby", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void ROTQMBY(spu_opcode_t op)
{
DisAsm("rotqmby", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void SHLQBY(spu_opcode_t op)
{
DisAsm("shlqby", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void ORX(spu_opcode_t op)
{
DisAsm("orx", spu_reg_name[op.rt], spu_reg_name[op.ra]);
}
void CBD(spu_opcode_t op)
{
DisAsm("cbd", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si7);
}
void CHD(spu_opcode_t op)
{
DisAsm("chd", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si7);
}
void CWD(spu_opcode_t op)
{
DisAsm("cwd", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si7);
}
void CDD(spu_opcode_t op)
{
DisAsm("cdd", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si7);
}
void ROTQBII(spu_opcode_t op)
{
DisAsm("rotqbii", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si7);
}
void ROTQMBII(spu_opcode_t op)
{
DisAsm("rotqmbii", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si7);
}
void SHLQBII(spu_opcode_t op)
{
DisAsm("shlqbii", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si7);
}
void ROTQBYI(spu_opcode_t op)
{
DisAsm("rotqbyi", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si7);
}
void ROTQMBYI(spu_opcode_t op)
{
DisAsm("rotqmbyi", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si7);
}
void SHLQBYI(spu_opcode_t op)
{
if (!op.si7)
{
// Made-up mnemonic: as MR on PPU
DisAsm("mr", spu_reg_name[op.rt], spu_reg_name[op.ra]);
return;
}
DisAsm("shlqbyi", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si7);
}
void NOP(spu_opcode_t op)
{
DisAsm("nop", spu_reg_name[op.rt]);
}
void CGT(spu_opcode_t op)
{
DisAsm("cgt", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void XOR(spu_opcode_t op)
{
DisAsm("xor", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void CGTH(spu_opcode_t op)
{
DisAsm("cgth", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void EQV(spu_opcode_t op)
{
DisAsm("eqv", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void CGTB(spu_opcode_t op)
{
DisAsm("cgtb", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void SUMB(spu_opcode_t op)
{
DisAsm("sumb", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void HGT(spu_opcode_t op)
{
DisAsm("hgt", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void CLZ(spu_opcode_t op)
{
DisAsm("clz", spu_reg_name[op.rt], spu_reg_name[op.ra]);
}
void XSWD(spu_opcode_t op)
{
DisAsm("xswd", spu_reg_name[op.rt], spu_reg_name[op.ra]);
}
void XSHW(spu_opcode_t op)
{
DisAsm("xshw", spu_reg_name[op.rt], spu_reg_name[op.ra]);
}
void CNTB(spu_opcode_t op)
{
DisAsm("cntb", spu_reg_name[op.rt], spu_reg_name[op.ra]);
}
void XSBH(spu_opcode_t op)
{
DisAsm("xsbh", spu_reg_name[op.rt], spu_reg_name[op.ra]);
}
void CLGT(spu_opcode_t op)
{
DisAsm("clgt", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void ANDC(spu_opcode_t op)
{
DisAsm("andc", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void FCGT(spu_opcode_t op)
{
DisAsm("fcgt", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void DFCGT(spu_opcode_t op)
{
DisAsm("dfcgt", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void FA(spu_opcode_t op)
{
DisAsm("fa", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void FS(spu_opcode_t op)
{
DisAsm("fs", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void FM(spu_opcode_t op)
{
DisAsm("fm", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void CLGTH(spu_opcode_t op)
{
DisAsm("clgth", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void ORC(spu_opcode_t op)
{
DisAsm("orc", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void FCMGT(spu_opcode_t op)
{
DisAsm("fcmgt", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void DFCMGT(spu_opcode_t op)
{
DisAsm("dfcmgt", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void DFA(spu_opcode_t op)
{
DisAsm("dfa", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void DFS(spu_opcode_t op)
{
DisAsm("dfs", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void DFM(spu_opcode_t op)
{
DisAsm("dfm", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void CLGTB(spu_opcode_t op)
{
DisAsm("clgtb", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void HLGT(spu_opcode_t op)
{
DisAsm("hlgt", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void DFMA(spu_opcode_t op)
{
DisAsm("dfma", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void DFMS(spu_opcode_t op)
{
DisAsm("dfms", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void DFNMS(spu_opcode_t op)
{
DisAsm("dfnms", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void DFNMA(spu_opcode_t op)
{
DisAsm("dfnma", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void CEQ(spu_opcode_t op)
{
DisAsm("ceq", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void MPYHHU(spu_opcode_t op)
{
DisAsm("mpyhhu", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void ADDX(spu_opcode_t op)
{
DisAsm("addx", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void SFX(spu_opcode_t op)
{
DisAsm("sfx", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void CGX(spu_opcode_t op)
{
DisAsm("cgx", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void BGX(spu_opcode_t op)
{
DisAsm("bgx", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void MPYHHA(spu_opcode_t op)
{
DisAsm("mpyhha", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void MPYHHAU(spu_opcode_t op)
{
DisAsm("mpyhhau", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void FSCRRD(spu_opcode_t op)
{
DisAsm("fscrrd", spu_reg_name[op.rt]);
}
void FESD(spu_opcode_t op)
{
DisAsm("fesd", spu_reg_name[op.rt], spu_reg_name[op.ra]);
}
void FRDS(spu_opcode_t op)
{
DisAsm("frds", spu_reg_name[op.rt], spu_reg_name[op.ra]);
}
void FSCRWR(spu_opcode_t op)
{
DisAsm("fscrwr", spu_reg_name[op.rt], spu_reg_name[op.ra]);
}
void DFTSV(spu_opcode_t op)
{
DisAsm("dftsv", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si7);
}
void FCEQ(spu_opcode_t op)
{
DisAsm("fceq", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void DFCEQ(spu_opcode_t op)
{
DisAsm("dfceq", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void MPY(spu_opcode_t op)
{
DisAsm("mpy", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void MPYH(spu_opcode_t op)
{
DisAsm("mpyh", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void MPYHH(spu_opcode_t op)
{
DisAsm("mpyhh", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void MPYS(spu_opcode_t op)
{
DisAsm("mpys", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void CEQH(spu_opcode_t op)
{
DisAsm("ceqh", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void FCMEQ(spu_opcode_t op)
{
DisAsm("fcmeq", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void DFCMEQ(spu_opcode_t op)
{
DisAsm("dfcmeq", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void MPYU(spu_opcode_t op)
{
DisAsm("mpyu", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void CEQB(spu_opcode_t op)
{
DisAsm("ceqb", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void FI(spu_opcode_t op)
{
DisAsm("fi", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
void HEQ(spu_opcode_t op)
{
DisAsm("heq", spu_reg_name[op.rt], spu_reg_name[op.ra], spu_reg_name[op.rb]);
}
//0 - 9
void CFLTS(spu_opcode_t op)
{
DisAsm("cflts", spu_reg_name[op.rt], spu_reg_name[op.ra], op.i8);
}
void CFLTU(spu_opcode_t op)
{
DisAsm("cfltu", spu_reg_name[op.rt], spu_reg_name[op.ra], op.i8);
}
void CSFLT(spu_opcode_t op)
{
DisAsm("csflt", spu_reg_name[op.rt], spu_reg_name[op.ra], op.i8);
}
void CUFLT(spu_opcode_t op)
{
DisAsm("cuflt", spu_reg_name[op.rt], spu_reg_name[op.ra], op.i8);
}
//0 - 8
void BRZ(spu_opcode_t op)
{
DisAsm("brz", spu_reg_name[op.rt], DisAsmBranchTarget(op.i16));
}
void STQA(spu_opcode_t op)
{
DisAsm("stqa", spu_reg_name[op.rt], DisAsmBranchTarget(op.i16 - dump_pc / 4));
}
void BRNZ(spu_opcode_t op)
{
DisAsm("brnz", spu_reg_name[op.rt], DisAsmBranchTarget(op.i16));
}
void BRHZ(spu_opcode_t op)
{
DisAsm("brhz", spu_reg_name[op.rt], DisAsmBranchTarget(op.i16));
}
void BRHNZ(spu_opcode_t op)
{
DisAsm("brhnz", spu_reg_name[op.rt], DisAsmBranchTarget(op.i16));
}
void STQR(spu_opcode_t op)
{
DisAsm("stqr", spu_reg_name[op.rt], DisAsmBranchTarget(op.i16));
}
void BRA(spu_opcode_t op)
{
DisAsm("bra", DisAsmBranchTarget(op.i16 - dump_pc / 4));
}
void LQA(spu_opcode_t op)
{
DisAsm("lqa", spu_reg_name[op.rt], DisAsmBranchTarget(op.i16 - dump_pc / 4));
}
void BRASL(spu_opcode_t op)
{
DisAsm("brasl", spu_reg_name[op.rt], DisAsmBranchTarget(op.i16 - dump_pc / 4));
}
void BR(spu_opcode_t op)
{
DisAsm("br", DisAsmBranchTarget(op.i16));
}
void FSMBI(spu_opcode_t op)
{
DisAsm("fsmbi", spu_reg_name[op.rt], op.i16);
}
void BRSL(spu_opcode_t op)
{
DisAsm("brsl", spu_reg_name[op.rt], DisAsmBranchTarget(op.i16));
}
void LQR(spu_opcode_t op)
{
DisAsm("lqr", spu_reg_name[op.rt], DisAsmBranchTarget(op.i16));
}
void IL(spu_opcode_t op)
{
DisAsm("il", spu_reg_name[op.rt], op.si16);
}
void ILHU(spu_opcode_t op)
{
DisAsm("ilhu", spu_reg_name[op.rt], op.i16);
comment_constant(last_opcode, op.i16 << 16);
}
void ILH(spu_opcode_t op)
{
DisAsm("ilh", spu_reg_name[op.rt], op.i16);
comment_constant(last_opcode, (op.i16 << 16) | op.i16);
}
void IOHL(spu_opcode_t op);
//0 - 7
void ORI(spu_opcode_t op)
{
if (!op.si10)
{
// Made-up mnemonic: as MR on PPU
DisAsm("mr", spu_reg_name[op.rt], spu_reg_name[op.ra]);
return;
}
DisAsm("ori", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si10);
if (auto [is_const, value] = try_get_const_equal_value_array<u32>(+op.ra); is_const)
{
// Comment constant formation
comment_constant(last_opcode, value | static_cast<u32>(op.si10));
}
}
void ORHI(spu_opcode_t op)
{
DisAsm("orhi", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si10);
}
void ORBI(spu_opcode_t op)
{
DisAsm("orbi", spu_reg_name[op.rt], spu_reg_name[op.ra], static_cast<u8>(op.si10));
}
void SFI(spu_opcode_t op)
{
DisAsm("sfi", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si10);
}
void SFHI(spu_opcode_t op)
{
DisAsm("sfhi", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si10);
}
void ANDI(spu_opcode_t op)
{
DisAsm("andi", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si10);
}
void ANDHI(spu_opcode_t op)
{
DisAsm("andhi", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si10);
}
void ANDBI(spu_opcode_t op)
{
DisAsm("andbi", spu_reg_name[op.rt], spu_reg_name[op.ra], static_cast<u8>(op.si10));
}
void AI(spu_opcode_t op)
{
DisAsm("ai", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si10);
if (auto [is_const, value] = try_get_const_equal_value_array<u32>(op.ra); is_const)
{
// Comment constant formation
comment_constant(last_opcode, value + static_cast<u32>(op.si10));
}
}
void AHI(spu_opcode_t op)
{
DisAsm("ahi", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si10);
}
void STQD(spu_opcode_t op)
{
DisAsm("stqd", spu_reg_name[op.rt], op.si10 << 4, spu_reg_name[op.ra]);
}
void LQD(spu_opcode_t op)
{
DisAsm("lqd", spu_reg_name[op.rt], op.si10 << 4, spu_reg_name[op.ra]);
}
void XORI(spu_opcode_t op)
{
DisAsm("xori", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si10);
if (auto [is_const, value] = try_get_const_equal_value_array<u32>(op.ra); is_const)
{
// Comment constant formation
comment_constant(last_opcode, value ^ static_cast<u32>(op.si10));
}
}
void XORHI(spu_opcode_t op)
{
DisAsm("xorhi", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si10);
}
void XORBI(spu_opcode_t op)
{
DisAsm("xorbi", spu_reg_name[op.rt], spu_reg_name[op.ra], static_cast<u8>(op.si10));
}
void CGTI(spu_opcode_t op)
{
DisAsm("cgti", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si10);
}
void CGTHI(spu_opcode_t op)
{
DisAsm("cgthi", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si10);
}
void CGTBI(spu_opcode_t op)
{
DisAsm("cgtbi", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si10);
}
void HGTI(spu_opcode_t op)
{
DisAsm("hgti", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si10);
}
void CLGTI(spu_opcode_t op)
{
DisAsm("clgti", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si10);
}
void CLGTHI(spu_opcode_t op)
{
DisAsm("clgthi", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si10);
}
void CLGTBI(spu_opcode_t op)
{
DisAsm("clgtbi", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si10);
}
void HLGTI(spu_opcode_t op)
{
DisAsm("hlgti", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si10);
}
void MPYI(spu_opcode_t op)
{
DisAsm("mpyi", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si10);
}
void MPYUI(spu_opcode_t op)
{
DisAsm("mpyui", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si10);
}
void CEQI(spu_opcode_t op)
{
DisAsm("ceqi", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si10);
}
void CEQHI(spu_opcode_t op)
{
DisAsm("ceqhi", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si10);
}
void CEQBI(spu_opcode_t op)
{
DisAsm("ceqbi", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si10);
}
void HEQI(spu_opcode_t op)
{
DisAsm("heqi", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si10);
}
//0 - 6
void HBRA(spu_opcode_t op)
{
DisAsm("hbra", DisAsmBranchTarget((op.r0h << 7) | op.rt), DisAsmBranchTarget(op.i16 - dump_pc / 4));
}
void HBRR(spu_opcode_t op)
{
DisAsm("hbrr", DisAsmBranchTarget((op.r0h << 7) | op.rt), DisAsmBranchTarget(op.i16));
}
void ILA(spu_opcode_t op)
{
DisAsm("ila", spu_reg_name[op.rt], op.i18);
}
//0 - 3
void SELB(spu_opcode_t op)
{
DisAsm("selb", spu_reg_name[op.rt4], spu_reg_name[op.ra], spu_reg_name[op.rb], spu_reg_name[op.rc]);
}
void SHUFB(spu_opcode_t op);
void MPYA(spu_opcode_t op)
{
DisAsm("mpya", spu_reg_name[op.rt4], spu_reg_name[op.ra], spu_reg_name[op.rb], spu_reg_name[op.rc]);
}
void FNMS(spu_opcode_t op)
{
DisAsm("fnms", spu_reg_name[op.rt4], spu_reg_name[op.ra], spu_reg_name[op.rb], spu_reg_name[op.rc]);
}
void FMA(spu_opcode_t op)
{
DisAsm("fma", spu_reg_name[op.rt4], spu_reg_name[op.ra], spu_reg_name[op.rb], spu_reg_name[op.rc]);
}
void FMS(spu_opcode_t op)
{
DisAsm("fms", spu_reg_name[op.rt4], spu_reg_name[op.ra], spu_reg_name[op.rb], spu_reg_name[op.rc]);
}
void UNK(spu_opcode_t /*op*/)
{
DisAsm("?? ??");
}
};