mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-20 21:27:52 -04:00
542 lines
22 KiB
C++
542 lines
22 KiB
C++
/*!
|
|
* @file OpcodeInfo.cpp
|
|
* Decoding info for each opcode.
|
|
*/
|
|
|
|
#include "OpcodeInfo.h"
|
|
#include "common/util/Assert.h"
|
|
|
|
namespace decompiler {
|
|
OpcodeInfo gOpcodeInfo[(uint32_t)InstructionKind::EE_OP_MAX];
|
|
|
|
namespace {
|
|
bool opcodes_initialized = false;
|
|
}
|
|
|
|
typedef InstructionKind IK;
|
|
typedef FieldType FT;
|
|
typedef DecodeType DT;
|
|
|
|
static OpcodeInfo& def(IK k, const char* name) {
|
|
gOpcodeInfo[(uint32_t)k].defined = true;
|
|
gOpcodeInfo[(uint32_t)k].name = name;
|
|
return gOpcodeInfo[(uint32_t)k];
|
|
}
|
|
|
|
static OpcodeInfo& def_branch(IK k, const char* name) {
|
|
auto& result = def(k, name);
|
|
result.is_branch = true;
|
|
result.has_delay_slot = true;
|
|
return result;
|
|
}
|
|
|
|
static OpcodeInfo& def_branch_likely(IK k, const char* name) {
|
|
auto& result = def(k, name);
|
|
result.is_branch = true;
|
|
result.is_branch_likely = true;
|
|
result.has_delay_slot = true;
|
|
return result;
|
|
}
|
|
|
|
static OpcodeInfo& def_store(IK k, const char* name) {
|
|
auto& result = def(k, name);
|
|
result.is_store = true;
|
|
return result;
|
|
}
|
|
|
|
static OpcodeInfo& def_load(IK k, const char* name) {
|
|
auto& result = def(k, name);
|
|
result.is_load = true;
|
|
return result;
|
|
}
|
|
|
|
static OpcodeInfo& drt_srs_ssimm16(OpcodeInfo& info) {
|
|
return info.dst_gpr(FT::RT).src_gpr(FT::RS).src(FT::SIMM16, DT::IMM);
|
|
}
|
|
|
|
static OpcodeInfo& srt_ssimm16_srs(OpcodeInfo& info) {
|
|
return info.src_gpr(FT::RT).src(FT::SIMM16, DT::IMM).src_gpr(FT::RS);
|
|
}
|
|
|
|
static OpcodeInfo& drt_ssimm16_srs(OpcodeInfo& info) {
|
|
return info.dst_gpr(FT::RT).src(FT::SIMM16, DT::IMM).src_gpr(FT::RS);
|
|
}
|
|
|
|
static OpcodeInfo& drd_srs_srt(OpcodeInfo& info) {
|
|
return info.dst_gpr(FT::RD).src_gpr(FT::RS).src_gpr(FT::RT);
|
|
}
|
|
|
|
static OpcodeInfo& drd_srt_srs(OpcodeInfo& info) {
|
|
return info.dst_gpr(FT::RD).src_gpr(FT::RT).src_gpr(FT::RS);
|
|
}
|
|
|
|
static OpcodeInfo& drd_srt_ssa(OpcodeInfo& info) {
|
|
return info.dst_gpr(FT::RD).src_gpr(FT::RT).src(FT::SA, DT::IMM);
|
|
}
|
|
|
|
static OpcodeInfo& srs_srt_bt(OpcodeInfo& info) {
|
|
return info.src_gpr(FT::RS).src_gpr(FT::RT).src(FT::SIMM16, DT::BRANCH_TARGET);
|
|
}
|
|
|
|
static OpcodeInfo& srs_bt(OpcodeInfo& info) {
|
|
return info.src_gpr(FT::RS).src(FT::SIMM16, DT::BRANCH_TARGET);
|
|
}
|
|
|
|
static OpcodeInfo& bt(OpcodeInfo& info) {
|
|
return info.src(FT::SIMM16, DT::BRANCH_TARGET);
|
|
}
|
|
|
|
static OpcodeInfo& dfd_sfs_sft(OpcodeInfo& info) {
|
|
return info.dst_fpr(FT::FD).src_fpr(FT::FS).src_fpr(FT::FT);
|
|
}
|
|
|
|
static OpcodeInfo& sfs_sft(OpcodeInfo& info) {
|
|
return info.src_fpr(FT::FS).src_fpr(FT::FT);
|
|
}
|
|
|
|
static OpcodeInfo& dfd_sfs(OpcodeInfo& info) {
|
|
return info.dst_fpr(FT::FD).src_fpr(FT::FS);
|
|
}
|
|
|
|
static OpcodeInfo& dfd_sft(OpcodeInfo& info) {
|
|
return info.dst_fpr(FT::FD).src_fpr(FT::FT);
|
|
}
|
|
|
|
static OpcodeInfo& drd(OpcodeInfo& info) {
|
|
return info.dst_gpr(FT::RD);
|
|
}
|
|
|
|
static OpcodeInfo& cd_dvft_svfs(OpcodeInfo& info) {
|
|
return info.src(FT::DEST, DT::DEST).dst_vf(FT::FT).src_vf(FT::FS);
|
|
}
|
|
|
|
static OpcodeInfo& cd_dvfd_svfs_svft(OpcodeInfo& info) {
|
|
return info.src(FT::DEST, DT::DEST).dst_vf(FT::FD).src_vf(FT::FS).src_vf(FT::FT);
|
|
}
|
|
|
|
static OpcodeInfo& cb_cd_dvfd_svfs_svft(OpcodeInfo& info) {
|
|
return info.src(FT::BC, DT::BC)
|
|
.src(FT::DEST, DT::DEST)
|
|
.dst_vf(FT::FD)
|
|
.src_vf(FT::FS)
|
|
.src_vf(FT::FT);
|
|
}
|
|
|
|
static OpcodeInfo& cb_cd_dacc_svfs_svft(OpcodeInfo& info) {
|
|
return info.src(FT::BC, DT::BC)
|
|
.src(FT::DEST, DT::DEST)
|
|
.dst(FT::ZERO, DT::VU_ACC)
|
|
.src_vf(FT::FS)
|
|
.src_vf(FT::FT);
|
|
}
|
|
|
|
static OpcodeInfo& cd_dvfd_svfs_sq(OpcodeInfo& info) {
|
|
return info.src(FT::DEST, DT::DEST).dst_vf(FT::FD).src_vf(FT::FS).src(FT::ZERO, DT::VU_Q);
|
|
}
|
|
|
|
static OpcodeInfo& cd_dacc_svfs_svft(OpcodeInfo& info) {
|
|
return info.src(FT::DEST, DT::DEST).dst(FT::ZERO, DT::VU_ACC).src_vf(FT::FS).src_vf(FT::FT);
|
|
}
|
|
|
|
void init_opcode_info() {
|
|
if (opcodes_initialized) {
|
|
return;
|
|
}
|
|
gOpcodeInfo[0].name = ";; ??????";
|
|
|
|
// RT, RS, SIMM
|
|
drt_srs_ssimm16(def(IK::DADDIU, "daddiu")); // Doubleword Add Immediate Unsigned
|
|
drt_srs_ssimm16(def(IK::ADDIU, "addiu")); // Add Immediate Unsigned Word
|
|
drt_srs_ssimm16(def(IK::SLTI, "slti")); // Set on Less Than Immediate
|
|
drt_srs_ssimm16(def(IK::SLTIU, "sltiu")); // Set on Less Than Immediate Unsigned
|
|
|
|
// stores in srt_ssimm16_srs
|
|
srt_ssimm16_srs(def_store(IK::SB, "sb")); // Store Byte
|
|
srt_ssimm16_srs(def_store(IK::SH, "sh")); // Store Halfword
|
|
srt_ssimm16_srs(def_store(IK::SW, "sw")); // Store Word
|
|
srt_ssimm16_srs(def_store(IK::SD, "sd")); // Store Doubleword
|
|
srt_ssimm16_srs(def_store(IK::SQ, "sq")); // Store Quadword
|
|
|
|
// loads in dsrt_ssimm16_srs
|
|
drt_ssimm16_srs(def_load(IK::LB, "lb")); // Load Byte
|
|
drt_ssimm16_srs(def_load(IK::LBU, "lbu")); // Load Byte Unsigned
|
|
drt_ssimm16_srs(def_load(IK::LH, "lh")); // Load Halfword
|
|
drt_ssimm16_srs(def_load(IK::LHU, "lhu")); // Load Halfword Unsigned
|
|
drt_ssimm16_srs(def_load(IK::LW, "lw")); // Load Word
|
|
drt_ssimm16_srs(def_load(IK::LWU, "lwu")); // Load Word Unsigned
|
|
drt_ssimm16_srs(def_load(IK::LD, "ld")); // Load Doubleword
|
|
drt_ssimm16_srs(def_load(IK::LQ, "lq")); // Load Quadword
|
|
drt_ssimm16_srs(def_load(IK::LDR, "ldr")); // Load Doubleword Left
|
|
drt_ssimm16_srs(def_load(IK::LDL, "ldl")); // Load Doubleword Right
|
|
drt_ssimm16_srs(def_load(IK::LWL, "lwl")); // Load Word Left
|
|
drt_ssimm16_srs(def_load(IK::LWR, "lwr")); // Load Word Right
|
|
|
|
// drd_srs_srt
|
|
drd_srs_srt(def(IK::DADDU, "daddu")); // Doubleword Add Unsigned
|
|
drd_srs_srt(def(IK::SUBU, "subu")); // Subtract Unsigned Word
|
|
drd_srs_srt(def(IK::ADDU, "addu")); // Add Unsigned Word
|
|
drd_srs_srt(def(IK::DSUBU, "dsubu")); // Doubleword Subtract Unsigned
|
|
drd_srs_srt(def(IK::MULT3, "mult3")); // Multiply Word
|
|
drd_srs_srt(def(IK::MULTU3, "multu3")); // Multiply Unsigned Word
|
|
drd_srs_srt(def(IK::AND, "and")); // And
|
|
drd_srs_srt(def(IK::OR, "or")); // Or
|
|
drd_srs_srt(def(IK::NOR, "nor")); // Not Or
|
|
drd_srs_srt(def(IK::XOR, "xor")); // Exclusive Or
|
|
drd_srs_srt(def(IK::MOVN, "movn")); // Move Conditional on Not Zero
|
|
drd_srs_srt(def(IK::MOVZ, "movz")); // Move Conditional on Zero
|
|
drd_srs_srt(def(IK::SLT, "slt")); // Set on Less Than
|
|
drd_srs_srt(def(IK::SLTU, "sltu")); // Set on Less Than Unsigned
|
|
|
|
// fixed shifts
|
|
drd_srt_ssa(def(IK::SLL, "sll")); // Shift Left Logical
|
|
drd_srt_ssa(def(IK::SRA, "sra")); // Shift Right Arithmetic
|
|
drd_srt_ssa(def(IK::SRL, "srl")); // Shift Right Logical
|
|
drd_srt_ssa(def(IK::DSLL, "dsll")); // Doubleword Shift Left Logical
|
|
drd_srt_ssa(def(IK::DSLL32, "dsll32")); // Doubleword Shift Left Logical Plus 32
|
|
drd_srt_ssa(def(IK::DSRA, "dsra")); // Doubleword Shift Right Arithmetic
|
|
drd_srt_ssa(def(IK::DSRA32, "dsra32")); // Doubleword Shift Right Arithmetic Plus 32
|
|
drd_srt_ssa(def(IK::DSRL, "dsrl")); // Doubleword Shift Right Logical
|
|
drd_srt_ssa(def(IK::DSRL32, "dsrl32")); // Doubleword Shift Right Logical Plus 32
|
|
|
|
// variable shifts
|
|
drd_srt_srs(def(IK::DSRAV, "dsrav")); // Doubleword Shift Right Arithmetic Variable
|
|
drd_srt_srs(def(IK::SLLV, "sllv")); // Shift Word Left Logical Variable
|
|
drd_srt_srs(def(IK::DSLLV, "dsllv")); // Doubleword Shift Left Logical Variable
|
|
drd_srt_srs(def(IK::DSRLV, "dsrlv")); // Doubleword Shift Right Logical Variable
|
|
|
|
// branch (two registers)
|
|
srs_srt_bt(def_branch(IK::BEQ, "beq")); // Branch on Equal
|
|
srs_srt_bt(def_branch(IK::BNE, "bne")); // Branch on Not Equal
|
|
srs_srt_bt(def_branch_likely(IK::BEQL, "beql")); // Branch on Equal Likely
|
|
srs_srt_bt(def_branch_likely(IK::BNEL, "bnel")); // Branch on Not Equal Likely
|
|
|
|
// branch (one register)
|
|
srs_bt(def_branch(IK::BLTZ, "bltz")); // Branch on Less Than Zero
|
|
srs_bt(def_branch(IK::BGEZ, "bgez")); // Branch on Greater Than or Equal to Zero
|
|
srs_bt(def_branch(IK::BLEZ, "blez")); // Branch on Less Than or Equal to Zero
|
|
srs_bt(def_branch(IK::BGTZ, "bgtz")); // Branch on Greater Than Zero
|
|
srs_bt(def_branch(IK::BGEZAL, "bgezal")); // Branch on Greater Than or Equal to Zero and Link
|
|
srs_bt(def_branch_likely(IK::BLTZL, "bltzl")); // Branch on Less Than Zero Likely
|
|
srs_bt(def_branch_likely(IK::BGTZL, "bgtzl")); // Branch on Greater Than Zero Likely
|
|
srs_bt(def_branch_likely(IK::BGEZL, "bgezl")); // Branch on Greater Than or Equal to Zero Likely
|
|
|
|
// weird ones
|
|
def(IK::DIV, "div").src_gpr(FT::RS).src_gpr(FT::RT); // Divide Word
|
|
def(IK::DIVU, "divu").src_gpr(FT::RS).src_gpr(FT::RT); // Divide Unsigned Word
|
|
|
|
def(IK::ORI, "ori").dst_gpr(FT::RT).src_gpr(FT::RS).src(FT::ZIMM16, DT::IMM); // Or Immediate
|
|
def(IK::XORI, "xori")
|
|
.dst_gpr(FT::RT)
|
|
.src_gpr(FT::RS)
|
|
.src(FT::ZIMM16, DT::IMM); // Exclusive Or Immediate
|
|
def(IK::ANDI, "andi").dst_gpr(FT::RT).src_gpr(FT::RS).src(FT::ZIMM16, DT::IMM); // And Immediate
|
|
|
|
def(IK::LUI, "lui").dst_gpr(FT::RT).src(FT::SIMM16, DT::IMM); // Load Upper Immediate
|
|
def(IK::JALR, "jalr").dst_gpr(FT::RD).src_gpr(FT::RS).has_delay_slot =
|
|
true; // Jump and Link Register
|
|
def(IK::JR, "jr").src_gpr(FT::RS).has_delay_slot = true; // Jump Register
|
|
|
|
def_load(IK::LWC1, "lwc1")
|
|
.dst_fpr(FT::FT)
|
|
.src(FT::SIMM16, DT::IMM)
|
|
.src_gpr(FT::RS); // Load Word to Floating Point
|
|
def_store(IK::SWC1, "swc1")
|
|
.src_fpr(FT::FT)
|
|
.src(FT::SIMM16, DT::IMM)
|
|
.src_gpr(FT::RS); // Store Word from Floating Point
|
|
|
|
// weird moves
|
|
def(IK::MFC1, "mfc1").dst_gpr(FT::RT).src_fpr(FT::FS); // Move Word from Floating Point
|
|
def(IK::MTC1, "mtc1").dst_fpr(FT::FS).src_gpr(FT::RT); // Move Word to Floating Point
|
|
def(IK::MTC0, "mtc0")
|
|
.src_gpr(FT::RT)
|
|
.dst(FT::RD, DT::COP0); // Move to System Control Coprocessor
|
|
def(IK::MFC0, "mfc0")
|
|
.dst_gpr(FT::RT)
|
|
.src(FT::RD, DT::COP0); // Move from System Control Coprocessor
|
|
def(IK::MTDAB, "mtdab").src_gpr(FT::RT); // Move to Data Address Breakpoint Register
|
|
def(IK::MTDABM, "mtdabm").src_gpr(FT::RT); // Move to Data Address Breakpoint Mask Register
|
|
drd(def(IK::MFHI, "mfhi")); // Move from HI Register
|
|
drd(def(IK::MFLO, "mflo")); // Move from LO Register
|
|
def(IK::MTLO1, "mtlo1").src_gpr(FT::RS); // Move to LO1 Register
|
|
drd(def(IK::MFLO1, "mflo1")); // Move from LO1 Register
|
|
drd(def(IK::PMFHL_UW, "pmfhl.uw").gpr128()); // Parallel Move From HI/LO Register
|
|
drd(def(IK::PMFHL_LW, "pmfhl.lw").gpr128());
|
|
drd(def(IK::PMFHL_LH, "pmfhl.lh").gpr128());
|
|
def(IK::MFPC, "mfpc").dst_gpr(FT::RT).src(FT::PCR, DT::PCR); // Move from Performance Counter
|
|
def(IK::MTPC, "mtpc").src_gpr(FT::RT).dst(FT::PCR, DT::PCR); // Move to Performance Counter
|
|
|
|
// other weirds
|
|
def(IK::SYSCALL, "syscall").src(FT::SYSCALL, DT::IMM); // System Call
|
|
def(IK::CACHE_DXWBIN, "cache dxwbin")
|
|
.src_gpr(FT::RS)
|
|
.src(FT::SIMM16, DT::IMM); // Cache Operation (Index Writeback Invalidate)
|
|
def(IK::PREF, "pref").src_gpr(FT::RT).src(FT::SIMM16, DT::IMM).src_gpr(FT::RS); // Prefetch
|
|
|
|
// plains
|
|
def(IK::SYNCP, "sync.p"); // Synchronize Shared Memory (Pipeline)
|
|
def(IK::SYNCL, "sync.l"); // Synchronize Shared Memory (Load)
|
|
def(IK::ERET, "eret"); // Exception Return
|
|
def(IK::EI, "ei"); // Enable Interrupt
|
|
def(IK::MTSAB, "mtsab")
|
|
.src_gpr(FT::RS)
|
|
.src(FT::ZIMM16, DT::IMM); // Move Byte Count to Shift Amount Register
|
|
drd_srs_srt(def(IK::QFSRV, "qfsrv")).gpr128(); // Quadword Funnel Shift Right Variable
|
|
|
|
drd_srs_srt(def(IK::PPACB, "ppacb").gpr128()); // Parallel Pack to Byte
|
|
drd_srs_srt(def(IK::PPACH, "ppach").gpr128()); // Parallel Pack to Halfword
|
|
drd_srs_srt(def(IK::PPACW, "ppacw").gpr128()); // Parallel Pack to Word
|
|
drd_srs_srt(def(IK::PADDB, "paddb").gpr128()); // Parallel Add Byte
|
|
drd_srs_srt(def(IK::PADDH, "paddh").gpr128()); // Parallel Add Halfword
|
|
drd_srs_srt(def(IK::PADDW, "paddw").gpr128()); // Parallel Add Word
|
|
drd_srs_srt(def(IK::PSUBH, "psubh").gpr128()); // Parallel Subtract Halfword
|
|
drd_srs_srt(def(IK::PSUBW, "psubw").gpr128()); // Parallel Subtract Word
|
|
drd_srs_srt(def(IK::PMINH, "pminh").gpr128()); // Parallel Minimize Halfword
|
|
drd_srs_srt(def(IK::PMINW, "pminw").gpr128()); // Parallel Minimize Word
|
|
drd_srs_srt(def(IK::PMAXH, "pmaxh").gpr128()); // Parallel Maximize Halfword
|
|
drd_srs_srt(def(IK::PMAXW, "pmaxw").gpr128()); // Parallel Maximize Word
|
|
drd_srs_srt(def(IK::PEXTLB, "pextlb").gpr128()); // Parallel Extend Lower from Byte
|
|
drd_srs_srt(def(IK::PEXTLH, "pextlh").gpr128()); // Parallel Extend Lower from Halfword
|
|
drd_srs_srt(def(IK::PEXTLW, "pextlw").gpr128()); // Parallel Extend Lower from Word
|
|
drd_srs_srt(def(IK::PCGTW, "pcgtw").gpr128()); // Parallel Compare for Greater Than Word
|
|
drd_srs_srt(def(IK::PCGTB, "pcgtb").gpr128()); // Parallel Compare for Greater Than Byte
|
|
drd_srs_srt(def(IK::PCEQB, "pceqb").gpr128()); // Parallel Compare for Equal Byte
|
|
drd_srs_srt(def(IK::PCEQW, "pceqw").gpr128()); // Parallel Compare for Equal Word
|
|
drd_srs_srt(def(IK::PEXTUB, "pextub").gpr128()); // Parallel Extend Upper from Byte
|
|
drd_srs_srt(def(IK::PEXTUH, "pextuh").gpr128()); // Parallel Extend Upper from Halfword
|
|
drd_srs_srt(def(IK::PEXTUW, "pextuw").gpr128()); // Parallel Extend Upper from Word
|
|
drd_srs_srt(def(IK::PCPYUD, "pcpyud").gpr128()); // Parallel Copy Upper Doubleword
|
|
drd_srs_srt(def(IK::PCPYLD, "pcpyld").gpr128()); // Parallel Copy Lower Doubleword
|
|
drd_srs_srt(def(IK::PMADDH, "pmaddh").gpr128()); // Parallel Multiply-Add Halfword
|
|
drd_srs_srt(def(IK::PMULTH, "pmulth").gpr128()); // Parallel Multiply Halfword
|
|
drd_srs_srt(def(IK::PINTEH, "pinteh").gpr128()); // Parallel Interleave Even Halfword
|
|
drd_srs_srt(def(IK::PAND, "pand").gpr128()); // Parallel And
|
|
drd_srs_srt(def(IK::POR, "por").gpr128()); // Parallel Or
|
|
drd_srs_srt(def(IK::PNOR, "pnor").gpr128()); // Parallel Not Or
|
|
drd_srs_srt(def(IK::PXOR, "pxor").gpr128()); // Parallel Exclusive Or
|
|
|
|
def(IK::PEXEW, "pexew").gpr128().dst_gpr(FT::RD).src_gpr(FT::RT); // Parallel Exchange Even Word
|
|
|
|
drd_srt_ssa(def(IK::PSLLW, "psllw").gpr128()); // Parallel Shift Left Logical Word
|
|
drd_srt_ssa(def(IK::PSLLH, "psllh").gpr128()); // Parallel Shift Left Logical Halfword
|
|
drd_srt_ssa(def(IK::PSRAW, "psraw").gpr128()); // Parallel Shift Right Arithmetic Word
|
|
drd_srt_ssa(def(IK::PSRAH, "psrah").gpr128()); // Parallel Shift Right Arithmetic Halfword
|
|
drd_srt_ssa(def(IK::PSRLH, "psrlh").gpr128()); // Parallel Shift Right Logical Halfword
|
|
|
|
def(IK::PLZCW, "plzcw")
|
|
.dst_gpr(FT::RD)
|
|
.src_gpr(FT::RS)
|
|
.gpr128(); // Parallel Leading Zero Count Word
|
|
def(IK::PABSW, "pabsw").dst_gpr(FT::RD).src_gpr(FT::RT).gpr128(); // Parallel Absolute Word
|
|
def(IK::PROT3W, "prot3w").dst_gpr(FT::RD).src_gpr(FT::RT).gpr128(); // Parallel Rotate 3 Word
|
|
def(IK::PCPYH, "pcpyh").dst_gpr(FT::RD).src_gpr(FT::RT).gpr128(); // Parallel Copy Halfword
|
|
|
|
// COP1
|
|
|
|
// branch (no registers)
|
|
bt(def_branch(IK::BC1F, "bc1f")); // Branch on FP False
|
|
bt(def_branch(IK::BC1T, "bc1t")); // Branch on FP True
|
|
bt(def_branch_likely(IK::BC1FL, "bc1fl")); // Branch on FP False Likely
|
|
bt(def_branch_likely(IK::BC1TL, "bc1tl")); // Branch on FP True Likely
|
|
|
|
dfd_sfs_sft(def(IK::ADDS, "add.s")); // Floating Point Add
|
|
dfd_sfs_sft(def(IK::SUBS, "sub.s")); // Floating Point Subtract
|
|
dfd_sfs_sft(def(IK::MULS, "mul.s")); // Floating Point Multiply
|
|
dfd_sfs_sft(def(IK::DIVS, "div.s")); // Floating Point Divide
|
|
dfd_sfs_sft(def(IK::MINS, "min.s")); // Floating Point Minimum
|
|
dfd_sfs_sft(def(IK::MAXS, "max.s")); // Floating Point Maximum
|
|
dfd_sfs_sft(def(IK::MADDS, "madd.s")); // Floating Point Multiply-Add
|
|
dfd_sfs_sft(def(IK::MSUBS, "msub.s")); // Floating Point Multiply and Subtract
|
|
dfd_sfs_sft(def(IK::RSQRTS, "rsqrt.s")); // Floating Point Reciporcal Square Root
|
|
|
|
dfd_sfs(def(IK::ABSS, "abs.s")); // Floating Point Absolute Value
|
|
dfd_sfs(def(IK::NEGS, "neg.s")); // Floating Point Negate
|
|
dfd_sfs(def(IK::CVTSW, "cvt.s.w")); // Fixed-point Convert to Single Floating Point
|
|
dfd_sfs(def(IK::CVTWS, "cvt.w.s")); // Floating Point Convert to Word Fixed-point
|
|
dfd_sfs(def(IK::MOVS, "mov.s")); // Floating Point Move
|
|
dfd_sft(def(IK::SQRTS, "sqrt.s")); // Floating Point Square Root
|
|
|
|
sfs_sft(def(IK::CLTS, "c.lt.s")); // Floating Point Compare
|
|
sfs_sft(def(IK::CLES, "c.le.s")); // Floating Point Compare
|
|
sfs_sft(def(IK::CEQS, "c.eq.s")); // Floating Point Compare
|
|
sfs_sft(def(IK::MULAS, "mula.s")); // Floating Point Multiply to Accumulator
|
|
sfs_sft(def(IK::MADDAS, "madda.s")); // Floating Point Multiply-Add to Accumulator
|
|
sfs_sft(def(IK::ADDAS, "adda.s")); // Floating Point Add to Accumulator
|
|
sfs_sft(def(IK::MSUBAS, "msuba.s")); // Floating Point Multiply and Subtract from Accumulator
|
|
|
|
// COP2 weirds
|
|
def_store(IK::SQC2, "sqc2")
|
|
.src(FT::FT, DT::VF)
|
|
.src(FT::SIMM16, DT::IMM)
|
|
.src_gpr(FT::RS); // Store Quadword from COP2
|
|
def_load(IK::LQC2, "lqc2")
|
|
.dst(FT::FT, DT::VF)
|
|
.src(FT::SIMM16, DT::IMM)
|
|
.src_gpr(FT::RS); // Load Quadword to COP2
|
|
|
|
// COP2
|
|
// NOTE: if adding more here, update AtomicOp.cpp AsmOp::update_register_info()
|
|
cd_dvft_svfs(def(IK::VMOVE, "vmove")); // Transfer between Floating-Point Registers
|
|
cd_dvft_svfs(def(IK::VFTOI0, "vftoi0")); // Conversion to Fixed Point
|
|
cd_dvft_svfs(def(IK::VFTOI4, "vftoi4")); // Conversion to Fixed Point
|
|
cd_dvft_svfs(def(IK::VFTOI12, "vftoi12")); // Conversion to Fixed Point
|
|
cd_dvft_svfs(def(IK::VFTOI15, "vftoi15")); // Conversion to Fixed Point
|
|
cd_dvft_svfs(def(IK::VITOF0, "vitof0")); // Conversion to Floating Point Number
|
|
cd_dvft_svfs(def(IK::VITOF12, "vitof12")); // Conversion to Floating Point Number
|
|
cd_dvft_svfs(def(IK::VITOF15, "vitof15")); // Conversion to Floating Point Number
|
|
cd_dvft_svfs(def(IK::VABS, "vabs")); // Absolute Value
|
|
|
|
cd_dvfd_svfs_svft(def(IK::VADD, "vadd"));
|
|
cd_dvfd_svfs_svft(def(IK::VSUB, "vsub"));
|
|
cd_dvfd_svfs_svft(def(IK::VMUL, "vmul"));
|
|
cd_dvfd_svfs_svft(def(IK::VMINI, "vmini"));
|
|
cd_dvfd_svfs_svft(def(IK::VMAX, "vmax"));
|
|
cd_dvfd_svfs_svft(def(IK::VOPMSUB, "vopmsub"));
|
|
cd_dvfd_svfs_svft(def(IK::VMADD, "vmadd"));
|
|
cd_dvfd_svfs_svft(def(IK::VMSUB, "vmsub"));
|
|
|
|
cb_cd_dvfd_svfs_svft(def(IK::VSUB_BC, "vsub"));
|
|
cb_cd_dvfd_svfs_svft(def(IK::VADD_BC, "vadd"));
|
|
cb_cd_dvfd_svfs_svft(def(IK::VMADD_BC, "vmadd"));
|
|
cb_cd_dvfd_svfs_svft(def(IK::VMSUB_BC, "vmsub"));
|
|
cb_cd_dvfd_svfs_svft(def(IK::VMUL_BC, "vmul"));
|
|
cb_cd_dvfd_svfs_svft(def(IK::VMINI_BC, "vmini"));
|
|
cb_cd_dvfd_svfs_svft(def(IK::VMAX_BC, "vmax"));
|
|
|
|
cb_cd_dacc_svfs_svft(def(IK::VADDA_BC, "vadda"));
|
|
cb_cd_dacc_svfs_svft(def(IK::VMADDA_BC, "vmadda"));
|
|
cb_cd_dacc_svfs_svft(def(IK::VMULA_BC, "vmula"));
|
|
cb_cd_dacc_svfs_svft(def(IK::VMSUBA_BC, "vmsuba"));
|
|
|
|
cd_dvfd_svfs_sq(def(IK::VADDQ, "vaddq"));
|
|
cd_dvfd_svfs_sq(def(IK::VSUBQ, "vsubq"));
|
|
cd_dvfd_svfs_sq(def(IK::VMULQ, "vmulq"));
|
|
cd_dvfd_svfs_sq(def(IK::VMSUBQ, "vmsubq"));
|
|
|
|
cd_dacc_svfs_svft(def(IK::VMULA, "vmula"));
|
|
cd_dacc_svfs_svft(def(IK::VADDA, "vadda"));
|
|
cd_dacc_svfs_svft(def(IK::VMADDA, "vmadda"));
|
|
cd_dacc_svfs_svft(def(IK::VMSUBA, "vmsuba"));
|
|
|
|
cd_dacc_svfs_svft(def(IK::VOPMULA, "vopmula"));
|
|
|
|
// weird
|
|
def(IK::VDIV, "vdiv")
|
|
.dst(FT::ZERO, DT::VU_Q)
|
|
.src_vf(FT::FS)
|
|
.src(FT::FS_F, DT::VF_F)
|
|
.src_vf(FT::FT)
|
|
.src(FT::FT_F, DT::VF_F);
|
|
def(IK::VRSQRT, "vrsqrt")
|
|
.dst(FT::ZERO, DT::VU_Q)
|
|
.src_vf(FT::FS)
|
|
.src(FT::FS_F, DT::VF_F)
|
|
.src_vf(FT::FT)
|
|
.src(FT::FT_F, DT::VF_F);
|
|
def(IK::VCLIP, "vclip").src(FT::DEST, DT::DEST).src_vf(FT::FS).src_vf(FT::FT);
|
|
def(IK::VMULAQ, "vmulaq")
|
|
.src(FT::DEST, DT::DEST)
|
|
.dst(FT::ZERO, DT::VU_ACC)
|
|
.src_vf(FT::FS)
|
|
.src(FT::ZERO, DT::VU_Q);
|
|
|
|
def(IK::VRGET, "vrget").src(FT::DEST, DT::DEST).dst_vf(FT::FT);
|
|
def(IK::VMR32, "vmr32").src(FT::DEST, DT::DEST).src_vf(FT::FT).dst_vf(FT::FS);
|
|
|
|
// integer
|
|
def(IK::VMTIR, "vmtir").dst(FT::RT, DT::VI).src_vf(FT::FS).src(FT::BC, DT::BC);
|
|
def(IK::VIAND, "viand").dst_vi(FT::FD).src_vi(FT::FS).src_vi(FT::FT);
|
|
def(IK::VLQI, "vlqi").src(FT::DEST, DT::DEST).dst_vf(FT::FT).src_vi(FT::FS); // todo inc
|
|
def(IK::VSQI, "vsqi").src(FT::DEST, DT::DEST).src_vf(FT::FS).src_vi(FT::FT); // todo inc
|
|
def(IK::VIADDI, "viaddi").dst_vi(FT::FT).src_vi(FT::FS).src(FT::IMM5, DT::IMM);
|
|
|
|
def(IK::QMFC2, "qmfc2").src(FT::IL, DT::IL).dst_gpr(FT::RT).src_vf(FT::FS);
|
|
def(IK::QMTC2, "qmtc2").src(FT::IL, DT::IL).dst_vf(FT::FS).src_gpr(FT::RT);
|
|
def(IK::VSQRT, "vsqrt").dst(FT::ZERO, DT::VU_Q).src_vf(FT::FT).src(FT::FT_F, DT::VF_F);
|
|
def(IK::VRXOR, "vrxor").src(FT::BC, DT::BC).src_vf(FT::FS);
|
|
def(IK::VRNEXT, "vrnext").src(FT::DEST, DT::DEST).dst_vf(FT::FT);
|
|
def(IK::CTC2, "ctc2").src(FT::IL, DT::IL).src_gpr(FT::RT).dst(FT::RD, DT::VI);
|
|
def(IK::CFC2, "cfc2").src(FT::IL, DT::IL).dst_gpr(FT::RT).src(FT::RD, DT::VI);
|
|
|
|
def(IK::VCALLMS, "vcallms").src(FT::IMM15, DT::VCALLMS_TARGET);
|
|
|
|
def(IK::VNOP, "vnop");
|
|
def(IK::VWAITQ, "vwaitq");
|
|
|
|
uint32_t valid_count = 0, total_count = 0;
|
|
for (auto& info : gOpcodeInfo) {
|
|
if (info.defined) {
|
|
valid_count++;
|
|
}
|
|
total_count++;
|
|
}
|
|
|
|
// for the UNKNOWN op which shouldn't be valid.
|
|
total_count--;
|
|
ASSERT(total_count == valid_count);
|
|
opcodes_initialized = true;
|
|
}
|
|
|
|
void OpcodeInfo::step(DecodeStep& s) {
|
|
ASSERT(step_count < MAX_DECODE_STEPS);
|
|
steps[step_count] = s;
|
|
step_count++;
|
|
defined = true;
|
|
}
|
|
|
|
OpcodeInfo& OpcodeInfo::src(FieldType field, DecodeType decode) {
|
|
DecodeStep new_step;
|
|
new_step.is_src = true;
|
|
new_step.field = field;
|
|
new_step.decode = decode;
|
|
step(new_step);
|
|
return *this;
|
|
}
|
|
|
|
OpcodeInfo& OpcodeInfo::src_gpr(FieldType field) {
|
|
return src(field, DT::GPR);
|
|
}
|
|
|
|
OpcodeInfo& OpcodeInfo::src_fpr(FieldType field) {
|
|
return src(field, DT::FPR);
|
|
}
|
|
|
|
OpcodeInfo& OpcodeInfo::src_vf(FieldType field) {
|
|
return src(field, DT::VF);
|
|
}
|
|
|
|
OpcodeInfo& OpcodeInfo::src_vi(FieldType field) {
|
|
return src(field, DT::VI);
|
|
}
|
|
|
|
OpcodeInfo& OpcodeInfo::dst(FieldType field, DecodeType decode) {
|
|
DecodeStep new_step;
|
|
new_step.is_src = false;
|
|
new_step.field = field;
|
|
new_step.decode = decode;
|
|
step(new_step);
|
|
return *this;
|
|
}
|
|
|
|
OpcodeInfo& OpcodeInfo::dst_gpr(FieldType field) {
|
|
return dst(field, DT::GPR);
|
|
}
|
|
|
|
OpcodeInfo& OpcodeInfo::dst_fpr(FieldType field) {
|
|
return dst(field, DT::FPR);
|
|
}
|
|
|
|
OpcodeInfo& OpcodeInfo::dst_vf(FieldType field) {
|
|
return dst(field, DT::VF);
|
|
}
|
|
|
|
OpcodeInfo& OpcodeInfo::dst_vi(FieldType field) {
|
|
return dst(field, DT::VI);
|
|
}
|
|
|
|
OpcodeInfo& OpcodeInfo::gpr128() {
|
|
gpr_128 = true;
|
|
return *this;
|
|
}
|
|
} // namespace decompiler
|