#include "ps2recomp/r5900_decoder.h" #include namespace ps2recomp { R5900Decoder::R5900Decoder() { } R5900Decoder::~R5900Decoder() { } Instruction R5900Decoder::decodeInstruction(uint32_t address, uint32_t rawInstruction) { Instruction inst; inst.address = address; inst.raw = rawInstruction; inst.opcode = OPCODE(rawInstruction); inst.rs = RS(rawInstruction); inst.rt = RT(rawInstruction); inst.rd = RD(rawInstruction); inst.sa = SA(rawInstruction); inst.function = FUNCTION(rawInstruction); inst.immediate = IMMEDIATE(rawInstruction); inst.simmediate = SIMMEDIATE(rawInstruction); inst.target = TARGET(rawInstruction); inst.isMMI = false; inst.isVU = false; inst.isBranch = false; inst.isJump = false; inst.isCall = false; inst.isReturn = false; inst.hasDelaySlot = false; inst.isMultimedia = false; inst.isLoad = false; inst.isStore = false; // Initialize the enhanced fields inst.mmiType = 0; inst.mmiFunction = 0; inst.pmfhlVariation = 0; inst.vuFunction = 0; inst.vectorInfo.isVector = false; inst.vectorInfo.usesQReg = false; inst.vectorInfo.usesPReg = false; inst.vectorInfo.modifiesMAC = false; inst.vectorInfo.vectorField = 0xF; // All fields (xyzw) inst.modificationInfo.modifiesGPR = false; inst.modificationInfo.modifiesFPR = false; inst.modificationInfo.modifiesVFR = false; inst.modificationInfo.modifiesVIR = false; inst.modificationInfo.modifiesVIC = false; inst.modificationInfo.modifiesMemory = false; inst.modificationInfo.modifiesControl = false; switch (inst.opcode) { case OPCODE_SPECIAL: decodeSpecial(inst); break; case OPCODE_REGIMM: decodeRegimm(inst); break; case OPCODE_J: decodeJType(inst); break; case OPCODE_JAL: decodeJType(inst); break; case OPCODE_BEQ: case OPCODE_BNE: case OPCODE_BLEZ: case OPCODE_BGTZ: case OPCODE_BEQL: case OPCODE_BNEL: case OPCODE_BLEZL: case OPCODE_BGTZL: decodeIType(inst); inst.isBranch = true; inst.hasDelaySlot = true; inst.modificationInfo.modifiesControl = true; // PC potentially break; case OPCODE_DADDI: case OPCODE_DADDIU: decodeIType(inst); if (inst.rt != 0) inst.modificationInfo.modifiesGPR = true; break; case OPCODE_MMI: decodeMMI(inst); break; case OPCODE_LQ: decodeIType(inst); inst.isLoad = true; inst.isMultimedia = true; // 128-bit load break; case OPCODE_SQ: decodeIType(inst); inst.isStore = true; inst.isMultimedia = true; // 128-bit store inst.modificationInfo.modifiesMemory = true; break; case OPCODE_LB: case OPCODE_LH: case OPCODE_LW: case OPCODE_LBU: case OPCODE_LHU: case OPCODE_LWU: case OPCODE_LD: inst.isLoad = true; if (inst.rt != 0) inst.modificationInfo.modifiesGPR = true; break; case OPCODE_LWL: case OPCODE_LWR: case OPCODE_LDL: case OPCODE_LDR: inst.isLoad = true; if (inst.rt != 0) inst.modificationInfo.modifiesGPR = true; inst.modificationInfo.modifiesMemory = true; break; case OPCODE_LL: case OPCODE_LLD: decodeIType(inst); inst.isLoad = true; if (inst.rt != 0) { inst.modificationInfo.modifiesGPR = true; } // LL/LLD manipulate the load-linked bit in COP0 status inst.modificationInfo.modifiesControl = true; break; case OPCODE_LWC1: inst.isLoad = true; inst.modificationInfo.modifiesFPR = true; break; case OPCODE_LDC1: // Not present/used on EE FPU case OPCODE_LWC2: // Maybe unused case OPCODE_LDC2: // VU Load inst.isLoad = true; inst.isVU = true; inst.modificationInfo.modifiesVFR = true; break; case OPCODE_SB: case OPCODE_SH: case OPCODE_SW: case OPCODE_SD: inst.isStore = true; inst.modificationInfo.modifiesMemory = true; break; case OPCODE_SWL: case OPCODE_SWR: case OPCODE_SDL: case OPCODE_SDR: inst.isStore = true; inst.modificationInfo.modifiesMemory = true; break; case OPCODE_SWC1: inst.isStore = true; inst.modificationInfo.modifiesMemory = true; break; case OPCODE_SDC1: // Not present/used on EE FPU case OPCODE_SWC2: // Potentially unused case OPCODE_SDC2: inst.isStore = true; inst.isVU = true; inst.modificationInfo.modifiesMemory = true; break; case OPCODE_SC: case OPCODE_SCD: inst.isStore = true; inst.modificationInfo.modifiesMemory = true; if (inst.rt != 0) inst.modificationInfo.modifiesGPR = true; // Writes success/fail to rt inst.modificationInfo.modifiesControl = true; // Reads/Clears LLBit break; case OPCODE_ADDI: case OPCODE_ADDIU: case OPCODE_SLTI: case OPCODE_SLTIU: case OPCODE_ANDI: case OPCODE_ORI: case OPCODE_XORI: case OPCODE_LUI: decodeIType(inst); if (inst.rt != 0) inst.modificationInfo.modifiesGPR = true; break; case OPCODE_CACHE: decodeIType(inst); inst.modificationInfo.modifiesControl = true; // Cache state break; case OPCODE_PREF: decodeIType(inst); break; case OPCODE_COP0: decodeCOP0(inst); break; case OPCODE_COP1: decodeCOP1(inst); break; case OPCODE_COP2: decodeCOP2(inst); break; default: // Default to I-type for most other instructions decodeIType(inst); break; } // Generic multimedia flag if MMI or VU if (inst.isMMI || inst.isVU) { inst.isMultimedia = true; inst.vectorInfo.isVector = inst.isVU; // Only VU ops are truly vector } return inst; } void R5900Decoder::decodeRType(Instruction &inst) const { // R-type instructions already have all fields set correctly if (inst.rd != 0) inst.modificationInfo.modifiesGPR = true; } void R5900Decoder::decodeIType(Instruction &inst) const { // I-type instructions already have all fields set correctly if (!inst.isStore && !inst.isBranch && inst.rt != 0) { inst.modificationInfo.modifiesGPR = true; } } void R5900Decoder::decodeJType(Instruction &inst) const { // J-type instructions already have all fields set correctly inst.isJump = true; inst.hasDelaySlot = true; inst.modificationInfo.modifiesControl = true; // PC if (inst.opcode == OPCODE_JAL) { inst.isCall = true; inst.modificationInfo.modifiesGPR = true; // $ra (r[31]) } } void R5900Decoder::decodeSpecial(Instruction &inst) const { if (inst.rd != 0) inst.modificationInfo.modifiesGPR = true; switch (inst.function) { case SPECIAL_JR: inst.isJump = true; inst.hasDelaySlot = true; inst.modificationInfo.modifiesGPR = false; // Doesn't modify GPR itself inst.modificationInfo.modifiesControl = true; // PC if (inst.rs == 31) { // jr $ra is typically a return inst.isReturn = true; } break; case SPECIAL_JALR: inst.isJump = true; inst.isCall = true; inst.hasDelaySlot = true; if (inst.rd == 0) inst.modificationInfo.modifiesGPR = false; // JALR $zero, $rs is like JR $rs else inst.modificationInfo.modifiesGPR = true; inst.modificationInfo.modifiesControl = true; // PC break; case SPECIAL_SYSCALL: case SPECIAL_BREAK: // Special handling for syscall/break inst.modificationInfo.modifiesGPR = false; // No GPR change inst.modificationInfo.modifiesControl = true; // Changes control flow, potentially registers via handler break; case SPECIAL_MFHI: case SPECIAL_MFLO: if (inst.rd == 0) inst.modificationInfo.modifiesGPR = false; break; case SPECIAL_MTHI: case SPECIAL_MTLO: // HI/LO register operations inst.modificationInfo.modifiesGPR = false; // Doesn't modify rd inst.modificationInfo.modifiesControl = true; // HI/LO break; case SPECIAL_MULT: case SPECIAL_MULTU: case SPECIAL_DIV: case SPECIAL_DIVU: // Multiplication and division operations inst.modificationInfo.modifiesGPR = false; // Doesn't modify rd inst.modificationInfo.modifiesControl = true; // HI/LO break; case SPECIAL_ADD: case SPECIAL_ADDU: case SPECIAL_SUB: case SPECIAL_SUBU: case SPECIAL_AND: case SPECIAL_OR: case SPECIAL_XOR: case SPECIAL_NOR: // ALU operations if (inst.rd == 0) inst.modificationInfo.modifiesGPR = false; break; case SPECIAL_SLL: case SPECIAL_SRL: case SPECIAL_SRA: case SPECIAL_SLLV: case SPECIAL_SRLV: case SPECIAL_SRAV: // Shift operations if (inst.rd == 0) inst.modificationInfo.modifiesGPR = false; break; // 64-bit specific operations case SPECIAL_DADD: case SPECIAL_DADDU: case SPECIAL_DSUB: case SPECIAL_DSUBU: case SPECIAL_DSLL: case SPECIAL_DSRL: case SPECIAL_DSRA: case SPECIAL_DSLL32: case SPECIAL_DSRL32: case SPECIAL_DSRA32: case SPECIAL_DSLLV: case SPECIAL_DSRLV: case SPECIAL_DSRAV: // 64-bit operations if (inst.rd == 0) inst.modificationInfo.modifiesGPR = false; break; case SPECIAL_MOVZ: case SPECIAL_MOVN: if (inst.rd == 0) inst.modificationInfo.modifiesGPR = false; break; // Set on Less Than case SPECIAL_SLT: case SPECIAL_SLTU: if (inst.rd == 0) inst.modificationInfo.modifiesGPR = false; break; case SPECIAL_TGE: case SPECIAL_TGEU: case SPECIAL_TLT: case SPECIAL_TLTU: case SPECIAL_TEQ: case SPECIAL_TNE: inst.modificationInfo.modifiesGPR = false; inst.modificationInfo.modifiesControl = true; // Control flow change via trap break; // PS2 Specific (MFSA/MTSA) case SPECIAL_MFSA: // Modifies rd GPR if (inst.rd == 0) inst.modificationInfo.modifiesGPR = false; break; case SPECIAL_MTSA: // Modifies SA control register inst.modificationInfo.modifiesGPR = false; inst.modificationInfo.modifiesControl = true; // SA reg break; case SPECIAL_SYNC: inst.modificationInfo.modifiesGPR = false; inst.modificationInfo.modifiesControl = true; break; } } void R5900Decoder::decodeRegimm(Instruction &inst) const { uint32_t rt = inst.rt; switch (rt) { case REGIMM_BLTZ: case REGIMM_BGEZ: case REGIMM_BLTZL: case REGIMM_BGEZL: // Branches inst.isBranch = true; inst.hasDelaySlot = true; inst.modificationInfo.modifiesControl = true; // PC potentially break; case REGIMM_BLTZAL: case REGIMM_BGEZAL: case REGIMM_BLTZALL: case REGIMM_BGEZALL: // Branch and Link inst.isBranch = true; inst.isCall = true; inst.hasDelaySlot = true; inst.modificationInfo.modifiesGPR = true; // $ra (r[31]) inst.modificationInfo.modifiesControl = true; // PC break; case REGIMM_TGEI: case REGIMM_TGEIU: case REGIMM_TLTI: case REGIMM_TLTIU: case REGIMM_TEQI: case REGIMM_TNEI: // Trap Instructions inst.modificationInfo.modifiesControl = true; break; case REGIMM_MTSAB: case REGIMM_MTSAH: // PS2 specific MTSAB/MTSAH instructions (for QMFC2/QMTC2) inst.isMultimedia = true; inst.modificationInfo.modifiesControl = true; // SA register break; default: // Unknown REGIMM instructions std::cerr << "Unknown REGIMM instruction: " << std::hex << inst.raw << std::endl; break; } } void R5900Decoder::decodeMMI(Instruction &inst) const { inst.isMMI = true; inst.isMultimedia = true; inst.modificationInfo.modifiesGPR = true; // Most MMI ops write to rd GPR if (inst.rd == 0) inst.modificationInfo.modifiesGPR = false; // Except if rd is $zero // The function field is actually determined by the lowest 6 bits (as in R-type) uint32_t mmiFunction = inst.function; uint32_t rs = inst.rs; if (mmiFunction == MMI_MMI0) { decodeMMI0(inst); return; } if (mmiFunction == MMI_MMI1) { decodeMMI1(inst); return; } if (mmiFunction == MMI_MMI2) { decodeMMI2(inst); return; } if (mmiFunction == MMI_MMI3) { decodeMMI3(inst); return; } switch (mmiFunction) { case MMI_PLZCW: // Parallel leading zero/one count word break; case MMI_MFHI1: case MMI_MFLO1: // Move from HI1/LO1 -> rd if (inst.rd == 0) { inst.modificationInfo.modifiesGPR = false; } inst.modificationInfo.modifiesControl = false; break; case MMI_MTHI1: case MMI_MTLO1: // Move to HI1/LO1 inst.modificationInfo.modifiesGPR = false; inst.modificationInfo.modifiesControl = true; break; case MMI_PSLLH: case MMI_PSRLH: case MMI_PSRAH: case MMI_PSLLW: case MMI_PSRLW: case MMI_PSRAW: // Packed shift instructions; defaults already mark GPR modify (unless rd==0) break; // HI/LO or HI1/LO1 producers/consumers case MMI_MADD: case MMI_MADDU: case MMI_MSUB: case MMI_MSUBU: case MMI_MADD1: case MMI_MADDU1: case MMI_MULT1: case MMI_MULTU1: case MMI_DIV1: case MMI_DIVU1: inst.modificationInfo.modifiesGPR = false; // Writes to HI/LO or HI1/LO1 inst.modificationInfo.modifiesControl = true; break; case MMI_PMTHL: case MMI3_PMTHI: case MMI3_PMTLO: inst.modificationInfo.modifiesGPR = false; // Writes to HI/LO or HI1/LO1 inst.modificationInfo.modifiesControl = true; break; case MMI_PMFHL: decodePMFHL(inst); break; default: // Unknown or unsupported MMI function std::cerr << "Unknown MMI function: " << std::hex << mmiFunction << std::endl; break; } } void R5900Decoder::decodeMMI0(Instruction &inst) const { inst.mmiType = 0; inst.mmiFunction = inst.sa; uint32_t sa = inst.sa; switch (sa) { case MMI0_PADDW: case MMI0_PSUBW: case MMI0_PCGTW: case MMI0_PMAXW: case MMI0_PADDH: case MMI0_PSUBH: case MMI0_PCGTH: case MMI0_PMAXH: case MMI0_PADDB: case MMI0_PSUBB: case MMI0_PCGTB: // Arithmetic and comparison operations break; case MMI0_PADDSW: case MMI0_PSUBSW: case MMI0_PADDSH: case MMI0_PSUBSH: case MMI0_PADDSB: case MMI0_PSUBSB: // Saturated arithmetic operations break; case MMI0_PEXTLW: case MMI0_PPACW: case MMI0_PEXTLH: case MMI0_PPACH: case MMI0_PEXTLB: case MMI0_PPACB: case MMI0_PEXT5: case MMI0_PPAC5: // Data packing/unpacking operations break; default: // Unknown MMI0 operation break; } } void R5900Decoder::decodeMMI1(Instruction &inst) const { inst.mmiType = 1; inst.mmiFunction = inst.sa; uint32_t subFunction = inst.function & 0x3F; uint32_t sa = inst.sa; switch (sa) { case MMI1_PABSW: case MMI1_PABSH: // Absolute value operations break; case MMI1_PCEQW: case MMI1_PCEQH: case MMI1_PCEQB: // Equality comparison operations break; case MMI1_PMINW: case MMI1_PMINH: // Minimum value operations break; case MMI1_PADDUW: case MMI1_PSUBUW: case MMI1_PEXTUW: case MMI1_PADDUH: case MMI1_PSUBUH: case MMI1_PEXTUH: case MMI1_PADDUB: case MMI1_PSUBUB: case MMI1_PEXTUB: // Unsigned arithmetic and extension operations break; case MMI1_QFSRV: // Quadword funnel shift right variable inst.isMultimedia = true; break; default: // Unknown MMI1 operation break; } } void R5900Decoder::decodeMMI2(Instruction &inst) const { inst.mmiType = 2; inst.mmiFunction = inst.sa; if (inst.sa == MMI2_PMADDW || inst.sa == MMI2_PMSUBW || inst.sa == MMI2_PMULTW || inst.sa == MMI2_PDIVW || inst.sa == MMI2_PDIVBW || inst.sa == MMI2_PMADDH || inst.sa == MMI2_PHMADH || inst.sa == MMI2_PMSUBH || inst.sa == MMI2_PHMSBH || inst.sa == MMI2_PMULTH) { inst.modificationInfo.modifiesControl = true; // HI/LO } uint32_t sa = inst.sa; switch (sa) { case MMI2_PMADDW: case MMI2_PMSUBW: case MMI2_PMADDH: case MMI2_PHMADH: case MMI2_PMSUBH: case MMI2_PHMSBH: case MMI2_PMULTH: // Multiply/multiply-add operations inst.isMultimedia = true; break; case MMI2_PSLLVW: case MMI2_PSRLVW: // Variable shift operations break; case MMI2_PMFHI: case MMI2_PMFLO: // Move from HI/LO registers break; case MMI2_PINTH: // Interleave half words break; case MMI2_PMULTW: case MMI2_PDIVW: case MMI2_PDIVBW: // Multiply/divide operations inst.isMultimedia = true; break; case MMI2_PCPYLD: // Copy lower doubleword break; case MMI2_PAND: case MMI2_PXOR: // Logical operations break; case MMI2_PEXEH: case MMI2_PREVH: case MMI2_PEXEW: case MMI2_PROT3W: // Data permutation operations break; default: // Unknown MMI2 operation break; } } void R5900Decoder::decodeMMI3(Instruction &inst) const { inst.mmiType = 3; inst.mmiFunction = inst.sa; uint32_t sa = inst.sa; switch (sa) { case MMI3_PMADDUW: // Unsigned multiply-add inst.isMultimedia = true; inst.modificationInfo.modifiesControl = true; // HI/LO break; case MMI3_PSRAVW: // Packed shift right arithmetic variable word break; case MMI3_PMTHI: inst.mmiFunction = MMI3_PMTHI; inst.modificationInfo.modifiesGPR = false; inst.modificationInfo.modifiesControl = true; // HI register is modified break; case MMI3_PMTLO: inst.mmiFunction = MMI3_PMTLO; inst.modificationInfo.modifiesGPR = false; inst.modificationInfo.modifiesControl = true; // LO register is modified break; case MMI3_PINTEH: // Interleave even halfwords break; case MMI3_PMULTUW: case MMI3_PDIVUW: // Unsigned multiply/divide operations inst.isMultimedia = true; inst.modificationInfo.modifiesControl = true; // HI/LO break; case MMI3_PCPYUD: // Copy upper doubleword break; case MMI3_POR: case MMI3_PNOR: // Logical operations break; case MMI3_PEXCH: case MMI3_PCPYH: case MMI3_PEXCW: // Data permutation operations break; default: // Unknown MMI3 operation break; } } void R5900Decoder::decodeCOP0(Instruction &inst) const { // COP0 (System Control) instructions uint8_t format = inst.rs; inst.modificationInfo.modifiesControl = true; // Assume COP0 always modifies some control state if (format == COP0_MF && inst.rt != 0) { inst.modificationInfo.modifiesGPR = true; } else if (format == COP0_CO && inst.function == COP0_CO_ERET) { inst.isReturn = true; inst.hasDelaySlot = false; } // ERET is special else if (format == COP0_BC) { inst.isBranch = true; inst.hasDelaySlot = true; } } void R5900Decoder::decodeCOP1(Instruction &inst) const { uint8_t format = inst.rs; if (format == COP1_MF || format == COP1_CF) { if (inst.rt != 0) inst.modificationInfo.modifiesGPR = true; } else if (format == COP1_BC) { inst.isBranch = true; inst.hasDelaySlot = true; inst.modificationInfo.modifiesControl = true; } else if (format == COP1_S || format == COP1_W || format == COP1_L) { inst.modificationInfo.modifiesFPR = true; } if (format == COP1_CT || (format == COP1_S && inst.function >= COP1_S_C_F)) { inst.modificationInfo.modifiesControl = true; } // FCR31 } void R5900Decoder::decodeCOP2(Instruction &inst) const { uint8_t format = inst.rs; inst.isVU = true; inst.isMultimedia = true; switch (format) { case COP2_QMFC2: case COP2_CFC2: if (inst.rt != 0) inst.modificationInfo.modifiesGPR = true; break; case COP2_QMTC2: inst.modificationInfo.modifiesVFR = true; break; // Modifies VU state case COP2_CTC2: inst.modificationInfo.modifiesControl = true; break; // Modifies VU control state case COP2_BC: inst.isBranch = true; inst.hasDelaySlot = true; inst.modificationInfo.modifiesControl = true; break; case COP2_CO: // VU Macro instructions (format >= 0x10) case COP2_CO + 1: case COP2_CO + 2: case COP2_CO + 3: case COP2_CO + 4: case COP2_CO + 5: case COP2_CO + 6: case COP2_CO + 7: case COP2_CO + 8: case COP2_CO + 9: case COP2_CO + 10: case COP2_CO + 11: case COP2_CO + 12: case COP2_CO + 13: case COP2_CO + 14: case COP2_CO + 15: { // Refine based on specific VU function uint8_t vu_func = inst.function; if (vu_func == VU0_S2_VDIV || vu_func == VU0_S2_VSQRT || vu_func == VU0_S2_VRSQRT) { inst.vectorInfo.fsf = (inst.raw >> 10) & 0x3; // Extract bits 10-11 inst.vectorInfo.ftf = (inst.raw >> 8) & 0x3; // Extract bits 8-9 } inst.vectorInfo.vectorField = (inst.raw >> 21) & 0xF; inst.modificationInfo.modifiesVFR = true; // Default: Modifies Vector Float Reg inst.modificationInfo.modifiesControl = true; // Default: Modifies Flags/Special Regs (Q, P, I, MAC, Clip...) if (vu_func >= 0x3C) // Special2 Table { switch (vu_func) { case VU0_S2_VDIV: case VU0_S2_VSQRT: case VU0_S2_VRSQRT: inst.vectorInfo.usesQReg = true; break; case VU0_S2_VMTIR: inst.modificationInfo.modifiesVFR = false; inst.modificationInfo.modifiesVIC = true; break; case VU0_S2_VMFIR: inst.modificationInfo.modifiesVIR = false; break; // Reads VI, writes VF case VU0_S2_VILWR: inst.modificationInfo.modifiesVFR = false; inst.modificationInfo.modifiesVIR = true; inst.isLoad = true; break; case VU0_S2_VISWR: inst.modificationInfo.modifiesVFR = false; inst.modificationInfo.modifiesVIR = false; inst.isStore = true; inst.modificationInfo.modifiesMemory = true; break; case VU0_S2_VRINIT: case VU0_S2_VRXOR: inst.modificationInfo.modifiesVFR = false; /* Modifies R */ break; // Modifies R case VU0_S2_VRGET: inst.modificationInfo.modifiesControl = false; /* Reads R, writes VF */ break; case VU0_S2_VRNEXT: inst.modificationInfo.modifiesControl = true; /* Modifies R */ inst.modificationInfo.modifiesVFR = false; break; // Writes R case VU0_S2_VABS: case VU0_S2_VMOVE: case VU0_S2_VMR32: inst.modificationInfo.modifiesControl = false; break; // Only VF case VU0_S2_VNOP: inst.modificationInfo.modifiesVFR = false; inst.modificationInfo.modifiesControl = false; break; case VU0_S2_VCLIPw: inst.modificationInfo.modifiesVFR = false; /* Modifies Clip flags */ break; } } else // Special1 Table { if (vu_func >= VU0_S1_VIADD && vu_func <= VU0_S1_VIOR) { inst.modificationInfo.modifiesVFR = false; inst.modificationInfo.modifiesVIR = true; } // Integer ops if (vu_func == VU0_S1_VIADDI) { inst.modificationInfo.modifiesVFR = false; inst.modificationInfo.modifiesVIR = true; } if (vu_func == VU0_S2_VMFIR) { inst.modificationInfo.modifiesVIR = false; } // Only reads VIR if (vu_func == VU0_S2_VMTIR) { inst.modificationInfo.modifiesVFR = false; inst.modificationInfo.modifiesVIC = true; } // Modifies I reg if (vu_func == VU0_S2_VILWR) { inst.modificationInfo.modifiesVFR = false; inst.modificationInfo.modifiesVIR = true; inst.isLoad = true; } if (vu_func == VU0_S2_VISWR) { inst.modificationInfo.modifiesVFR = false; inst.modificationInfo.modifiesVIR = false; inst.isStore = true; inst.modificationInfo.modifiesMemory = true; } if (vu_func == VU0_S2_VDIV || vu_func == VU0_S2_VSQRT || vu_func == VU0_S2_VRSQRT) { inst.vectorInfo.usesQReg = true; } } break; } } } void R5900Decoder::decodePMFHL(Instruction &inst) const { uint32_t saField = inst.sa; switch (saField) { case PMFHL_LW: inst.pmfhlVariation = PMFHL_LW; break; case PMFHL_UW: inst.pmfhlVariation = PMFHL_UW; break; case PMFHL_SLW: inst.pmfhlVariation = PMFHL_SLW; break; case PMFHL_LH: inst.pmfhlVariation = PMFHL_LH; break; case PMFHL_SH: inst.pmfhlVariation = PMFHL_SH; break; default: inst.pmfhlVariation = 0xFF; break; } } bool R5900Decoder::isBranchInstruction(const Instruction &inst) const { return inst.isBranch; } bool R5900Decoder::isJumpInstruction(const Instruction &inst) const { return inst.isJump; } bool R5900Decoder::isCallInstruction(const Instruction &inst) const { return inst.isCall; } bool R5900Decoder::isReturnInstruction(const Instruction &inst) const { return inst.isReturn; } bool R5900Decoder::isMMIInstruction(const Instruction &inst) const { return inst.isMMI; } bool R5900Decoder::isVUInstruction(const Instruction &inst) const { return inst.isVU; } bool R5900Decoder::isStore(const Instruction &inst) const { return inst.isStore; } bool R5900Decoder::isLoad(const Instruction &inst) const { return inst.isLoad; } bool R5900Decoder::hasDelaySlot(const Instruction &inst) const { return inst.hasDelaySlot; } uint32_t R5900Decoder::getBranchTarget(const Instruction &inst) const { if (!inst.isBranch) { return 0; } int32_t offset = inst.simmediate << 2; return inst.address + 4 + offset; } uint32_t R5900Decoder::getJumpTarget(const Instruction &inst) const { if (!inst.isJump) { return 0; } if (inst.opcode == OPCODE_SPECIAL && (inst.function == SPECIAL_JR || inst.function == SPECIAL_JALR)) { // JR/JALR: target is in the rs register (can't be determined statically) return 0; } if (inst.opcode == OPCODE_J || inst.opcode == OPCODE_JAL) { // J/JAL: target is in the lower 26 bits, shifted left by 2 // and combined with the upper 4 bits of PC + 4 uint32_t pc_upper = (inst.address + 4) & 0xF0000000; return pc_upper | (inst.target << 2); } return 0; } } // namespace ps2recomp