refactor: added more instructions decoder

This commit is contained in:
Ran-j
2025-04-16 01:45:13 -03:00
parent 7353b966f2
commit 23bb92bd4a
5 changed files with 463 additions and 57 deletions
@@ -47,6 +47,8 @@ namespace ps2recomp
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);
@@ -280,6 +280,8 @@ namespace ps2recomp
MMI3_PEXCH = 0x1A,
MMI3_PCPYH = 0x1B,
MMI3_PEXCW = 0x1E,
MMI3_PMTHI = 0x08, // Move To HI register
MMI3_PMTLO = 0x09 // Move To LO register
};
// COP0 (rs field)
+36 -11
View File
@@ -23,17 +23,42 @@ namespace ps2recomp
uint32_t immediate; // Immediate value for I-type instructions
uint32_t target; // Jump target for J-type instructions
uint32_t raw; // Raw instruction value
bool isMMI; // Is MMI instruction (PS2 specific)
bool isVU; // Is VU instruction (PS2 specific)
bool isBranch; // Is branch instruction
bool isJump; // Is jump instruction
bool isCall; // Is function call
bool isReturn; // Is return instruction
bool hasDelaySlot; // Has delay slot
bool isMultimedia; // PS2-specific multimedia operations
bool isStore;
bool isLoad;
uint8_t pmfhlVariation;
// Instruction type flags
bool isMMI; // Is MMI instruction (PS2 specific)
bool isVU; // Is VU instruction (PS2 specific)
bool isBranch; // Is branch instruction
bool isJump; // Is jump instruction
bool isCall; // Is function call
bool isReturn; // Is return instruction
bool hasDelaySlot; // Has delay slot
bool isMultimedia; // PS2-specific multimedia operations
bool isStore; // Is store instruction
bool isLoad; // Is load instruction
// Additional PS2-specific fields
uint8_t mmiType; // 0=MMI0, 1=MMI1, 2=MMI2, 3=MMI3
uint8_t mmiFunction; // Function within MMI type
uint8_t pmfhlVariation; // For PMFHL instructions
uint8_t vuFunction; // For VU instructions
struct
{
bool isVector; // Uses vector operations
bool usesQReg; // Uses Q register
bool usesPReg; // Uses P register
bool modifiesMAC; // Modifies MAC flags
uint8_t vectorField; // xyzw field mask
} vectorInfo;
struct
{
bool modifiesGPR; // Modifies general purpose register
bool modifiesFPR; // Modifies floating point register
bool modifiesVFR; // Modifies vector float register
bool modifiesMemory; // Modifies memory
bool modifiesControl; // Modifies control register
} modificationInfo;
};
// Function information
+97 -13
View File
@@ -465,6 +465,11 @@ namespace ps2recomp
{
return "// NOP (addiu $zero, ...)";
}
if (inst.modificationInfo.modifiesGPR)
{
return fmt::format("ctx->r[{}] = ADD32(ctx->r[{}], 0x{:X}); // Modifies GPR",
inst.rt, inst.rs, (int16_t)inst.immediate);
}
return fmt::format("ctx->r[{}] = ADD32(ctx->r[{}], 0x{:X});",
inst.rt, inst.rs, (int16_t)inst.immediate);
@@ -526,10 +531,20 @@ namespace ps2recomp
// PS2-specific 128-bit load/store
case OPCODE_LQ:
if (inst.vectorInfo.isVector)
{
return fmt::format("ctx->r[{}] = (__m128i)READ128(ADD32(ctx->r[{}], 0x{:X})); // Vector load",
inst.rt, inst.rs, (int16_t)inst.immediate);
}
return fmt::format("ctx->r[{}] = (__m128i)READ128(ADD32(ctx->r[{}], 0x{:X}));",
inst.rt, inst.rs, (int16_t)inst.immediate);
case OPCODE_SQ:
if (inst.vectorInfo.isVector)
{
return fmt::format("WRITE128(ADD32(ctx->r[{}], 0x{:X}), (__m128i)ctx->r[{}]); // Vector store",
inst.rs, (int16_t)inst.immediate, inst.rt);
}
return fmt::format("WRITE128(ADD32(ctx->r[{}], 0x{:X}), (__m128i)ctx->r[{}]);",
inst.rs, (int16_t)inst.immediate, inst.rt);
@@ -553,6 +568,14 @@ namespace ps2recomp
return fmt::format("WRITE128(ADD32(ctx->r[{}], 0x{:X}), (__m128i)ctx->vu0_vf[{}]);",
inst.rs, (int16_t)inst.immediate, inst.rt);
case OPCODE_J:
return fmt::format("// J 0x{:X} - Handled by branch logic",
(inst.address & 0xF0000000) | (inst.target << 2));
case OPCODE_JAL:
return fmt::format("// JAL 0x{:X} - Handled by branch logic",
(inst.address & 0xF0000000) | (inst.target << 2));
case OPCODE_LWC1:
return fmt::format("{{ uint32_t val = READ32(ADD32(ctx->r[{}], 0x{:X})); ctx->f[{}] = *(float*)&val; }}",
inst.rs, (int16_t)inst.immediate, inst.rt);
@@ -579,20 +602,17 @@ namespace ps2recomp
switch (inst.rt)
{
case REGIMM_BLTZ:
return fmt::format("// BLTZ r{}, 0x{:X} - Handled by branch logic",
inst.rs, inst.address + 4 + ((int16_t)inst.immediate << 2));
case REGIMM_BGEZ:
return fmt::format("// BGEZ r{}, 0x{:X} - Handled by branch logic",
inst.rs, inst.address + 4 + ((int16_t)inst.immediate << 2));
case REGIMM_BLTZL:
case REGIMM_BGEZL:
case REGIMM_BLTZAL:
return fmt::format("// BLTZAL r{}, 0x{:X} - Handled by branch logic",
inst.rs, inst.address + 4 + ((int16_t)inst.immediate << 2));
case REGIMM_BGEZAL:
return fmt::format("// BGEZAL r{}, 0x{:X} - Handled by branch logic",
inst.rs, inst.address + 4 + ((int16_t)inst.immediate << 2));
case REGIMM_BLTZALL:
case REGIMM_BGEZALL:
{
uint32_t target = inst.address + 4 + ((int16_t)inst.immediate << 2);
return fmt::format("// REGIMM branch instruction to 0x{:X} - Handled by branch logic", target);
}
case REGIMM_MTSAB:
return fmt::format("ctx->sa = (ctx->r[{}] + 0x{:X}) & 0x0F;",
@@ -631,6 +651,10 @@ namespace ps2recomp
}
// MIPS-IV special format opcodes
case OPCODE_BEQ:
case OPCODE_BNE:
case OPCODE_BLEZ:
case OPCODE_BGTZ:
case OPCODE_BEQL:
case OPCODE_BNEL:
case OPCODE_BLEZL:
@@ -1128,6 +1152,15 @@ namespace ps2recomp
switch (inst.sa)
{
case MMI0_PADDW:
if (inst.vectorInfo.isVector && inst.vectorInfo.vectorField != 0xF)
{
return fmt::format("{{ __m128i mask = _mm_set_epi32({}, {}, {}, {}); ctx->r[{}] = _mm_blendv_epi8(ctx->r[{}], PS2_PADDW(ctx->r[{}], ctx->r[{}]), mask); }}",
(inst.vectorInfo.vectorField & 0x8) ? 0xFFFFFFFF : 0,
(inst.vectorInfo.vectorField & 0x4) ? 0xFFFFFFFF : 0,
(inst.vectorInfo.vectorField & 0x2) ? 0xFFFFFFFF : 0,
(inst.vectorInfo.vectorField & 0x1) ? 0xFFFFFFFF : 0,
inst.rd, inst.rd, inst.rs, inst.rt);
}
return fmt::format("ctx->r[{}] = PS2_PADDW(ctx->r[{}], ctx->r[{}]);",
inst.rd, inst.rs, inst.rt);
@@ -1192,7 +1225,8 @@ namespace ps2recomp
inst.rd, inst.rs, inst.rt);
case MMI0_PPACB:
return fmt::format("// PS2_PPACB not implemented");
return fmt::format("ctx->r[{}] = PS2_PPACB(ctx->r[{}], ctx->r[{}]);",
inst.rd, inst.rs, inst.rt);
default:
return fmt::format("// Unhandled MMI0 function: 0x{:X}", inst.sa);
@@ -1316,6 +1350,36 @@ namespace ps2recomp
case MMI2_PHMADH:
return translatePHMADH(inst);
case MMI2_PMSUBH:
return fmt::format("{{ __m128i product = _mm_mullo_epi16(ctx->r[{}], ctx->r[{}]); "
"// Convert products to 32-bit\n"
"__m128i prod_lo = _mm_unpacklo_epi16(product, _mm_srai_epi16(product, 15));\n"
"__m128i prod_hi = _mm_unpackhi_epi16(product, _mm_srai_epi16(product, 15));\n"
"// Subtract from accumulator\n"
"__m128i acc = _mm_set_epi32(0, ctx->hi, 0, ctx->lo);\n"
"__m128i result = _mm_sub_epi32(acc, _mm_add_epi32(prod_lo, prod_hi));\n"
"ctx->r[{}] = result;\n"
"ctx->lo = _mm_extract_epi32(result, 0);\n"
"ctx->hi = _mm_extract_epi32(result, 1); }}",
inst.rs, inst.rt, inst.rd);
case MMI2_PHMSBH:
return fmt::format("{{ // Multiply horizontally adjacent halfwords\n"
"__m128i rtEven = _mm_shuffle_epi32(ctx->r[{}], _MM_SHUFFLE(2, 0, 2, 0));\n"
"__m128i rtOdd = _mm_shuffle_epi32(ctx->r[{}], _MM_SHUFFLE(3, 1, 3, 1));\n"
"__m128i rsEven = _mm_shuffle_epi32(ctx->r[{}], _MM_SHUFFLE(2, 0, 2, 0));\n"
"__m128i rsOdd = _mm_shuffle_epi32(ctx->r[{}], _MM_SHUFFLE(3, 1, 3, 1));\n"
"__m128i prod1 = _mm_mullo_epi16(rtEven, rsEven);\n"
"__m128i prod2 = _mm_mullo_epi16(rtOdd, rsOdd);\n"
"__m128i sum = _mm_add_epi16(prod1, prod2);\n"
"// Convert to 32-bit and subtract from accumulator\n"
"__m128i acc = _mm_set_epi32(0, ctx->hi, 0, ctx->lo);\n"
"__m128i result = _mm_sub_epi32(acc, _mm_unpacklo_epi16(sum, _mm_srai_epi16(sum, 15)));\n"
"ctx->r[{}] = result;\n"
"ctx->lo = _mm_extract_epi32(result, 0);\n"
"ctx->hi = _mm_extract_epi32(result, 1); }}",
inst.rt, inst.rt, inst.rs, inst.rs, inst.rd);
case MMI2_PEXEH:
return translatePEXEH(inst);
@@ -1352,7 +1416,11 @@ namespace ps2recomp
inst.rd, inst.rs, inst.rt);
case MMI3_PMADDUW:
return fmt::format("// PS2_PMADDUW - Packed Multiply-Add Unsigned Word");
return fmt::format("{{ uint64_t result = (uint64_t)(((uint64_t)ctx->hi << 32) | ctx->lo) + "
"(uint64_t)_mm_extract_epi32(ctx->r[{}], 0) * (uint64_t)_mm_extract_epi32(ctx->r[{}], 0); "
"ctx->lo = (uint32_t)result; ctx->hi = (uint32_t)(result >> 32); "
"ctx->r[{}] = _mm_set_epi32(0, 0, ctx->hi, ctx->lo); }}",
inst.rs, inst.rt, inst.rd);
case MMI3_PSRAVW:
return fmt::format("ctx->r[{}] = PS2_PSRAVW(ctx->r[{}], ctx->r[{}]);",
@@ -1380,6 +1448,12 @@ namespace ps2recomp
case MMI3_PEXCW:
return translatePEXCW(inst);
case MMI3_PMTHI:
return translatePMTHI(inst);
case MMI3_PMTLO:
return translatePMTLO(inst);
default:
return fmt::format("// Unhandled MMI3 function: 0x{:X}", inst.sa);
}
@@ -2258,6 +2332,16 @@ namespace ps2recomp
inst.rs, inst.rd);
}
std::string CodeGenerator::translatePMTHI(const Instruction &inst)
{
return fmt::format("ctx->hi = _mm_extract_epi32(ctx->r[{}], 0);", inst.rs);
}
std::string CodeGenerator::translatePMTLO(const Instruction &inst)
{
return fmt::format("ctx->lo = _mm_extract_epi32(ctx->r[{}], 0);", inst.rs);
}
std::string CodeGenerator::generateJumpTableSwitch(const Instruction &inst, uint32_t tableAddress,
const std::vector<JumpTableEntry> &entries)
{
+326 -33
View File
@@ -34,6 +34,26 @@ namespace ps2recomp
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.modifiesMemory = false;
inst.modificationInfo.modifiesControl = false;
switch (inst.opcode)
{
@@ -86,18 +106,21 @@ namespace ps2recomp
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
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:
@@ -462,71 +485,341 @@ namespace ps2recomp
void R5900Decoder::decodeCOP2(Instruction &inst) const
{
// COP2 (VU0 macro mode) instructions
inst.isVU = true;
inst.isMultimedia = true;
uint32_t rs = inst.rs; // The VU0 format field
uint32_t rs = inst.rs; // The format field
if (rs == COP2_MFC2)
switch (rs)
{
// Move From COP2 register
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
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;
}
}
else if (rs == COP2_CFC2)
break;
case COP2_CO: // VU0 vector operations
{
// Move From COP2 Control register
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;
}
}
else if (rs == COP2_MTC2)
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
break;
case COP2_VU0OPS: // Additional VU0 operations
{
// Move To COP2 register
uint32_t function = inst.function;
switch (function)
{
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;
}
}
else if (rs == COP2_CTC2)
{
// Move To COP2 Control register
}
else if (rs == COP2_BCF || rs == COP2_BCT)
{
// VU0 Branch on Condition
inst.isBranch = true;
inst.hasDelaySlot = true;
}
else
{
// VU0 vector operations
// These would need detailed decoding based on function field
break;
default:
// Unknown COP2 format
break;
}
}
void R5900Decoder::decodeMMI0(Instruction &inst) const
{
// Decode MMI0 subfunctions (based on function field)
uint32_t subFunction = inst.function & 0x3F;
uint32_t sa = inst.sa;
// The implementation would set appropriate flags or properties based on the specific MMI0 operation
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
{
// Decode MMI1 subfunctions (based on function field)
uint32_t subFunction = inst.function & 0x3F;
// The implementation would set appropriate flags or properties based on the specific MMI1 operation
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
{
// Decode MMI2 subfunctions (based on function field)
uint32_t subFunction = inst.function & 0x3F;
uint32_t sa = inst.sa;
// The implementation would set appropriate flags or properties based on the specific MMI2 operation
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
{
// Decode MMI3 subfunctions (based on function field)
uint32_t subFunction = inst.function & 0x3F;
uint32_t sa = inst.sa;
// The implementation would set appropriate flags or properties based on the specific MMI3 operation
switch (sa)
{
case MMI3_PMADDUW:
// Unsigned multiply-add
inst.isMultimedia = true;
break;
case MMI3_PSRAVW:
// Packed shift right arithmetic variable word
break;
case MMI3_PMTHI:
inst.mmiFunction = MMI3_PMTHI;
inst.modificationInfo.modifiesControl = true; // HI register is modified
break;
case MMI3_PMTLO:
inst.mmiFunction = MMI3_PMTLO;
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;
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::decodePMFHL(Instruction &inst) const