mirror of
https://github.com/ran-j/PS2Recomp.git
synced 2026-09-26 08:51:05 -04:00
feat: more instruction
This commit is contained in:
@@ -281,7 +281,7 @@ namespace ps2recomp
|
||||
MMI3_PCPYH = 0x1B,
|
||||
MMI3_PEXCW = 0x1E,
|
||||
MMI3_PMTHI = 0x08, // Move To HI register
|
||||
MMI3_PMTLO = 0x09 // Move To LO register
|
||||
MMI3_PMTLO = 0x09 // Move To LO register
|
||||
};
|
||||
|
||||
// COP0 (rs field)
|
||||
@@ -342,8 +342,8 @@ namespace ps2recomp
|
||||
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_L = 0x15, // Long (64-bit integer) Operation
|
||||
COP1_D = 0x11, // Double Precision Operation (unused on PS2 FPU?)
|
||||
};
|
||||
|
||||
enum Cop1Functions
|
||||
@@ -386,7 +386,6 @@ namespace ps2recomp
|
||||
COP1_FUNC_C_LE = 0x3E, // Signaling Less Than or Equal
|
||||
COP1_FUNC_C_NGT = 0x3F, // Not Greater Than (Unordered or Less Than or Equal)
|
||||
};
|
||||
|
||||
|
||||
// COP2 (VU0 macro) function codes
|
||||
enum Cop2Functions
|
||||
@@ -435,7 +434,8 @@ namespace ps2recomp
|
||||
VU0_VISWR = 0x16,
|
||||
VU0_VCALLMS = 0x20,
|
||||
VU0_VCALLMSR = 0x21,
|
||||
VU0_VRGET = 0x3F // Get VU0 R register
|
||||
VU0_VRGET = 0x3F, // Get VU0 R register
|
||||
VU0_VSUB_XYZ = 0x38 // Subtract with component selection
|
||||
};
|
||||
|
||||
enum VU0SpecialFormats
|
||||
@@ -459,13 +459,39 @@ namespace ps2recomp
|
||||
|
||||
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 = 0x3C // Wait for Q register operations to complete
|
||||
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
|
||||
{
|
||||
VU0_VCALLMS_DIRECT = 0x00,
|
||||
VU0_VCALLMS_REG = 0x01
|
||||
};
|
||||
|
||||
enum VU0SpecialMasks
|
||||
{
|
||||
VU0_FIELD_MASK = 0xF, // Mask for vector field selection
|
||||
VU0_FIELD_SHIFT = 21, // Shift amount for field selection
|
||||
VU0_STORE_BIT = 0x80, // Bit indicating store operation
|
||||
VU0_SUBOP_MASK = 0x1F, // Mask for sub-operation code
|
||||
VU0_SUBOP_SHIFT = 6, // Shift amount for sub-operation
|
||||
VU0_SQC0 = 0x8 // SQC0 instruction code
|
||||
};
|
||||
|
||||
enum VU0FormatsExtra
|
||||
{
|
||||
VU0_FMT_MACRO_MOVE = 0x1, // Move between VU registers format
|
||||
VU0_FMT_VIF_STATUS = 0x5, // VIF status operations
|
||||
VU0_FMT_VCALLMS = 0x14, // VU0 microprogram call format
|
||||
VU0_FMT_LQSQ_COP0 = 0x1B // Load/store quad VU0 format
|
||||
};
|
||||
|
||||
// PMFHL functions (sa field)
|
||||
|
||||
@@ -586,18 +586,18 @@ namespace ps2recomp
|
||||
inst.rt, inst.rs, (int16_t)inst.immediate);
|
||||
|
||||
// Special case for R5900
|
||||
case OPCODE_COP0:
|
||||
return translateCOP0Instruction(inst);
|
||||
|
||||
case OPCODE_COP1:
|
||||
return translateFPUInstruction(inst);
|
||||
|
||||
case OPCODE_CACHE:
|
||||
return "// CACHE instruction (ignored)";
|
||||
|
||||
case OPCODE_PREF:
|
||||
return "// PREF instruction (ignored)";
|
||||
|
||||
case OPCODE_COP1:
|
||||
return translateFPUInstruction(inst);
|
||||
|
||||
case OPCODE_COP0:
|
||||
return translateCOP0Instruction(inst);
|
||||
|
||||
// REGIMM special format (opcode=0x01)
|
||||
case OPCODE_REGIMM:
|
||||
switch (inst.rt)
|
||||
@@ -616,8 +616,7 @@ namespace ps2recomp
|
||||
}
|
||||
|
||||
case REGIMM_MTSAB:
|
||||
return fmt::format("ctx->sa = (ctx->r[{}] + 0x{:X}) & 0x0F;",
|
||||
inst.rs, inst.immediate);
|
||||
return fmt::format("ctx->sa = (ADD32(ctx->r[{}], (int32_t)(int16_t)0x{:X})) & 0x0F;", inst.rs, inst.immediate);
|
||||
|
||||
case REGIMM_MTSAH:
|
||||
return fmt::format("ctx->sa = ((ctx->r[{}] + 0x{:X}) & 0x07) << 1;",
|
||||
@@ -1037,7 +1036,7 @@ namespace ps2recomp
|
||||
return fmt::format("ctx->cop0_errorepc = ctx->r[{}];", rt);
|
||||
|
||||
default:
|
||||
return fmt::format("// MTC0 to register {} ignored", rd);
|
||||
return fmt::format("// Unimplemented MTC0 to COP0 {}", rd);
|
||||
}
|
||||
|
||||
case COP0_CO: // COP0 co-processor operations
|
||||
@@ -1047,24 +1046,16 @@ namespace ps2recomp
|
||||
switch (function)
|
||||
{
|
||||
case COP0_CO_TLBR:
|
||||
return fmt::format("// TLBR instruction - TLB Read\n"
|
||||
" // Reads TLB entry specified by Index register\n"
|
||||
" // Not fully implemented in recompiled code");
|
||||
return fmt::format("runtime->handleTLBR(rdram, ctx);");
|
||||
|
||||
case COP0_CO_TLBWI:
|
||||
return fmt::format("// TLBWI instruction - TLB Write Indexed\n"
|
||||
" // Writes TLB entry specified by Index register\n"
|
||||
" // Not fully implemented in recompiled code");
|
||||
return fmt::format("runtime->handleTLBWI(rdram, ctx);");
|
||||
|
||||
case COP0_CO_TLBWR:
|
||||
return fmt::format("// TLBWR instruction - TLB Write Random\n"
|
||||
" // Writes TLB entry specified by Random register\n"
|
||||
" // Not fully implemented in recompiled code");
|
||||
return fmt::format("runtime->handleTLBWR(rdram, ctx);");
|
||||
|
||||
case COP0_CO_TLBP:
|
||||
return fmt::format("// TLBP instruction - TLB Probe\n"
|
||||
" // Searches TLB for matching entry to EntryHi, sets Index\n"
|
||||
" // Not fully implemented in recompiled code");
|
||||
return fmt::format("runtime->handleTLBP(rdram, ctx);");
|
||||
|
||||
case COP0_CO_ERET:
|
||||
return fmt::format("// ERET instruction - Return from Exception\n"
|
||||
@@ -1543,6 +1534,138 @@ namespace ps2recomp
|
||||
case COP2_BC2:
|
||||
return fmt::format("// VU branch instruction not implemented");
|
||||
|
||||
case VU0_FMT_LQSQ_COP0:
|
||||
if (inst.function & VU0_SQC0) // Store operation
|
||||
{
|
||||
return fmt::format("WRITE128(ADD32(ctx->r[{}], 0x{:X}), (__m128i)ctx->vu0_vf[{}]);",
|
||||
inst.rs, (int16_t)inst.immediate, inst.rt);
|
||||
}
|
||||
else // Load operation
|
||||
{
|
||||
return fmt::format("ctx->vu0_vf[{}] = (__m128)READ128(ADD32(ctx->r[{}], 0x{:X}));",
|
||||
inst.rt, inst.rs, (int16_t)inst.immediate);
|
||||
}
|
||||
|
||||
case VU0_FMT_VIF_STATUS:
|
||||
{
|
||||
int field = (inst.function >> VU0_FIELD_SHIFT) & VU0_FIELD_MASK; // Field selector
|
||||
int dest = inst.rd; // Destination register
|
||||
|
||||
if (inst.function & VU0_STORE_BIT) // Store to status
|
||||
{
|
||||
return fmt::format("ctx->vu0_status &= ~(0xFF << {}); ctx->vu0_status |= (_mm_extract_epi32(ctx->vu0_vf[{}], 0) & 0xFF) << {};",
|
||||
field * 8, dest, field * 8);
|
||||
}
|
||||
else // Load from status
|
||||
{
|
||||
return fmt::format("ctx->vu0_vf[{}] = (__m128)_mm_set1_epi32((ctx->vu0_status >> {}) & 0xFF);",
|
||||
dest, field * 8);
|
||||
}
|
||||
}
|
||||
|
||||
case VU0_FMT_MACRO_MOVE:
|
||||
{
|
||||
uint32_t subop = (inst.function >> VU0_SUBOP_SHIFT) & VU0_SUBOP_MASK;
|
||||
|
||||
switch (subop)
|
||||
{
|
||||
case VU0OPS_QMFC2_NI: // VMOVE - Move between VF registers
|
||||
return fmt::format("ctx->vu0_vf[{}] = ctx->vu0_vf[{}];",
|
||||
inst.rd, inst.rs);
|
||||
|
||||
case VU0OPS_QMFC2_I: // VRNEXT - Get next random value
|
||||
return fmt::format("{{ uint32_t random_val = (ctx->vu0_status * 0x41C64E6D + 12345) & 0xFFFFFFFF;\n"
|
||||
" ctx->vu0_status = random_val;\n"
|
||||
" ctx->vu0_vf[{}] = (__m128)_mm_set1_epi32(random_val); }}",
|
||||
inst.rd);
|
||||
|
||||
case VU0OPS_QMTC2_NI: // VRGET - Get random state
|
||||
return fmt::format("ctx->vu0_vf[{}] = (__m128)_mm_set1_epi32(ctx->vu0_status);",
|
||||
inst.rd);
|
||||
|
||||
default:
|
||||
return fmt::format("// Unhandled VU0 format 0x1 subop: 0x{:X}", subop);
|
||||
}
|
||||
}
|
||||
|
||||
case VU0_FMT_VCALLMS:
|
||||
{
|
||||
uint32_t subop = inst.function & 0x3F;
|
||||
|
||||
switch (subop)
|
||||
{
|
||||
case VU0_VCALLMS_DIRECT: // VCALLMS - Call VU0 microprogram
|
||||
return fmt::format("{{ uint32_t mpg_addr = 0x{:X};\n"
|
||||
" ctx->vu0_cmsar0 = mpg_addr;\n"
|
||||
" ctx->vu0_status |= 0x1; // Set execution bit }}",
|
||||
inst.immediate * 8);
|
||||
|
||||
case VU0_VCALLMS_REG: // VCALLMSR - Call VU0 microprogram (register)
|
||||
return fmt::format("{{ uint32_t mpg_addr = ctx->r[{}].m128i_u32[0] & 0xFFF;\n"
|
||||
" ctx->vu0_cmsar0 = mpg_addr;\n"
|
||||
" ctx->vu0_status |= 0x1; // Set execution bit }}",
|
||||
inst.rs);
|
||||
|
||||
default:
|
||||
return fmt::format("// Unhandled VU0 format 0x14 subop: 0x{:X}", subop);
|
||||
}
|
||||
}
|
||||
|
||||
case VU0_VSUB_XYZ:
|
||||
{
|
||||
int destMask = (inst.function >> 21) & 0xF;
|
||||
|
||||
return fmt::format("{{ __m128 result = PS2_VSUB(ctx->vu0_vf[{}], ctx->vu0_vf[{}]);\n"
|
||||
" __m128 destMask = _mm_set_ps(\n"
|
||||
" {}f, {}f, {}f, {}f);\n"
|
||||
" // Blend the result with the destination register based on mask\n"
|
||||
" ctx->vu0_vf[{}] = _mm_blendv_ps(ctx->vu0_vf[{}], result, destMask); }}",
|
||||
inst.rs, inst.rt,
|
||||
(destMask & 0x8) ? 0xFFFFFFFF : 0,
|
||||
(destMask & 0x4) ? 0xFFFFFFFF : 0,
|
||||
(destMask & 0x2) ? 0xFFFFFFFF : 0,
|
||||
(destMask & 0x1) ? 0xFFFFFFFF : 0,
|
||||
inst.rd, inst.rd);
|
||||
}
|
||||
|
||||
case VU0OPS_VMFHL: // 0x1C - Move from High/Low (similar to PMFHL)
|
||||
{
|
||||
int subop = (inst.function >> 16) & 0x1F;
|
||||
switch (subop)
|
||||
{
|
||||
case 0: // LW variant - Extracts low word from accumulator
|
||||
return fmt::format("{{ \n"
|
||||
" float w = _mm_cvtss_f32(_mm_castsi128_ps(_mm_cvtsi32_si128(ctx->lo)));\n"
|
||||
" float z = 0.0f;\n"
|
||||
" float y = 0.0f;\n"
|
||||
" float x = 0.0f;\n"
|
||||
" ctx->vu0_vf[{}] = _mm_set_ps(w, z, y, x); }}",
|
||||
inst.rd);
|
||||
|
||||
case 1: // UW variant - Extracts upper word from accumulator
|
||||
return fmt::format("{{ \n"
|
||||
" float w = _mm_cvtss_f32(_mm_castsi128_ps(_mm_cvtsi32_si128(ctx->hi)));\n"
|
||||
" float z = 0.0f;\n"
|
||||
" float y = 0.0f;\n"
|
||||
" float x = 0.0f;\n"
|
||||
" ctx->vu0_vf[{}] = _mm_set_ps(w, z, y, x); }}",
|
||||
inst.rd);
|
||||
|
||||
case 2: // SLW variant - Saturated conversion of accumulator
|
||||
return fmt::format("{{ \n"
|
||||
" int64_t acc = ((int64_t)ctx->hi << 32) | ctx->lo;\n"
|
||||
" float result = (float)acc;\n"
|
||||
" // Clamp to prevent overflow\n"
|
||||
" if (result > FLT_MAX) result = FLT_MAX;\n"
|
||||
" if (result < -FLT_MAX) result = -FLT_MAX;\n"
|
||||
" ctx->vu0_vf[{}] = _mm_set_ps(result, 0.0f, 0.0f, 0.0f); }}",
|
||||
inst.rd);
|
||||
|
||||
default:
|
||||
return fmt::format("// Unhandled VU0OPS_VMFHL suboperation: 0x{:X}", subop);
|
||||
}
|
||||
}
|
||||
|
||||
case COP2_BC2F:
|
||||
switch (inst.rt)
|
||||
{
|
||||
@@ -1577,9 +1700,6 @@ namespace ps2recomp
|
||||
case COP2_MTVUCF:
|
||||
return fmt::format("ctx->vu0_cf[{}] = ctx->r[{}];", inst.rd, inst.rt);
|
||||
|
||||
case COP2_VMTIR:
|
||||
return fmt::format("ctx->vu0_i = (float)ctx->r[{}].m128_i32[0];", inst.rt);
|
||||
|
||||
case COP2_VCLIP: // VU0 Clipping operation (0x1E)
|
||||
return fmt::format("{{ float x = ctx->vu0_vf[{}].m128_f32[0]; "
|
||||
"float y = ctx->vu0_vf[{}].m128_f32[1]; "
|
||||
@@ -1753,6 +1873,9 @@ namespace ps2recomp
|
||||
return fmt::format("// VWAITQ - Wait for Q register operations to complete\n"
|
||||
" // need proper implementation for this\n");
|
||||
|
||||
case VU0OPS_VMTIR:
|
||||
return fmt::format("ctx->vu0_i = (float)ctx->r[{}].m128_i32[0];", inst.rt);
|
||||
|
||||
default:
|
||||
return fmt::format("// Unhandled VU0OPS function: 0x{:X}", inst.function);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user