/*! * @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 def(IK::PEXCW, "pexcw") .gpr128() .dst_gpr(FT::RD) .src_gpr(FT::RT); // Parallel Exchange Center 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