feat: better decode and code gen (remove some old instruction)

This commit is contained in:
Ran-j
2025-04-24 12:04:56 -03:00
parent 2bedfdb0fd
commit 70f672cfd8
6 changed files with 2182 additions and 2555 deletions
+41 -23
View File
@@ -28,48 +28,66 @@ namespace ps2recomp
std::string translateVUInstruction(const Instruction &inst);
std::string translateFPUInstruction(const Instruction &inst);
std::string translateCOP0Instruction(const Instruction &inst);
std::string translateRegimmInstruction(const Instruction &inst);
std::string translateSpecialInstruction(const Instruction &inst);
// MMI instruction translations
// MMI Translation functions
std::string translateMMI0Instruction(const Instruction &inst);
std::string translateMMI1Instruction(const Instruction &inst);
std::string translateMMI2Instruction(const Instruction &inst);
std::string translateMMI3Instruction(const Instruction &inst);
std::string translatePMFHLInstruction(const Instruction &inst);
std::string translatePMTHLInstruction(const Instruction &inst);
// Instruction Helpers
std::string translateQFSRV(const Instruction &inst);
std::string translatePCPYLD(const Instruction &inst);
std::string translatePCPYUD(const Instruction &inst);
std::string translatePMADDW(const Instruction &inst);
std::string translatePDIVW(const Instruction &inst);
std::string translatePCPYLD(const Instruction &inst);
std::string translatePMADDH(const Instruction &inst);
std::string translatePHMADH(const Instruction &inst);
std::string translatePMULTH(const Instruction &inst);
std::string translatePDIVW(const Instruction &inst);
std::string translatePDIVBW(const Instruction &inst);
std::string translatePEXEH(const Instruction &inst);
std::string translatePREVH(const Instruction &inst);
std::string translatePMULTH(const Instruction &inst);
std::string translatePDIVBW(const Instruction &inst);
std::string translatePEXEW(const Instruction &inst);
std::string translatePROT3W(const Instruction &inst);
std::string translatePMULTUW(const Instruction &inst);
std::string translatePDIVUW(const Instruction &inst);
std::string translatePCPYUD(const Instruction &inst);
std::string translatePEXCH(const Instruction &inst);
std::string translatePCPYH(const Instruction &inst);
std::string translatePEXCW(const Instruction &inst);
std::string translatePMTHI(const Instruction &inst);
std::string translatePMTLO(const Instruction &inst);
// SPECIAL instructions
std::string translateSYNC(const Instruction &inst);
std::string translateEI(const Instruction &inst);
std::string translateDI(const Instruction &inst);
std::string translateDSLL(const Instruction &inst);
std::string translateDSRL(const Instruction &inst);
std::string translateDSRA(const Instruction &inst);
std::string translateDSLLV(const Instruction &inst);
std::string translateDSRLV(const Instruction &inst);
std::string translateDSRAV(const Instruction &inst);
std::string translateDSLL32(const Instruction &inst);
std::string translateDSRL32(const Instruction &inst);
std::string translateDSRA32(const Instruction &inst);
std::string translateDADD(const Instruction &inst);
std::string translateDADDU(const Instruction &inst);
std::string translateDSUB(const Instruction &inst);
std::string translateDSUBU(const Instruction &inst);
// VU instruction translations
std::string translateVU_VADD_Field(const Instruction &inst);
std::string translateVU_VSUB_Field(const Instruction &inst);
std::string translateVU_VMUL_Field(const Instruction &inst);
std::string translateVU_VADD(const Instruction &inst);
std::string translateVU_VSUB(const Instruction &inst);
std::string translateVU_VMUL(const Instruction &inst);
std::string translateVU_VDIV(const Instruction &inst);
std::string translateVU_VSQRT(const Instruction &inst);
std::string translateVU_VRSQRT(const Instruction &inst);
std::string translateVU_VMTIR(const Instruction &inst);
std::string translateVU_VMFIR(const Instruction &inst);
std::string translateVU_VILWR(const Instruction &inst);
std::string translateVU_VISWR(const Instruction &inst);
std::string translateVU_VIADD(const Instruction &inst);
std::string translateVU_VISUB(const Instruction &inst);
std::string translateVU_VIADDI(const Instruction &inst);
std::string translateVU_VIAND(const Instruction &inst);
std::string translateVU_VIOR(const Instruction &inst);
std::string translateVU_VCALLMS(const Instruction &inst);
std::string translateVU_VCALLMSR(const Instruction &inst);
std::string translateVU_VRNEXT(const Instruction &inst);
std::string translateVU_VRGET(const Instruction &inst);
std::string translateVU_VRINIT(const Instruction &inst);
std::string translateVU_VRXOR(const Instruction &inst);
//
std::string generateJumpTableSwitch(const Instruction &inst, uint32_t tableAddress,
const std::vector<JumpTableEntry> &entries);
+556 -318
View File
@@ -8,183 +8,221 @@ namespace ps2recomp
// Basic MIPS opcodes (shared with R4300i)
enum MipsOpcodes
{
OPCODE_SPECIAL = 0x00,
OPCODE_REGIMM = 0x01,
OPCODE_J = 0x02,
OPCODE_JAL = 0x03,
OPCODE_BEQ = 0x04,
OPCODE_BNE = 0x05,
OPCODE_BLEZ = 0x06,
OPCODE_BGTZ = 0x07,
OPCODE_ADDI = 0x08,
OPCODE_ADDIU = 0x09,
OPCODE_SLTI = 0x0A,
OPCODE_SLTIU = 0x0B,
OPCODE_ANDI = 0x0C,
OPCODE_ORI = 0x0D,
OPCODE_XORI = 0x0E,
OPCODE_LUI = 0x0F,
OPCODE_COP0 = 0x10,
OPCODE_COP1 = 0x11,
OPCODE_COP2 = 0x12, // VU0 macro instructions
OPCODE_SPECIAL = 0x00, // Special instructions group (see SpecialFunctions)
OPCODE_REGIMM = 0x01, // RegImm instructions group (see RegimmFunctions)
OPCODE_J = 0x02, // Jump
OPCODE_JAL = 0x03, // Jump and Link
OPCODE_BEQ = 0x04, // Branch on Equal
OPCODE_BNE = 0x05, // Branch on Not Equal
OPCODE_BLEZ = 0x06, // Branch on Less Than or Equal to Zero
OPCODE_BGTZ = 0x07, // Branch on Greater Than Zero
OPCODE_ADDI = 0x08, // Add Immediate Word
OPCODE_ADDIU = 0x09, // Add Immediate Unsigned Word
OPCODE_SLTI = 0x0A, // Set on Less Than Immediate
OPCODE_SLTIU = 0x0B, // Set on Less Than Immediate Unsigned
OPCODE_ANDI = 0x0C, // AND Immediate
OPCODE_ORI = 0x0D, // OR Immediate
OPCODE_XORI = 0x0E, // XOR Immediate
OPCODE_LUI = 0x0F, // Load Upper Immediate
OPCODE_COP0 = 0x10, // Coprocessor 0 instructions (see Cop0Format)
OPCODE_COP1 = 0x11, // Coprocessor 1 (FPU) instructions (see Cop1Format)
OPCODE_COP2 = 0x12, // Coprocessor 2 (VU0 Macro) instructions (see Cop2Format)
OPCODE_COP3 = 0x13, // Unused on PS2
OPCODE_BEQL = 0x14,
OPCODE_BNEL = 0x15,
OPCODE_BLEZL = 0x16,
OPCODE_BGTZL = 0x17,
OPCODE_DADDI = 0x18,
OPCODE_DADDIU = 0x19,
OPCODE_LDL = 0x1A,
OPCODE_LDR = 0x1B,
OPCODE_MMI = 0x1C, // PS2 specific multimedia instructions
OPCODE_LQ = 0x1E, // PS2 specific 128-bit load
OPCODE_SQ = 0x1F, // PS2 specific 128-bit store
OPCODE_LB = 0x20,
OPCODE_LH = 0x21,
OPCODE_LWL = 0x22,
OPCODE_LW = 0x23,
OPCODE_LBU = 0x24,
OPCODE_LHU = 0x25,
OPCODE_LWR = 0x26,
OPCODE_LWU = 0x27,
OPCODE_SB = 0x28,
OPCODE_SH = 0x29,
OPCODE_SWL = 0x2A,
OPCODE_SW = 0x2B,
OPCODE_SDL = 0x2C,
OPCODE_SDR = 0x2D,
OPCODE_SWR = 0x2E,
OPCODE_CACHE = 0x2F,
OPCODE_LL = 0x30,
OPCODE_LWC1 = 0x31,
OPCODE_LWC2 = 0x32,
OPCODE_PREF = 0x33,
OPCODE_LLD = 0x34,
OPCODE_LDC1 = 0x35,
OPCODE_LDC2 = 0x36,
OPCODE_LD = 0x37,
OPCODE_SC = 0x38,
OPCODE_SWC1 = 0x39,
OPCODE_SWC2 = 0x3A,
OPCODE_SCD = 0x3C,
OPCODE_SDC1 = 0x3D,
OPCODE_SDC2 = 0x3E,
OPCODE_SD = 0x3F,
OPCODE_LQC2 = 0x36,
OPCODE_SQC2 = 0x3E
OPCODE_BEQL = 0x14, // Branch on Equal Likely
OPCODE_BNEL = 0x15, // Branch on Not Equal Likely
OPCODE_BLEZL = 0x16, // Branch on Less Than or Equal to Zero Likely
OPCODE_BGTZL = 0x17, // Branch on Greater Than Zero Likely
OPCODE_DADDI = 0x18, // Doubleword Add Immediate
OPCODE_DADDIU = 0x19, // Doubleword Add Immediate Unsigned
OPCODE_LDL = 0x1A, // Load Doubleword Left
OPCODE_LDR = 0x1B, // Load Doubleword Right
OPCODE_MMI = 0x1C, // PS2 specific MMI instructions group (see MMIFunctions)
OPCODE_LQ = 0x1E, // PS2 specific 128-bit load
OPCODE_SQ = 0x1F, // PS2 specific 128-bit store
OPCODE_LB = 0x20, // Load Byte
OPCODE_LH = 0x21, // Load Halfword
OPCODE_LWL = 0x22, // Load Word Left
OPCODE_LW = 0x23, // Load Word
OPCODE_LBU = 0x24, // Load Byte Unsigned
OPCODE_LHU = 0x25, // Load Halfword Unsigned
OPCODE_LWR = 0x26, // Load Word Right
OPCODE_LWU = 0x27, // Load Word Unsigned
OPCODE_SB = 0x28, // Store Byte
OPCODE_SH = 0x29, // Store Halfword
OPCODE_SWL = 0x2A, // Store Word Left
OPCODE_SW = 0x2B, // Store Word
OPCODE_SDL = 0x2C, // Store Doubleword Left
OPCODE_SDR = 0x2D, // Store Doubleword Right
OPCODE_SWR = 0x2E, // Store Word Right
OPCODE_CACHE = 0x2F, // Cache Operation
OPCODE_LL = 0x30, // LL - Load Linked Word, maybe omitted/unused
OPCODE_LWC1 = 0x31, // Load Word to Coprocessor 1 (FPU)
OPCODE_LWC2 = 0x32, // Load Word to Coprocessor 2, maybe omitted/unused
OPCODE_PREF = 0x33, // Prefetch
OPCODE_LLD = 0x34, // Load Linked Doubleword, maybe omitted/unused
OPCODE_LDC1 = 0x35, // Load Doubleword to Coprocessor 1, FPU is single-precision
OPCODE_LDC2 = 0x36, // Load Quadword to Coprocessor 2 (VU0) - Overrides standard MIPS LDC2
OPCODE_LD = 0x37, // Load Doubleword
OPCODE_SC = 0x38, // Store Conditional Word, maybe omitted/unused?
OPCODE_SWC1 = 0x39, // Store Word from Coprocessor 1 (FPU)
OPCODE_SWC2 = 0x3A, // SWC2 - Store Word from Coprocessor 2, maybe omitted/unused
OPCODE_SCD = 0x3C, // SCD - Store Conditional Doubleword, maybe omitted/unused?
OPCODE_SDC1 = 0x3D, // SDC1 - Store Doubleword from Coprocessor 1, FPU is single-precision
OPCODE_SDC2 = 0x3E, // PS2 specific Store Quadword from Coprocessor 2 (VU0) - Overrides standard MIPS SDC2
OPCODE_SD = 0x3F, // Store Doubleword
//OPCODE_LQC2 = 0x36,
//OPCODE_SQC2 = 0x3E
};
// SPECIAL function codes
// SPECIAL Function (bits 5-0) for OPCODE_SPECIAL
enum SpecialFunctions
{
SPECIAL_SLL = 0x00,
SPECIAL_SRL = 0x02,
SPECIAL_SRA = 0x03,
SPECIAL_SLLV = 0x04,
SPECIAL_SRLV = 0x06,
SPECIAL_SRAV = 0x07,
SPECIAL_JR = 0x08,
SPECIAL_JALR = 0x09,
SPECIAL_MOVZ = 0x0A,
SPECIAL_MOVN = 0x0B,
SPECIAL_SYSCALL = 0x0C,
SPECIAL_BREAK = 0x0D,
SPECIAL_SYNC = 0x0F,
SPECIAL_MFHI = 0x10,
SPECIAL_MTHI = 0x11,
SPECIAL_MFLO = 0x12,
SPECIAL_MTLO = 0x13,
SPECIAL_DSLLV = 0x14,
SPECIAL_DSRLV = 0x16,
SPECIAL_DSRAV = 0x17,
SPECIAL_MULT = 0x18,
SPECIAL_MULTU = 0x19,
SPECIAL_DIV = 0x1A,
SPECIAL_DIVU = 0x1B,
SPECIAL_ADD = 0x20,
SPECIAL_ADDU = 0x21,
SPECIAL_SUB = 0x22,
SPECIAL_SUBU = 0x23,
SPECIAL_AND = 0x24,
SPECIAL_OR = 0x25,
SPECIAL_XOR = 0x26,
SPECIAL_NOR = 0x27,
SPECIAL_MFSA = 0x28,
SPECIAL_MTSA = 0x29,
SPECIAL_SLT = 0x2A,
SPECIAL_SLTU = 0x2B,
SPECIAL_DADD = 0x2C,
SPECIAL_DADDU = 0x2D,
SPECIAL_DSUB = 0x2E,
SPECIAL_DSUBU = 0x2F,
SPECIAL_TGE = 0x30,
SPECIAL_TGEU = 0x31,
SPECIAL_TLT = 0x32,
SPECIAL_TLTU = 0x33,
SPECIAL_TEQ = 0x34,
SPECIAL_TNE = 0x36,
SPECIAL_DSLL = 0x38,
SPECIAL_DSRL = 0x3A,
SPECIAL_DSRA = 0x3B,
SPECIAL_DSLL32 = 0x3C,
SPECIAL_DSRL32 = 0x3E,
SPECIAL_DSRA32 = 0x3F
SPECIAL_SLL = 0x00, // Shift Word Left Logical
SPECIAL_SRL = 0x02, // Shift Word Right Logical
SPECIAL_SRA = 0x03, // Shift Word Right Arithmetic
SPECIAL_SLLV = 0x04, // Shift Word Left Logical Variable
SPECIAL_SRLV = 0x06, // Shift Word Right Logical Variable
SPECIAL_SRAV = 0x07, // Shift Word Right Arithmetic Variable
SPECIAL_JR = 0x08, // Jump Register
SPECIAL_JALR = 0x09, // Jump and Link Register
SPECIAL_MOVZ = 0x0A, // Move Conditional on Zero
SPECIAL_MOVN = 0x0B, // Move Conditional on Not Zero
SPECIAL_SYSCALL = 0x0C, // System Call
SPECIAL_BREAK = 0x0D, // Breakpoint
SPECIAL_SYNC = 0x0F, // Synchronize Shared Memory
SPECIAL_MFHI = 0x10, // Move From HI Register
SPECIAL_MTHI = 0x11, // Move To HI Register
SPECIAL_MFLO = 0x12, // Move From LO Register
SPECIAL_MTLO = 0x13, // Move To LO Register
SPECIAL_DSLLV = 0x14, // Doubleword Shift Left Logical Variable
SPECIAL_DSRLV = 0x16, // Doubleword Shift Right Logical Variable
SPECIAL_DSRAV = 0x17, // Doubleword Shift Right Arithmetic Variable
SPECIAL_MULT = 0x18, // Multiply Word
SPECIAL_MULTU = 0x19, // Multiply Unsigned Word
SPECIAL_DIV = 0x1A, // Divide Word
SPECIAL_DIVU = 0x1B, // Divide Unsigned Word
SPECIAL_ADD = 0x20, // Add Word
SPECIAL_ADDU = 0x21, // Add Unsigned Word
SPECIAL_SUB = 0x22, // Subtract Word
SPECIAL_SUBU = 0x23, // Subtract Unsigned Word
SPECIAL_AND = 0x24, // AND
SPECIAL_OR = 0x25, // OR
SPECIAL_XOR = 0x26, // XOR
SPECIAL_NOR = 0x27, // NOR
SPECIAL_MFSA = 0x28, // Move From SA Register (PS2 specific)
SPECIAL_MTSA = 0x29, // Move To SA Register (PS2 specific)
SPECIAL_SLT = 0x2A, // Set on Less Than
SPECIAL_SLTU = 0x2B, // Set on Less Than Unsigned
SPECIAL_DADD = 0x2C, // Doubleword Add
SPECIAL_DADDU = 0x2D, // Doubleword Add Unsigned
SPECIAL_DSUB = 0x2E, // Doubleword Subtract
SPECIAL_DSUBU = 0x2F, // Doubleword Subtract Unsigned
SPECIAL_TGE = 0x30, // Trap if Greater or Equal
SPECIAL_TGEU = 0x31, // Trap if Greater or Equal Unsigned
SPECIAL_TLT = 0x32, // Trap if Less Than
SPECIAL_TLTU = 0x33, // Trap if Less Than Unsigned
SPECIAL_TEQ = 0x34, // Trap if Equal
SPECIAL_TNE = 0x36, // Trap if Not Equal
SPECIAL_DSLL = 0x38, // Doubleword Shift Left Logical
SPECIAL_DSRL = 0x3A, // Doubleword Shift Right Logical
SPECIAL_DSRA = 0x3B, // Doubleword Shift Right Arithmetic
SPECIAL_DSLL32 = 0x3C, // Doubleword Shift Left Logical +32
SPECIAL_DSRL32 = 0x3E, // Doubleword Shift Right Logical +32
SPECIAL_DSRA32 = 0x3F, // Doubleword Shift Right Arithmetic +32
};
// REGIMM function codes
// REGIMM RT Field (bits 20-16) for OPCODE_REGIMM
enum RegimmFunctions
{
REGIMM_BLTZ = 0x00,
REGIMM_BGEZ = 0x01,
REGIMM_BLTZL = 0x02,
REGIMM_BGEZL = 0x03,
REGIMM_TGEI = 0x08,
REGIMM_TGEIU = 0x09,
REGIMM_TLTI = 0x0A,
REGIMM_TLTIU = 0x0B,
REGIMM_TEQI = 0x0C,
REGIMM_TNEI = 0x0E,
REGIMM_BLTZAL = 0x10,
REGIMM_BGEZAL = 0x11,
REGIMM_BLTZALL = 0x12,
REGIMM_BGEZALL = 0x13,
REGIMM_MTSAB = 0x18,
REGIMM_MTSAH = 0x19
REGIMM_BLTZ = 0x00, // Branch on Less Than Zero
REGIMM_BGEZ = 0x01, // Branch on Greater Than or Equal to Zero
REGIMM_BLTZL = 0x02, // Branch on Less Than Zero Likely
REGIMM_BGEZL = 0x03, // Branch on Greater Than or Equal to Zero Likely
REGIMM_TGEI = 0x08, // Trap if Greater or Equal Immediate
REGIMM_TGEIU = 0x09, // Trap if Greater or Equal Immediate Unsigned
REGIMM_TLTI = 0x0A, // Trap if Less Than Immediate
REGIMM_TLTIU = 0x0B, // Trap if Less Than Immediate Unsigned
REGIMM_TEQI = 0x0C, // Trap if Equal Immediate
REGIMM_TNEI = 0x0E, // Trap if Not Equal Immediate
REGIMM_BLTZAL = 0x10, // Branch on Less Than Zero and Link
REGIMM_BGEZAL = 0x11, // Branch on Greater Than or Equal to Zero and Link
REGIMM_BLTZALL = 0x12, // Branch on Less Than Zero and Link Likely
REGIMM_BGEZALL = 0x13, // Branch on Greater Than or Equal to Zero and Link Likely
REGIMM_MTSAB = 0x18, // Move To SA Register Byte (PS2 specific)
REGIMM_MTSAH = 0x19, // Move To SA Register Halfword (PS2 specific)
};
// PS2-specific MMI function codes
// MMI Function Field (bits 5-0) for OPCODE_MMI (0x1C)
enum MMIFunctions
{
MMI_MADD = 0x00,
MMI_MADDU = 0x01,
MMI_PLZCW = 0x04,
MMI_MMI0 = 0x08,
MMI_MMI2 = 0x09,
MMI_MFHI1 = 0x10,
MMI_MTHI1 = 0x11,
MMI_MFLO1 = 0x12,
MMI_MTLO1 = 0x13,
MMI_MULT1 = 0x18,
MMI_MULTU1 = 0x19,
MMI_DIV1 = 0x1A,
MMI_DIVU1 = 0x1B,
MMI_MADD1 = 0x20,
MMI_MADDU1 = 0x21,
MMI_MMI1 = 0x28,
MMI_MMI3 = 0x29,
MMI_PMFHL = 0x30,
MMI_PMTHL = 0x31,
MMI_PSLLH = 0x34,
MMI_PSRLH = 0x36,
MMI_PSRAH = 0x37,
MMI_PSLLW = 0x3C,
MMI_PSRLW = 0x3E,
MMI_PSRAW = 0x3F,
MMI_MSUB = 0x02,
MMI_MSUBU = 0x03
MMI_MADD = 0x00, // Multiply Add Word (to LO/HI)
MMI_MADDU = 0x01, // Multiply Add Unsigned Word (to LO/HI)
MMI_MSUB = 0x02, // Multiply Subtract Word (Not listed in provided doc table, but valid MMI)
MMI_MSUBU = 0x03, // Multiply Subtract Unsigned Word (Not listed in provided doc table, but valid MMI)
MMI_PLZCW = 0x04, // Parallel Leading Zero/One Count Word
MMI_MMI0 = 0x08, // Group MMI0 instructions (see MMI0Functions)
MMI_MMI2 = 0x09, // Group MMI2 instructions (see MMI2Functions)
MMI_MFHI1 = 0x10, // Move From HI1 Register
MMI_MTHI1 = 0x11, // Move To HI1 Register
MMI_MFLO1 = 0x12, // Move From LO1 Register
MMI_MTLO1 = 0x13, // Move To LO1 Register
MMI_MULT1 = 0x18, // Multiply Word to LO1/HI1
MMI_MULTU1 = 0x19, // Multiply Unsigned Word to LO1/HI1
MMI_DIV1 = 0x1A, // Divide Word using LO1/HI1
MMI_DIVU1 = 0x1B, // Divide Unsigned Word using LO1/HI1
MMI_MADD1 = 0x20, // Multiply Add Word to LO1/HI1
MMI_MADDU1 = 0x21, // Multiply Add Unsigned Word to LO1/HI1
MMI_MMI1 = 0x28, // Group MMI1 instructions (see MMI1Functions)
MMI_MMI3 = 0x29, // Group MMI3 instructions (see MMI3Functions)
MMI_PMFHL = 0x30, // Parallel Move From HI/LO Register (see PMFHLFunctions for 'sa' field)
MMI_PMTHL = 0x31, // Parallel Move To HI/LO Register (see PMFHLFunctions for 'sa' field)
MMI_PSLLH = 0x34, // Parallel Shift Left Logical Halfword
MMI_PSRLH = 0x36, // Parallel Shift Right Logical Halfword
MMI_PSRAH = 0x37, // Parallel Shift Right Arithmetic Halfword
MMI_PSLLW = 0x3C, // Parallel Shift Left Logical Word
MMI_PSRLW = 0x3E, // Parallel Shift Right Logical Word
MMI_PSRAW = 0x3F // Parallel Shift Right Arithmetic Word
};
// PS2-specific MMI0 function codes
// PS2-specific MMI0 Sub-Function Field (bits 0-5 within MMI_MMI0 group)
enum MMI0Functions
{
MMI0_PADDW = 0x00,
@@ -214,7 +252,7 @@ namespace ps2recomp
MMI0_PPAC5 = 0x1F
};
// PS2-specific MMI1 function codes
// PS2-specific MMI1 Sub-Function Field (bits 0-5 within MMI_MMI1 group)
enum MMI1Functions
{
MMI1_PABSW = 0x01,
@@ -237,7 +275,7 @@ namespace ps2recomp
MMI1_QFSRV = 0x1B
};
// PS2-specific MMI2 function codes
// PS2-specific MMI2 Sub-Function Field (bits 0-5 within MMI_MMI2 group)
enum MMI2Functions
{
MMI2_PMADDW = 0x00,
@@ -248,14 +286,12 @@ namespace ps2recomp
MMI2_PMFLO = 0x09,
MMI2_PINTH = 0x0A,
MMI2_PMULTW = 0x0C,
MMI2_PDIVW = 0x0D,
MMI2_PDIVW = 0x0D,
MMI2_PCPYLD = 0x0E,
MMI2_PAND = 0x12,
MMI2_PXOR = 0x13,
MMI2_PMADDH = 0x14,
MMI2_PHMADH = 0x15,
MMI2_PAND_ = 0x16,
MMI2_PXOR_ = 0x17,
MMI2_PMSUBH = 0x18,
MMI2_PHMSBH = 0x19,
MMI2_PEXEH = 0x1A,
@@ -266,11 +302,13 @@ namespace ps2recomp
MMI2_PROT3W = 0x1F
};
// PS2-specific MMI3 function codes
// PS2-specific MMI3 Sub-Function Field (bits 0-5 within MMI_MMI3 group)
enum MMI3Functions
{
MMI3_PMADDUW = 0x00,
MMI3_PSRAVW = 0x03,
MMI3_PMTHI = 0x08, // Move To HI register
MMI3_PMTLO = 0x09, // Move To LO register
MMI3_PINTEH = 0x0A,
MMI3_PMULTUW = 0x0C,
MMI3_PDIVUW = 0x0D,
@@ -279,195 +317,382 @@ namespace ps2recomp
MMI3_PNOR = 0x13,
MMI3_PEXCH = 0x1A,
MMI3_PCPYH = 0x1B,
MMI3_PEXCW = 0x1E,
MMI3_PMTHI = 0x08, // Move To HI register
MMI3_PMTLO = 0x09 // Move To LO register
MMI3_PEXCW = 0x1E
};
// COP0 (rs field)
// PMFHL/PMTHL Sub-Function Field ('sa' field, bits 10-6)
enum PMFHLFunctions
{
PMFHL_LW = 0x00, // Load Word / Lower Word
PMFHL_UW = 0x01, // Upper Word
PMFHL_SLW = 0x02, // Signed Lower Word
PMFHL_LH = 0x03, // Load Halfword / Lower Halfword
PMFHL_SH = 0x04 // Store Halfword / Signed Upper Halfword? (Doc name varies)
};
// COP0 Format Field ('fmt' or 'rs' field, bits 25-21) for OPCODE_COP0
enum COP0Format
{
COP0_MF = 0x00, // Move From COP0
COP0_MT = 0x04, // Move To COP0
COP0_CO = 0x10 // COP0 operation
COP0_MF = 0x00, // Move From COP0 - MFC0 (fmt=00000)
COP0_MT = 0x04, // Move To COP0 - MTC0 (fmt=00100)
COP0_BC = 0x08, // BC0 group (fmt=01000) (see Cop0BranchCondition)
COP0_CO = 0x10 // COP0 Operation group (fmt=10000) (see Cop0CoFunctions)
};
// COP0 CO (COProcessor) function codes
// COP0 CO Function Field (bits 5-0) for COP0_CO Format
enum Cop0CoFunctions
{
COP0_CO_TLBR = 0x01, // TLB Read
COP0_CO_TLBWI = 0x02, // TLB Write Indexed
COP0_CO_TLBWR = 0x06, // TLB Write Random
COP0_CO_TLBP = 0x08, // TLB Probe
COP0_CO_ERET = 0x18, // Return from Exception
COP0_CO_EI = 0x38, // Enable Interrupts
COP0_CO_DI = 0x39 // Disable Interrupts
COP0_CO_TLBP = 0x08, // TLB Probe
COP0_CO_ERET = 0x18, // Return from Exception
COP0_CO_EI = 0x38, // Enable Interrupts
COP0_CO_DI = 0x39 // Disable Interrupts
};
// COP0 BC Condition Field ('fmt' or 'rt' field, bits 20-16) for COP0_BC Format
enum Cop0BranchCondition
{
COP0_BC_BCF = 0x00, // Branch on Condition False
COP0_BC_BCT = 0x01, // Branch on Condition True
COP0_BC_BCFL = 0x02, // Branch on Condition False Likely
COP0_BC_BCTL = 0x03, // Branch on Condition True Likely
};
// COP0 Register Numbers (used with MFC0/MTC0)
enum COP0Reg
{
COP0_REG_INDEX = 0, // Index into TLB array
COP0_REG_RANDOM = 1, // Randomly generated index into TLB array
COP0_REG_ENTRYLO0 = 2, // Low half of TLB entry for even-numbered virtual pages
COP0_REG_ENTRYLO1 = 3, // Low half of TLB entry for odd-numbered virtual pages
COP0_REG_CONTEXT = 4, // TLB miss handler pointer
COP0_REG_PAGEMASK = 5, // TLB page size mask
COP0_REG_WIRED = 6, // Controls which TLB entries are affected by random replacement
COP0_REG_BADVADDR = 8, // Virtual address of most recent address-related exception
COP0_REG_COUNT = 9, // Timer count
COP0_REG_ENTRYHI = 10, // High half of TLB entry
COP0_REG_COMPARE = 11, // Timer compare value
COP0_REG_STATUS = 12, // Processor status and control
COP0_REG_CAUSE = 13, // Cause of last exception
COP0_REG_EPC = 14, // Exception program counter
COP0_REG_PRID = 15, // Processor identification and revision
COP0_REG_CONFIG = 16, // Configuration register
COP0_REG_INDEX = 0, // Index into TLB array
COP0_REG_RANDOM = 1, // Randomly generated index into TLB array
COP0_REG_ENTRYLO0 = 2, // Low half of TLB entry for even-numbered virtual pages
COP0_REG_ENTRYLO1 = 3, // Low half of TLB entry for odd-numbered virtual pages
COP0_REG_CONTEXT = 4, // Context
COP0_REG_PAGEMASK = 5, // TLB page size mask
COP0_REG_WIRED = 6, // Controls which TLB entries are affected by random replacement
COP0_REG_BADVADDR = 8, // Virtual address of most recent address-related exception
COP0_REG_COUNT = 9, // Timer count
COP0_REG_ENTRYHI = 10, // High half of TLB entry
COP0_REG_COMPARE = 11, // Timer compare value
COP0_REG_STATUS = 12, // Processor status and control
COP0_REG_CAUSE = 13, // Cause of last exception
COP0_REG_EPC = 14, // Exception program counter
COP0_REG_PRID = 15, // Processor identification and revision
COP0_REG_CONFIG = 16, // Configuration register
COP0_REG_BADPADDR = 23, // Bad physical address
COP0_REG_DEBUG = 24, // Debug register
COP0_REG_PERF = 25, // Performance counter
COP0_REG_TAGLO = 28, // Low bits of cache tag
COP0_REG_TAGHI = 29, // High bits of cache tag
COP0_REG_ERROREPC = 30 // Error exception program counter
COP0_REG_TAGLO = 28, // Cache TagLo (I-Cache & D-Cache)
COP0_REG_TAGHI = 29, // High bits of cache tag ( Cache TagHi )
COP0_REG_ERROREPC = 30 // Error exception program counter
};
// COP1 (FPU) function codes
// COP1 (FPU) Format Field ('fmt' or 'rs' field, bits 25-21) for OPCODE_COP1
enum Cop1Format
{
COP1_MF = 0x00, // Move From FPU Register
COP1_CF = 0x02, // Move From FPU Control Register
COP1_MT = 0x04, // Move To FPU Register
COP1_CT = 0x06, // Move To FPU Control Register
COP1_BC = 0x08, // Branch on FPU Condition
COP1_S = 0x10, // Single Precision Operation
COP1_W = 0x14, // Word (integer) Operation
COP1_BC_BCF = 0x00,
COP1_BC_BCT = 0x01,
COP1_L = 0x15, // Long (64-bit integer) Operation
COP1_D = 0x11, // Double Precision Operation (unused on PS2 FPU?)
COP1_BC = 0x08, // Branch on FPU Condition (see Cop1BranchCondition)
COP1_D = 0x11, // Standard MIPS Double format; EE FPU is single-precision, (unused on PS2 FPU?)
COP1_L = 0x15, // Long (64-bit integer) Operation (unused on PS2 FPU?)
COP1_S = 0x10, // Single Precision Operation (see Cop1FunctionsS)
COP1_W = 0x14 // Word (integer) Operation (see Cop1FunctionsW)
};
enum Cop1Functions
// COP1 Function Field (bits 5-0) for COP1_S Format (Single-Precision)
enum Cop1FunctionsS
{
COP1_FUNC_ADD = 0x00,
COP1_FUNC_SUB = 0x01,
COP1_FUNC_MUL = 0x02,
COP1_FUNC_DIV = 0x03,
COP1_FUNC_SQRT = 0x04,
COP1_FUNC_ABS = 0x05,
COP1_FUNC_MOV = 0x06,
COP1_FUNC_NEG = 0x07,
COP1_FUNC_ROUND_L = 0x08,
COP1_FUNC_TRUNC_L = 0x09,
COP1_FUNC_CEIL_L = 0x0A,
COP1_FUNC_FLOOR_L = 0x0B,
COP1_FUNC_ROUND_W = 0x0C,
COP1_FUNC_TRUNC_W = 0x0D,
COP1_FUNC_CEIL_W = 0x0E,
COP1_FUNC_FLOOR_W = 0x0F,
COP1_FUNC_CVT_S = 0x20, // Convert to Single
COP1_FUNC_CVT_D = 0x21, // Convert to Double
COP1_FUNC_CVT_W = 0x24, // Convert to Word
COP1_FUNC_CVT_L = 0x25, // Convert to Long
// Comparisons (lowest 5 bits matter for condition, C bit set in FCR31)
COP1_FUNC_C_F = 0x30, // False
COP1_FUNC_C_UN = 0x31, // Unordered
COP1_FUNC_C_EQ = 0x32, // Equal
COP1_FUNC_C_UEQ = 0x33, // Unordered or Equal
COP1_FUNC_C_OLT = 0x34, // Ordered Less Than
COP1_FUNC_C_ULT = 0x35, // Unordered or Less Than
COP1_FUNC_C_OLE = 0x36, // Ordered Less Than or Equal
COP1_FUNC_C_ULE = 0x37, // Unordered or Less Than or Equal
COP1_FUNC_C_SF = 0x38, // Signaling False
COP1_FUNC_C_NGLE = 0x39, // Not Greater or Less or Equal (Unordered)
COP1_FUNC_C_SEQ = 0x3A, // Signaling Equal
COP1_FUNC_C_NGL = 0x3B, // Not Greater or Less (Unordered or Equal)
COP1_FUNC_C_LT = 0x3C, // Signaling Less Than
COP1_FUNC_C_NGE = 0x3D, // Not Greater or Equal (Unordered or Less Than)
COP1_FUNC_C_LE = 0x3E, // Signaling Less Than or Equal
COP1_FUNC_C_NGT = 0x3F, // Not Greater Than (Unordered or Less Than or Equal)
COP1_S_ADD = 0x00, // ADD.S
COP1_S_SUB = 0x01, // SUB.S
COP1_S_MUL = 0x02, // MUL.S
COP1_S_DIV = 0x03, // DIV.S
COP1_S_SQRT = 0x04, // SQRT.S
COP1_S_ABS = 0x05, // ABS.S
COP1_S_MOV = 0x06, // MOV.S
COP1_S_NEG = 0x07, // NEG.S
COP1_S_ROUND_L = 0x08, // ROUND.L.S - Requires 64-bit int dest, likely unused
COP1_S_TRUNC_L = 0x09, // TRUNC.L.S - Requires 64-bit int dest, likely unused
COP1_S_CEIL_L = 0x0A, // CEIL.L.S - Requires 64-bit int dest, likely unused
COP1_S_FLOOR_L = 0x0B, // FLOOR.L.S - Requires 64-bit int dest, likely unused
COP1_S_ROUND_W = 0x0C, // ROUND.W.S
COP1_S_TRUNC_W = 0x0D, // TRUNC.W.S
COP1_S_CEIL_W = 0x0E, // CEIL.W.S
COP1_S_FLOOR_W = 0x0F, // FLOOR.W.S
// --- Additional Arithmetic/Functions (from FPU.S table) ---
COP1_S_RSQRT = 0x16, // RSQRT.S (Reciprocal Square Root)
COP1_S_ADDA = 0x18, // ADDA.S (Add Accumulator)
COP1_S_SUBA = 0x19, // SUBA.S (Subtract Accumulator)
COP1_S_MULA = 0x1A, // MULA.S (Multiply Accumulator)
COP1_S_MADD = 0x1C, // MADD.S (Multiply Add)
COP1_S_MSUB = 0x1D, // MSUB.S (Multiply Subtract)
COP1_S_MADDA = 0x1E, // MADDA.S (Multiply Add Accumulator)
COP1_S_MSUBA = 0x1F, // MSUBA.S (Multiply Subtract Accumulator)
// --- Conversions (from FPU.S table) ---
COP1_S_CVT_D = 0x21, // CVT.D.S - Requires double-precision FPU
COP1_S_CVT_W = 0x24, // CVT.W.S (Convert to Word)
COP1_S_CVT_L = 0x25, // CVT.L.S - Requires 64-bit int dest, likely unused
// --- Min/Max (from FPU.S table) ---
COP1_S_MAX = 0x28, // MAX.S
COP1_S_MIN = 0x29, // MIN.S
COP1_S_C_F = 0x30, // C.F.S (False)
COP1_S_C_UN = 0x31, // C.UN.S (Unordered)
COP1_S_C_EQ = 0x32, // C.EQ.S (Equal)
COP1_S_C_UEQ = 0x33, // C.UEQ.S (Unordered or Equal)
COP1_S_C_OLT = 0x34, // C.OLT.S (Ordered Less Than)
COP1_S_C_ULT = 0x35, // C.ULT.S (Unordered or Less Than)
COP1_S_C_OLE = 0x36, // C.OLE.S (Ordered Less Than or Equal)
COP1_S_C_ULE = 0x37, // C.ULE.S (Unordered or Less Than or Equal)
COP1_S_C_SF = 0x38, // C.SF.S (Signaling False)
COP1_S_C_NGLE = 0x39, // C.NGLE.S (Not Greater or Less or Equal - Unordered)
COP1_S_C_SEQ = 0x3A, // C.SEQ.S (Signaling Equal)
COP1_S_C_NGL = 0x3B, // C.NGL.S (Not Greater or Less - Unordered or Equal)
COP1_S_C_LT = 0x3C, // C.LT.S (Signaling Less Than)
COP1_S_C_NGE = 0x3D, // C.NGE.S (Not Greater or Equal - Unordered or Less Than)
COP1_S_C_LE = 0x3E, // C.LE.S (Signaling Less Than or Equal)
COP1_S_C_NGT = 0x3F, // C.NGT.S (Not Greater Than - Unordered or Less Than or Equal)
};
// COP2 (VU0 macro) function codes
enum Cop2Functions
// COP1 Function Field (bits 5-0) for COP1_W Format (Word/Integer source)
enum Cop1FunctionsW
{
COP2_QMFC2 = 0x00, // Move From Coprocessor 2 (128-bit)
COP2_CFC2 = 0x02, // Move Control From Coprocessor 2
COP2_QMTC2 = 0x04, // Move To Coprocessor 2 (128-bit)
COP2_CTC2 = 0x06, // Move Control To Coprocessor 2
COP2_BC2 = 0x08, // Branch On Coprocessor 2 Condition
COP2_CO = 0x10, // COProcessor instructions (VU0 macro)
COP2_BCF = 0x00, // Branch on VU0 false
COP2_BCT = 0x01, // Branch on VU0 true
COP2_BCFL = 0x02, // Branch on VU0 false likely
COP2_BCTL = 0x03, // Branch on VU0 true likely
COP2_BCEF = 0x4, // Branch on VU0 equal flag false (new)
COP2_BCET = 0x5, // Branch on VU0 equal flag true (new)
COP2_BCEFL = 0x6, // Branch on VU0 equal flag false likely (new)
COP2_BCETL = 0x7, // Branch on VU0 equal flag true likely (new)
COP2_MFC2 = 0x02,
COP2_MTC2 = 0x0A,
COP2_BC2F = 0x11, // Branch on VU0 condition false
COP2_VU0OPS = 0x12, // VU0 Special Operations
COP2_MTVUCF = 0x13, // Move To VU0 control/flag register
COP2_CTCVU = 0x18, // Control To VU0 with specific functionality
COP2_VMTIR = 0x1C, // Move To VU0 I Register
COP2_VCLIP = 0x1E, // VU0 Clipping operation
COP2_VLDQ = 0x1F // VU0 Load/Store Quad with Decrement
COP1_W_CVT_S = 0x20, // CVT.S.W (Convert Word Integer to Single Float)
// 0x21 --- (Standard MIPS: CVT.D.W - requires double-precision)
// 0x24 --- (Standard MIPS: CVT.W.W - Nop?)
// 0x25 --- (Standard MIPS: CVT.L.W - requires 64-bit int dest)
};
// VU0 macro instruction function codes (subset - there are many more)
enum VU0MacroFunctions
// COP1 BC Condition Field ('fmt' or 'rt' field, bits 20-16) for COP1_BC Format
enum Cop1BranchCondition
{
VU0_VADD = 0x00,
VU0_VSUB = 0x01,
VU0_VMUL = 0x02,
VU0_VDIV = 0x03,
VU0_VSQRT = 0x04,
VU0_VRSQRT = 0x05,
VU0_VMULQ = 0x06,
VU0_VIADD = 0x10,
VU0_VISUB = 0x11,
VU0_VIADDI = 0x12,
VU0_VIAND = 0x13,
VU0_VIOR = 0x14,
VU0_VILWR = 0x15,
VU0_VISWR = 0x16,
VU0_VCALLMS = 0x20,
VU0_VCALLMSR = 0x21,
VU0_VRGET = 0x3F, // Get VU0 R register
VU0_VSUB_XYZ = 0x38 // Subtract with component selection
COP1_BC_BCF = 0x00, // Branch on FPU Condition False (BC1F)
COP1_BC_BCT = 0x01, // Branch on FPU Condition True (BC1T)
COP1_BC_BCFL = 0x02, // Branch on FPU Condition False Likely (BC1FL)
COP1_BC_BCTL = 0x03, // Branch on FPU Condition True Likely (BC1TL)
};
enum VU0SpecialFormats
// COP2 (VU0 Macro) Format Field ('fmt' or 'rs' field, bits 25-21) for OPCODE_COP2
enum Cop2Format
{
VU0_BC2F = 0x11, // Branch on VU0 condition false
VU0_MTVUCF = 0x13, // Move To VU0 control/flag register
VU0_CTCVU = 0x18, // Control To VU0 with specific functionality
VU0_VMTIR = 0x1C, // Move To VU0 I Register
VU0_VCLIP = 0x1E, // VU0 Clipping operation
VU0_VLDQ = 0x1F // VU0 Load/Store Quad with Decrement
// Note: Standard MIPS MFC2/MTC2 use fmt 0x00/0x04, EE uses QMFC2/QMTC2
COP2_QMFC2 = 0x01, // QMFC2 (fmt=00001) - Load Quadword From Coprocessor 2
COP2_CFC2 = 0x02, // CFC2 (fmt=00010) - Load Control Word From Coprocessor 2
COP2_QMTC2 = 0x05, // QMTC2 (fmt=00101) - Store Quadword To Coprocessor 2
COP2_CTC2 = 0x06, // CTC2 (fmt=00110) - Store Control Word To Coprocessor 2
COP2_BC = 0x08, // BC2 group (fmt=01000) (see Cop2BranchCondition)
COP2_CO = 0x10, // VU0 Macro Operation group (fmt=1xxxx)
};
// COP2 BC Condition Field ('fmt' or 'rt' field, bits 20-16) for COP2_BC Format
enum Cop2BranchCondition
{
COP2_BC_BCF = 0x00, // Branch on VU0 Condition False (BC2F)
COP2_BC_BCT = 0x01, // Branch on VU0 Condition True (BC2T)
COP2_BC_BCFL = 0x02, // Branch on VU0 Condition False Likely (BC2FL)
COP2_BC_BCTL = 0x03, // Branch on VU0 Condition True Likely (BC2TL)
};
// VU0 Macro Function Field (bits 5-0) for COP2_CO Format (Special1 Table)
enum VU0MacroSpecial1Functions : uint8_t
{
VU0_S1_VADDx = 0x00,
VU0_S1_VADDy = 0x01,
VU0_S1_VADDz = 0x02,
VU0_S1_VADDw = 0x03,
VU0_S1_VSUBx = 0x04,
VU0_S1_VSUBy = 0x05,
VU0_S1_VSUBz = 0x06,
VU0_S1_VSUBw = 0x07,
VU0_S1_VMADDx = 0x08,
VU0_S1_VMADDy = 0x09,
VU0_S1_VMADDz = 0x0A,
VU0_S1_VMADDw = 0x0B,
VU0_S1_VMSUBx = 0x0C,
VU0_S1_VMSUBy = 0x0D,
VU0_S1_VMSUBz = 0x0E,
VU0_S1_VMSUBw = 0x0F,
VU0_S1_VMAXx = 0x10,
VU0_S1_VMAXy = 0x11,
VU0_S1_VMAXz = 0x12,
VU0_S1_VMAXw = 0x13,
VU0_S1_VMINIx = 0x14,
VU0_S1_VMINIy = 0x15,
VU0_S1_VMINIz = 0x16,
VU0_S1_VMINIw = 0x17,
VU0_S1_VMULx = 0x18,
VU0_S1_VMULy = 0x19,
VU0_S1_VMULz = 0x1A,
VU0_S1_VMULw = 0x1B,
VU0_S1_VMULq = 0x1C,
VU0_S1_VMAXi = 0x1D,
VU0_S1_VMULi = 0x1E,
VU0_S1_VMINIi = 0x1F,
VU0_S1_VADDq = 0x20,
VU0_S1_VMADDq = 0x21,
VU0_S1_VADDi = 0x22,
VU0_S1_VMADDi = 0x23,
VU0_S1_VSUBq = 0x24,
VU0_S1_VMSUBq = 0x25,
VU0_S1_VSUBi = 0x26,
VU0_S1_VMSUBi = 0x27,
VU0_S1_VADD = 0x28,
VU0_S1_VMADD = 0x29,
VU0_S1_VMUL = 0x2A,
VU0_S1_VMAX = 0x2B,
VU0_S1_VSUB = 0x2C,
VU0_S1_VMSUB = 0x2D,
VU0_S1_VOPMSUB = 0x2E,
VU0_S1_VMINI = 0x2F,
VU0_S1_VIADD = 0x30,
VU0_S1_VISUB = 0x31,
VU0_S1_VIADDI = 0x32,
VU0_S1_VIAND = 0x34,
VU0_S1_VIOR = 0x35,
VU0_S1_VCALLMS = 0x38,
VU0_S1_VCALLMSR = 0x39,
};
// VU0 Macro Function Field (bits 5-0) for COP2_CO Format (Special2 Table)
enum VU0MacroSpecial2Functions : uint8_t
{
VU0_S2_VADDAx = 0x00,
VU0_S2_VADDAy = 0x01,
VU0_S2_VADDAz = 0x02,
VU0_S2_VADDAw = 0x03,
VU0_S2_VSUBAx = 0x04,
VU0_S2_VSUBAy = 0x05,
VU0_S2_VSUBAz = 0x06,
VU0_S2_VSUBAw = 0x07,
VU0_S2_VMADDAx = 0x08,
VU0_S2_VMADDAy = 0x09,
VU0_S2_VMADDAz = 0x0A,
VU0_S2_VMADDAw = 0x0B,
VU0_S2_VMSUBAx = 0x0C,
VU0_S2_VMSUBAy = 0x0D,
VU0_S2_VMSUBAz = 0x0E,
VU0_S2_VMSUBAw = 0x0F,
VU0_S2_VITOF0 = 0x10,
VU0_S2_VITOF4 = 0x11,
VU0_S2_VITOF12 = 0x12,
VU0_S2_VITOF15 = 0x13,
VU0_S2_VFTOI0 = 0x14,
VU0_S2_VFTOI4 = 0x15,
VU0_S2_VFTOI12 = 0x16,
VU0_S2_VFTOI15 = 0x17,
VU0_S2_VMULAx = 0x18,
VU0_S2_VMULAy = 0x19,
VU0_S2_VMULAz = 0x1A,
VU0_S2_VMULAw = 0x1B,
VU0_S2_VMULAq = 0x1C,
VU0_S2_VABS = 0x1D,
VU0_S2_VMULAi = 0x1E,
VU0_S2_VCLIPw = 0x1F,
VU0_S2_VADDAq = 0x20,
VU0_S2_VMADDAq = 0x21,
VU0_S2_VADDAi = 0x22,
VU0_S2_VMADDAi = 0x23,
VU0_S2_VSUBAq = 0x24,
VU0_S2_VMSUBAq = 0x25,
VU0_S2_VSUBAi = 0x26,
VU0_S2_VMSUBAi = 0x27,
VU0_S2_VADDA = 0x28,
VU0_S2_VMADDA = 0x29,
VU0_S2_VMULA = 0x2A,
VU0_S2_VSUBA = 0x2C,
VU0_S2_VMSUBA = 0x2D,
VU0_S2_VOPMULA = 0x2E,
VU0_S2_VNOP = 0x2F,
VU0_S2_VMOVE = 0x30,
VU0_S2_VMR32 = 0x31,
VU0_S2_VLQI = 0x34,
VU0_S2_VSQI = 0x35,
VU0_S2_VLQD = 0x36,
VU0_S2_VSQD = 0x37,
VU0_S2_VDIV = 0x38,
VU0_S2_VSQRT = 0x39,
VU0_S2_VRSQRT = 0x3A,
VU0_S2_VWAITQ = 0x3B,
VU0_S2_VMTIR = 0x3C,
VU0_S2_VMFIR = 0x3D,
VU0_S2_VILWR = 0x3E,
VU0_S2_VISWR = 0x3F,
VU0_S2_VRNEXT = 0x40,
VU0_S2_VRGET = 0x41,
VU0_S2_VRINIT = 0x42,
VU0_S2_VRXOR = 0x43
};
// // VU0 macro instruction function codes (subset - there are many more)
// enum VU0MacroFunctions
// {
// VU0_VADD = 0x00,
// VU0_VSUB = 0x01,
// VU0_VMUL = 0x02,
// VU0_VDIV = 0x03,
// VU0_VSQRT = 0x04,
// VU0_VRSQRT = 0x05,
// VU0_VMULQ = 0x06,
// VU0_VIADD = 0x10,
// VU0_VISUB = 0x11,
// VU0_VIADDI = 0x12,
// VU0_VIAND = 0x13,
// VU0_VIOR = 0x14,
// VU0_VILWR = 0x15,
// VU0_VISWR = 0x16,
// VU0_VCALLMS = 0x20,
// VU0_VCALLMSR = 0x21,
// VU0_VRGET = 0x3F, // Get VU0 R register
// VU0_VSUB_XYZ = 0x38 // Subtract with component selection
// };
// enum VU0SpecialFormats
// {
// VU0_BC2F = 0x11, // Branch on VU0 condition false
// VU0_MTVUCF = 0x13, // Move To VU0 control/flag register
// VU0_CTCVU = 0x18, // Control To VU0 with specific functionality
// VU0_VMTIR = 0x1C, // Move To VU0 I Register
// VU0_VCLIP = 0x1E, // VU0 Clipping operation
// VU0_VLDQ = 0x1F // VU0 Load/Store Quad with Decrement
// };
// VU0 Control Register Numbers (used with CFC2/CTC2)
enum VU0ControlRegisters
{
VU0_CR_STATUS = 0, // Status/Control register
VU0_CR_MAC = 1, // MAC flags register
VU0_CR_CLIP = 5, // Clipping flags register
VU0_CR_CLIP = 5, // Clipping flags register //TODO maybe this is a 2 instead of 5
VU0_CR_R = 3, // R register (Random number)
VU0_CR_I = 4, // I register (Immediate)
VU0_CR_CMSAR0 = 13, // VU0 microprogram start address register
VU0_CR_FBRST = 18 // VIF/VU0/VU1 reset register
};
enum VU0OPSFunctions
{
VU0OPS_QMFC2_NI = 0x00, // Non-incrementing QMFC2
VU0OPS_QMFC2_I = 0x01, // Incrementing QMFC2
VU0OPS_QMTC2_NI = 0x02, // Non-incrementing QMTC2
VU0OPS_QMTC2_I = 0x03, // Incrementing QMTC2
VU0OPS_VMFIR = 0x04, // Move From Integer Register
VU0OPS_VXITOP = 0x08, // Execute Interrupt on VU0
VU0OPS_VWAITQ = 0x3B, // Wait for Q register operations to complete
VU0OPS_VMFHL = 0x1C, // Move from High / Low(similar to PMFHL)
VU0OPS_VMTIR = 0x3C // Move to VU0 I Register with function code
VU0OPS_QMFC2_NI = 0x00, // Non-incrementing QMFC2
VU0OPS_QMFC2_I = 0x01, // Incrementing QMFC2
VU0OPS_QMTC2_NI = 0x02, // Non-incrementing QMTC2
VU0OPS_QMTC2_I = 0x03, // Incrementing QMTC2
VU0OPS_VMFIR = 0x04, // Move From Integer Register
VU0OPS_VXITOP = 0x08, // Execute Interrupt on VU0
VU0OPS_VWAITQ = 0x3B, // Wait for Q register operations to complete
VU0OPS_VMFHL = 0x1C, // Move from High / Low(similar to PMFHL)
VU0OPS_VMTIR = 0x3C // Move to VU0 I Register with function code
};
enum VU0OPSFunctionsExtra
@@ -494,16 +719,6 @@ namespace ps2recomp
VU0_FMT_LQSQ_COP0 = 0x1B // Load/store quad VU0 format
};
// PMFHL functions (sa field)
enum PMFHLFunctions
{
PMFHL_LW = 0x00,
PMFHL_UW = 0x01,
PMFHL_SLW = 0x02,
PMFHL_LH = 0x03,
PMFHL_SH = 0x04
};
// Instruction decoding helper macros
#define OPCODE(inst) ((inst >> 26) & 0x3F)
#define RS(inst) ((inst >> 21) & 0x1F)
@@ -512,8 +727,31 @@ namespace ps2recomp
#define SA(inst) ((inst >> 6) & 0x1F)
#define FUNCTION(inst) ((inst) & 0x3F)
#define IMMEDIATE(inst) ((inst) & 0xFFFF)
#define SIMMEDIATE(inst) ((int16_t)((inst) & 0xFFFF))
#define SIMMEDIATE(inst) ((int32_t)(int16_t)((inst) & 0xFFFF))
#define TARGET(inst) ((inst) & 0x3FFFFFF)
#define COP_FUNCT(inst) ((uint8_t)((inst) & 0x3F)) // Function field for COPz CO instructions
#define FPU_FMT(inst) ((uint8_t)(((inst) >> 21) & 0x1F)) // Format field for FPU instructions
#define FT(inst) RT(inst) // Target FPU register
#define FS(inst) RD(inst) // Source FPU register
#define FD(inst) SA(inst) // Destination FPU register
#define VU_I(inst) ((inst >> 25) & 0x1) // VU Upper I bit
#define VU_E(inst) ((inst >> 24) & 0x1) // VU Upper E bit
#define VU_M(inst) ((inst >> 23) & 0x1) // VU Upper M bit (VU0 only)
#define VU_D(inst) ((inst >> 22) & 0x1) // VU Upper D bit
#define VU_T(inst) ((inst >> 21) & 0x1) // VU Upper T bit
#define VU_DEST(inst) ((uint8_t)(((inst) >> 16) & 0xF)) // VU Destination mask
#define VU_FSF(inst) ((uint8_t)(((inst) >> 10) & 0x3)) // VU Source Field F
#define VU_FTF(inst) ((uint8_t)(((inst) >> 8) & 0x3)) // VU Target Field F
#define VU_FD(inst) ((uint8_t)(((inst) >> 11) & 0x1F)) // VU Destination Vector Register
#define VU_FS(inst) ((uint8_t)(((inst) >> 6) & 0x1F)) // VU Source Vector Register
#define VU_FT(inst) ((uint8_t)((inst) & 0x1F)) // VU Target Vector Register
#define VU_IS(inst) RT(inst) // VU Source Integer Register
#define VU_IT(inst) RD(inst) // VU Target Integer Register
#define VU_ID(inst) SA(inst) // VU Destination Integer Register
#define VU_IMM5(inst) ((uint8_t)((inst >> 6) & 0x1F)) // VU 5-bit immediate
#define VU_IMM11(inst) ((uint16_t)((inst) & 0x7FF)) // VU 11-bit immediate
#define VU_SIMM11(inst) ((int16_t)(((inst & 0x7FF) ^ 0x400) - 0x400)) // VU 11-bit signed immediate
#define VU_IMM15(inst) ((uint16_t)((inst) & 0x7FFF)) // VU 15-bit immediate
} // namespace ps2recomp
+23 -8
View File
@@ -15,14 +15,15 @@ namespace ps2recomp
{
uint32_t address;
uint32_t opcode;
uint32_t rs; // Source register
uint32_t rt; // Target register
uint32_t rd; // Destination register
uint32_t sa; // Shift amount
uint32_t function; // Function code for R-type instructions
uint32_t immediate; // Immediate value for I-type instructions
uint32_t target; // Jump target for J-type instructions
uint32_t raw; // Raw instruction value
uint32_t rs; // Source register
uint32_t rt; // Target register
uint32_t rd; // Destination register
uint32_t sa; // Shift amount
uint32_t function; // Function code for R-type instructions
uint32_t immediate; // Immediate value for I-type instructions
uint32_t simmediate; // Sign-extended immediate value (extended to 32 bits)
uint32_t target; // Jump target for J-type instructions
uint32_t raw; // Raw instruction value
// Instruction type flags
bool isMMI; // Is MMI instruction (PS2 specific)
@@ -49,6 +50,8 @@ namespace ps2recomp
bool usesPReg; // Uses P register
bool modifiesMAC; // Modifies MAC flags
uint8_t vectorField; // xyzw field mask
uint8_t fsf; // Field select for FS reg (bits 10-11)
uint8_t ftf; // Source Field select for FT reg (bits 8-9)
} vectorInfo;
struct
@@ -56,9 +59,21 @@ namespace ps2recomp
bool modifiesGPR; // Modifies general purpose register
bool modifiesFPR; // Modifies floating point register
bool modifiesVFR; // Modifies vector float register
bool modifiesVIR; // Modifies vector integer register
bool modifiesVIC; // Modifies vector integer control register
bool modifiesMemory; // Modifies memory
bool modifiesControl; // Modifies control register
} modificationInfo;
Instruction() : address(0), opcode(0), rs(0), rt(0), rd(0), sa(0), function(0),
immediate(0), simmediate(0), target(0), raw(0),
isMMI(false), isVU(false), isBranch(false), isJump(false), isCall(false),
isReturn(false), hasDelaySlot(false), isMultimedia(false), isStore(false), isLoad(false),
mmiType(0), mmiFunction(0), pmfhlVariation(0), vuFunction(0)
{
vectorInfo = {};
modificationInfo = {};
}
};
// Function information
File diff suppressed because it is too large Load Diff
+326 -371
View File
@@ -25,6 +25,7 @@ namespace ps2recomp
inst.sa = SA(rawInstruction);
inst.function = FUNCTION(rawInstruction);
inst.immediate = IMMEDIATE(rawInstruction);
inst.simmediate = SIMMEDIATE(rawInstruction);
inst.target = TARGET(rawInstruction);
inst.isMMI = false;
@@ -53,6 +54,8 @@ namespace ps2recomp
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;
@@ -68,18 +71,10 @@ namespace ps2recomp
case OPCODE_J:
decodeJType(inst);
inst.isJump = true;
inst.hasDelaySlot = true;
inst.modificationInfo.modifiesControl = true; // PC
break;
case OPCODE_JAL:
decodeJType(inst);
inst.isJump = true;
inst.isCall = true;
inst.hasDelaySlot = true;
inst.modificationInfo.modifiesGPR = true; // $ra (r[31])
inst.modificationInfo.modifiesControl = true; // PC
break;
case OPCODE_BEQ:
@@ -96,6 +91,103 @@ namespace ps2recomp
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_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:
@@ -109,144 +201,25 @@ namespace ps2recomp
inst.modificationInfo.modifiesGPR = true;
break;
case OPCODE_DADDI:
case OPCODE_DADDIU:
decodeIType(inst);
if (inst.rt != 0)
inst.modificationInfo.modifiesGPR = true;
break;
case OPCODE_MMI:
decodeMMI(inst);
inst.isMMI = true;
inst.isMultimedia = true;
inst.modificationInfo.modifiesGPR = true;
break;
case OPCODE_LQ:
decodeIType(inst);
inst.isLoad = true;
inst.isMultimedia = true; // 128-bit load
if (inst.rt != 0)
inst.modificationInfo.modifiesGPR = true;
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_LWL:
case OPCODE_LW:
case OPCODE_LBU:
case OPCODE_LHU:
case OPCODE_LWR:
case OPCODE_LWU:
case OPCODE_LD:
case OPCODE_LDL:
case OPCODE_LDR:
case OPCODE_LL:
case OPCODE_LWC1:
case OPCODE_LDC1:
case OPCODE_LWC2:
case OPCODE_LDC2: // VU Load
decodeIType(inst);
inst.isLoad = true;
if (inst.opcode == OPCODE_LWC1 || inst.opcode == OPCODE_LDC1)
inst.modificationInfo.modifiesFPR = true;
else if (inst.opcode == OPCODE_LQC2)
inst.modificationInfo.modifiesVFR = true;
else if (inst.rt != 0)
inst.modificationInfo.modifiesGPR = true; // Standard GPR loads
break;
case OPCODE_SB:
case OPCODE_SH:
case OPCODE_SWL:
case OPCODE_SW:
case OPCODE_SWR:
case OPCODE_SD:
case OPCODE_SDL:
case OPCODE_SDR:
case OPCODE_SC:
case OPCODE_SWC1:
case OPCODE_SDC1:
case OPCODE_SWC2:
case OPCODE_SDC2:
case OPCODE_SCD: // VU Store
decodeIType(inst);
inst.isStore = true;
if (inst.opcode == OPCODE_SC || inst.opcode == OPCODE_SCD)
{
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);
inst.modificationInfo.modifiesControl = true;
if (inst.rs == COP0_MF && inst.rt != 0)
inst.modificationInfo.modifiesGPR = true;
break;
case OPCODE_COP1:
decodeCOP1(inst);
// Can modify FPRs, FCRs, GPRs (MFC1/CFC1), or PC (BC1)
if (inst.isBranch)
inst.modificationInfo.modifiesControl = true; // PC
if (inst.rs == COP1_MF || inst.rs == COP1_CF)
{
// MFC1, CFC1
if (inst.rt != 0)
inst.modificationInfo.modifiesGPR = true;
}
else if (inst.rs == COP1_S || inst.rs == COP1_W || inst.rs == COP1_L)
{
inst.modificationInfo.modifiesFPR = true;
}
if (inst.rs == COP1_CT || inst.function >= COP1_FUNC_C_F)
{ // CTC1 or Compare
inst.modificationInfo.modifiesControl = true; // FCR31
}
break;
case OPCODE_COP2:
decodeCOP2(inst);
inst.isVU = true;
inst.isMultimedia = true;
// Can modify VFRs, VU Flags, GPRs (QMFC2/CFC2), PC (BC2), memory (VISWR)
if (inst.isBranch)
inst.modificationInfo.modifiesControl = true; // PC
if (inst.rs == COP2_QMFC2 || inst.rs == COP2_CFC2)
{
// QMFC2, CFC2
if (inst.rt != 0)
inst.modificationInfo.modifiesGPR = true;
}
else if (inst.rs == COP2_QMTC2 || inst.rs == COP2_CTC2)
{
// Modifies VU state based on GPR
}
else
{
inst.modificationInfo.modifiesVFR = true; // Default assumption
inst.modificationInfo.modifiesControl = true; // Flags, Q, P, I etc.
}
if (inst.isStore)
inst.modificationInfo.modifiesMemory = true;
break;
default:
@@ -255,6 +228,13 @@ namespace ps2recomp
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;
}
@@ -277,9 +257,12 @@ namespace ps2recomp
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])
}
}
@@ -420,13 +403,8 @@ namespace ps2recomp
case SPECIAL_SYNC:
inst.modificationInfo.modifiesGPR = false;
// Potentially modifies memory/cache visibility
inst.modificationInfo.modifiesControl = true;
break;
default:
// Other R-type instructions
break;
}
}
@@ -493,82 +471,69 @@ namespace ps2recomp
// The function field is actually determined by the lowest 6 bits (as in R-type)
uint32_t mmiFunction = inst.function;
// Categorize the MMI instruction type based on the rs field
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)
{
// Thouse comments has the same value
case MMI_MADD:
case MMI_MADDU:
case MMI_MSUB:
case MMI_MSUBU:
case MMI_MADD1:
case MMI_MADDU1:
// Multiply-add operations
inst.modificationInfo.modifiesControl = true; // Modifies HI/LO or HI1/LO1
break;
case MMI_PLZCW:
// Count leading zeros/ones
break;
case MMI_MFHI1:
case MMI_MFLO1:
// Modifies rd GPR (already set)
break;
case MMI_MTHI1:
case MMI_MTLO1:
// Secondary HI/LO register operations
inst.modificationInfo.modifiesGPR = false;
inst.modificationInfo.modifiesControl = true;
break;
case MMI_MULT1:
case MMI_MULTU1:
case MMI_DIV1:
case MMI_DIVU1:
// Secondary multiply/divide operations
break;
case MMI_MMI0:
// First set of multimedia instructions
decodeMMI0(inst);
break;
case MMI_MMI1:
// Second set of multimedia instructions
decodeMMI1(inst);
break;
case MMI_MMI2:
// Third set of multimedia instructions
decodeMMI2(inst);
break;
case MMI_MMI3:
// Fourth set of multimedia instructions
decodeMMI3(inst);
break;
case MMI_PMFHL:
// PMFHL variations based on sa field
decodePMFHL(inst);
break;
case MMI_PMTHL:
// PMTHL operations
inst.modificationInfo.modifiesGPR = false;
// case MMI2_PMADDW:
case MMI2_PMSUBW:
case MMI2_PMULTW:
case MMI2_PDIVW:
case MMI2_PDIVBW:
case MMI2_PMADDH:
case MMI2_PHMADH:
// case MMI2_PMSUBH:
// case MMI2_PHMSBH:
case MMI2_PMULTH:
// case MMI3_PMADDUW:
// case MMI3_PMULTUW:
// case MMI3_PDIVUW:
inst.modificationInfo.modifiesGPR = false; // Writes to HI/LO or HI1/LO1
inst.modificationInfo.modifiesControl = true;
break;
case MMI_PSLLH:
case MMI_PSRLH:
case MMI_PSRAH:
case MMI_PSLLW:
case MMI_PSRLW:
case MMI_PSRAW:
// SIMD shift operations
case MMI_MTHI1:
case MMI_MTLO1:
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;
@@ -812,207 +777,197 @@ namespace ps2recomp
void R5900Decoder::decodeCOP0(Instruction &inst) const
{
// COP0 (System Control) instructions
uint32_t rs = inst.rs; // Actually the cop0 format field
if (rs == COP0_MF)
uint8_t format = inst.rs;
inst.modificationInfo.modifiesControl = true; // Assume COP0 always modifies some control state
if (format == COP0_MF && inst.rt != 0)
{
// Move From COP0 register
inst.modificationInfo.modifiesGPR = true;
}
else if (rs == COP0_MT)
else if (format == COP0_CO && inst.function == COP0_CO_ERET)
{
// Move To COP0 register
}
else if (rs == COP0_CO)
inst.isReturn = true;
inst.hasDelaySlot = false;
} // ERET is special
else if (format == COP0_BC)
{
// COProcessor operations
uint32_t function = inst.function;
if (function == COP0_CO_ERET)
{
inst.isReturn = true;
inst.hasDelaySlot = true;
}
else if (function == COP0_CO_TLBR ||
function == COP0_CO_TLBWI ||
function == COP0_CO_TLBWR ||
function == COP0_CO_TLBP)
{
// TLB operations
}
else if (function == COP0_CO_EI || function == COP0_CO_DI)
{
// Enable/Disable Interrupts
}
inst.isBranch = true;
inst.hasDelaySlot = true;
}
}
void R5900Decoder::decodeCOP1(Instruction &inst) const
{
// COP1 (FPU) instructions
uint32_t rs = inst.rs; // The FPU format field
if (rs == COP1_MF)
uint8_t format = inst.rs;
if (format == COP1_MF || format == COP1_CF)
{
// Move From FPU register
if (inst.rt != 0)
inst.modificationInfo.modifiesGPR = true;
}
else if (rs == COP1_CF)
else if (format == COP1_BC)
{
// Move From FPU Control register
inst.isBranch = true;
inst.hasDelaySlot = true;
inst.modificationInfo.modifiesControl = true;
}
else if (rs == COP1_MT)
else if (format == COP1_S || format == COP1_W || format == COP1_L)
{
// Move To FPU register
inst.modificationInfo.modifiesFPR = true;
}
else if (rs == COP1_CT)
if (format == COP1_CT || (format == COP1_S && inst.function >= COP1_S_C_F))
{
// Move To FPU Control register
}
else if (rs == COP1_BC)
{
// FPU Branch on Condition
uint32_t rt = inst.rt; // The condition code
if (rt == COP1_BC_BCF || rt == COP1_BC_BCT)
{
inst.isBranch = true;
inst.hasDelaySlot = true;
}
}
else if (rs == COP1_S || rs == COP1_W)
{
// FPU operations (single precision or word)
uint32_t function = inst.function;
// Decode specific FPU operation based on function field
}
inst.modificationInfo.modifiesControl = true;
} // FCR31
}
void R5900Decoder::decodeCOP2(Instruction &inst) const
{
uint8_t format = inst.rs;
inst.isVU = true;
inst.isMultimedia = true;
uint32_t rs = inst.rs; // The format field
switch (rs)
switch (format)
{
case COP2_QMFC2: // Move From COP2 (128-bit)
case COP2_CFC2: // Move Control From COP2
case COP2_QMTC2: // Move To COP2 (128-bit)
case COP2_CTC2: // Move Control To COP2
// Register transfer operations
case COP2_QMFC2:
case COP2_CFC2:
if (inst.rt != 0)
inst.modificationInfo.modifiesGPR = true;
break;
case COP2_BC2: // Branch on COP2 condition
{
uint32_t rt = inst.rt; // The condition code
if (rt == COP2_BCF || rt == COP2_BCT ||
rt == COP2_BCFL || rt == COP2_BCTL ||
rt == COP2_BCEF || rt == COP2_BCET ||
rt == COP2_BCEFL || rt == COP2_BCETL)
{
inst.isBranch = true;
inst.hasDelaySlot = true;
}
}
break;
case COP2_CO: // VU0 vector operations
{
uint32_t function = inst.function;
switch (function)
{
case VU0_VADD:
case VU0_VSUB:
case VU0_VMUL:
// Basic vector math operations
break;
case VU0_VDIV:
case VU0_VSQRT:
case VU0_VRSQRT:
// Division and square root operations
break;
case VU0_VMULQ:
// Multiply by Q register
break;
case VU0_VIADD:
case VU0_VISUB:
case VU0_VIADDI:
// Integer operations
break;
case VU0_VIAND:
case VU0_VIOR:
// Logical operations
break;
case VU0_VILWR:
case VU0_VISWR:
// Load/Store operations
inst.isLoad = (function == VU0_VILWR);
inst.isStore = (function == VU0_VISWR);
break;
case VU0_VCALLMS:
case VU0_VCALLMSR:
// VU0 microprogram calls
inst.isCall = true;
break;
case VU0_VRGET:
// Get random number from R register
break;
default:
// Other VU0 operations
break;
}
}
break;
case COP2_CTCVU: // Control Transfer to VU0
case COP2_MTVUCF: // Move To VU Control/Flag register
case COP2_VMTIR: // Move To VU0 I Register
// Special register operations
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;
case COP2_VU0OPS: // Additional VU0 operations
{
uint32_t function = inst.function;
switch (function)
if (vu_func == VU0_S2_VDIV || vu_func == VU0_S2_VSQRT || vu_func == VU0_S2_VRSQRT)
{
case VU0OPS_QMFC2_NI: // Non-incrementing QMFC2
case VU0OPS_QMFC2_I: // Incrementing QMFC2
case VU0OPS_QMTC2_NI: // Non-incrementing QMTC2
case VU0OPS_QMTC2_I: // Incrementing QMTC2
// Extended register transfer operations
break;
case VU0OPS_VMFIR: // Move From Integer Register
// Move operations
break;
case VU0OPS_VXITOP: // Execute Interrupt on VU0
break;
case VU0OPS_VWAITQ: // Wait for Q register operations
break;
default:
// Unknown VU0OPS
break;
inst.vectorInfo.fsf = (inst.raw >> 10) & 0x3; // Extract bits 10-11
inst.vectorInfo.ftf = (inst.raw >> 8) & 0x3; // Extract bits 8-9
}
}
break;
default:
// Unknown COP2 format
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
@@ -1094,8 +1049,7 @@ namespace ps2recomp
return 0;
}
// Calculate branch target: PC + 4 + (sign-extended immediate << 2)
int32_t offset = static_cast<int16_t>(inst.immediate) << 2;
int32_t offset = inst.simmediate << 2;
return inst.address + 4 + offset;
}
@@ -1106,6 +1060,13 @@ namespace ps2recomp
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
@@ -1113,12 +1074,6 @@ namespace ps2recomp
uint32_t pc_upper = (inst.address + 4) & 0xF0000000;
return pc_upper | (inst.target << 2);
}
else 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;
}
return 0;
}
+1 -1
View File
@@ -11,7 +11,7 @@
#include <iostream>
constexpr uint32_t PS2_RAM_SIZE = 32 * 1024 * 1024; // 32MB
constexpr uint32_t PS2_RAM_MASK = PS2_RAM_SIZE - 1; // Mask for 32MB alignment
constexpr uint32_t PS2_RAM_MASK = 0x1FFFFFF; // Mask for 32MB alignment
constexpr uint32_t PS2_RAM_BASE = 0x00000000; // Physical base of RDRAM
constexpr uint32_t PS2_SCRATCHPAD_BASE = 0x70000000;
constexpr uint32_t PS2_SCRATCHPAD_SIZE = 16 * 1024; // 16KB