feat: added more instructions with revision

This commit is contained in:
Ran-j
2025-05-29 16:20:08 -03:00
parent 70f672cfd8
commit 342bb19607
5 changed files with 349 additions and 21 deletions
@@ -86,8 +86,14 @@ namespace ps2recomp
std::string translateVU_VRGET(const Instruction &inst);
std::string translateVU_VRINIT(const Instruction &inst);
std::string translateVU_VRXOR(const Instruction &inst);
std::string translateVU_VMADD_Field(const Instruction &inst);
std::string translateVU_VMINI_Field(const Instruction &inst);
std::string translateVU_VMADD(const Instruction &inst);
std::string translateVU_VMAX(const Instruction &inst);
std::string translateVU_VOPMSUB(const Instruction &inst);
std::string translateVU_VMINI(const Instruction &inst);
//
// Jump Table Generation
std::string generateJumpTableSwitch(const Instruction &inst, uint32_t tableAddress,
const std::vector<JumpTableEntry> &entries);
+31 -11
View File
@@ -80,8 +80,8 @@ namespace ps2recomp
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
// OPCODE_LQC2 = 0x36,
// OPCODE_SQC2 = 0x3E
};
// SPECIAL Function (bits 5-0) for OPCODE_SPECIAL
@@ -286,7 +286,7 @@ 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,
@@ -673,15 +673,35 @@ namespace ps2recomp
// 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 //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
};
VU0_CR_STATUS = 0, // Status/Control register
VU0_CR_MAC = 1, // MAC flags register
VU0_CR_CLIP = 5, // Clipping flags register
VU0_CR_R = 3, // R register (Random number)
VU0_CR_I = 4, // I register (Immediate)
// Add missing registers
VU0_CR_VPU_STAT = 2, // VPU-STAT register
VU0_CR_TPC = 6, // T (program counter) register
VU0_CR_CMSAR0 = 7, // Call/return address 0
VU0_CR_FBRST = 8, // VIF/VU reset register
VU0_CR_VPU_STAT2 = 9, // VPU-STAT register 2
VU0_CR_TPC2 = 10, // T (program counter) register 2
VU0_CR_CMSAR1 = 11, // Call/return address 1
VU0_CR_FBRST2 = 12, // VIF/VU reset register 2
VU0_CR_VPU_STAT3 = 13, // VPU-STAT register 3
VU0_CR_CMSAR2 = 14, // Call/return address 2
VU0_CR_FBRST3 = 15, // VIF/VU reset register 3
VU0_CR_VPU_STAT4 = 16, // VPU-STAT register 4
VU0_CR_CMSAR3 = 17, // Call/return address 3
VU0_CR_FBRST4 = 18, // VIF/VU reset register 4
VU0_CR_ACC = 20, // Accumulator register
VU0_CR_INFO = 21, // Information register
VU0_CR_CLIP2 = 22, // Clipping flags register 2
VU0_CR_P = 26, // P register
VU0_CR_XITOP = 27, // XITOP register
VU0_CR_ITOP = 28, // ITOP register
VU0_CR_TOP = 29 // TOP register
};
enum VU0OPSFunctions
{
VU0OPS_QMFC2_NI = 0x00, // Non-incrementing QMFC2
+276 -8
View File
@@ -580,15 +580,78 @@ namespace ps2recomp
case OPCODE_BLEZL:
case OPCODE_BGTZL:
return fmt::format("// Likely branch instruction at 0x{:X} - Handled by branch logic", inst.address);
case OPCODE_LDL:
return fmt::format("{{ uint32_t addr = ADD32(GPR_U32(ctx, {}), {}); "
"uint32_t shift = (addr & 7) << 3; "
"uint64_t mask = 0xFFFFFFFFFFFFFFFFULL << shift; "
"uint64_t aligned_data = READ64(addr & ~7ULL); "
"SET_GPR_U64(ctx, {}, (GPR_U64(ctx, {}) & ~mask) | (aligned_data & mask)); }}",
inst.rs, inst.simmediate, inst.rt, inst.rt);
case OPCODE_LDR:
case OPCODE_SDL:
case OPCODE_SDR:
return fmt::format("{{ uint32_t addr = ADD32(GPR_U32(ctx, {}), {}); "
"uint32_t shift = ((~addr) & 7) << 3; "
"uint64_t mask = 0xFFFFFFFFFFFFFFFFULL >> shift; "
"uint64_t aligned_data = READ64(addr & ~7ULL); "
"SET_GPR_U64(ctx, {}, (GPR_U64(ctx, {}) & ~mask) | (aligned_data & mask)); }}",
inst.rs, inst.simmediate, inst.rt, inst.rt);
case OPCODE_LWL:
return fmt::format("{{ uint32_t addr = ADD32(GPR_U32(ctx, {}), {}); "
"uint32_t shift = (addr & 3) << 3; "
"uint32_t mask = 0xFFFFFFFF << shift; "
"uint32_t aligned_data = READ32(addr & ~3); "
"SET_GPR_U32(ctx, {}, (GPR_U32(ctx, {}) & ~mask) | (aligned_data & mask)); }}",
inst.rs, inst.simmediate, inst.rt, inst.rt);
case OPCODE_LWR:
return fmt::format("{{ uint32_t addr = ADD32(GPR_U32(ctx, {}), {}); "
"uint32_t shift = ((~addr) & 3) << 3; "
"uint32_t mask = 0xFFFFFFFF >> shift; "
"uint32_t aligned_data = READ32(addr & ~3); "
"SET_GPR_U32(ctx, {}, (GPR_U32(ctx, {}) & ~mask) | (aligned_data & mask)); }}",
inst.rs, inst.simmediate, inst.rt, inst.rt);
case OPCODE_SWL:
return fmt::format("{{ uint32_t addr = ADD32(GPR_U32(ctx, {}), {}); "
"uint32_t shift = (addr & 3) << 3; "
"uint32_t mask = 0xFFFFFFFF << shift; "
"uint32_t aligned_addr = addr & ~3; "
"uint32_t old_data = READ32(aligned_addr); "
"uint32_t new_data = (old_data & ~mask) | (GPR_U32(ctx, {}) & mask); "
"WRITE32(aligned_addr, new_data); }}",
inst.rs, inst.simmediate, inst.rt);
case OPCODE_SWR:
return fmt::format("//Unhandled Unaligned load/store instruction 0x{:X} not implemented", inst.opcode);
return fmt::format("{{ uint32_t addr = ADD32(GPR_U32(ctx, {}), {}); "
"uint32_t shift = ((~addr) & 3) << 3; "
"uint32_t mask = 0xFFFFFFFF >> shift; "
"uint32_t aligned_addr = addr & ~3; "
"uint32_t old_data = READ32(aligned_addr); "
"uint32_t new_data = (old_data & ~mask) | (GPR_U32(ctx, {}) & mask); "
"WRITE32(aligned_addr, new_data); }}",
inst.rs, inst.simmediate, inst.rt);
case OPCODE_SDL:
return fmt::format("{{ uint32_t addr = ADD32(GPR_U32(ctx, {}), {}); "
"uint32_t shift = (addr & 7) << 3; "
"uint64_t mask = 0xFFFFFFFFFFFFFFFFULL << shift; "
"uint64_t aligned_addr = addr & ~7ULL; "
"uint64_t old_data = READ64(aligned_addr); "
"uint64_t new_data = (old_data & ~mask) | (GPR_U64(ctx, {}) & mask); "
"WRITE64(aligned_addr, new_data); }}",
inst.rs, inst.simmediate, inst.rt);
case OPCODE_SDR:
return fmt::format("{{ uint32_t addr = ADD32(GPR_U32(ctx, {}), {}); "
"uint32_t shift = ((~addr) & 7) << 3; "
"uint64_t mask = 0xFFFFFFFFFFFFFFFFULL >> shift; "
"uint64_t aligned_addr = addr & ~7ULL; "
"uint64_t old_data = READ64(aligned_addr); "
"uint64_t new_data = (old_data & ~mask) | (GPR_U64(ctx, {}) & mask); "
"WRITE64(aligned_addr, new_data); }}",
inst.rs, inst.simmediate, inst.rt);
case OPCODE_CACHE:
return "// CACHE instruction (ignored)";
case OPCODE_PREF:
@@ -645,7 +708,20 @@ namespace ps2recomp
case SPECIAL_DIVU:
return fmt::format("{{ uint32_t divisor = GPR_U32(ctx, {}); if (divisor != 0) {{ ctx->lo = GPR_U32(ctx, {}) / divisor; ctx->hi = GPR_U32(ctx, {}) % divisor; }} else {{ ctx->lo = 0xFFFFFFFF; ctx->hi = GPR_U32(ctx,{}); }} }}", inst.rt, inst.rs, inst.rt, inst.rs, inst.rt);
case SPECIAL_ADD:
return fmt::format("SET_GPR_S32(ctx, {}, ADD32(GPR_U32(ctx, {}), GPR_U32(ctx, {})));", inst.rd, inst.rs, inst.rt);
return fmt::format(
"if (runtime->check_overflow) {{ "
" int32_t rs_val = GPR_S32(ctx, {}); "
" int32_t rt_val = GPR_S32(ctx, {}); "
" int64_t result = (int64_t)rs_val + (int64_t)rt_val; "
" if (result > INT32_MAX || result < INT32_MIN) {{ "
" runtime->SignalException(ctx, EXCEPTION_INTEGER_OVERFLOW); "
" }} else {{ "
" SET_GPR_S32(ctx, {}, (int32_t)result); "
" }} "
"}} else {{ "
" SET_GPR_S32(ctx, {}, ADD32(GPR_S32(ctx, {}), GPR_S32(ctx, {}))); "
"}}",
inst.rs, inst.rt, inst.rd, inst.rd, inst.rs, inst.rt);
case SPECIAL_ADDU:
return fmt::format("SET_GPR_U32(ctx, {}, ADD32(GPR_U32(ctx, {}), GPR_U32(ctx, {})));", inst.rd, inst.rs, inst.rt);
case SPECIAL_SUB:
@@ -1349,14 +1425,56 @@ namespace ps2recomp
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_status);", rt);
case VU0_CR_MAC:
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_mac_flags);", rt);
case VU0_CR_CLIP:
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_clip_flags);", rt);
case VU0_CR_VPU_STAT:
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_vpu_stat);", rt);
case VU0_CR_R:
return fmt::format("SET_GPR_VEC(ctx, {}, (__m128i)ctx->vu0_r);", rt);
case VU0_CR_I:
return fmt::format("SET_GPR_U32(ctx, {}, *(uint32_t*)&ctx->vu0_i);", rt);
case VU0_CR_CLIP:
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_clip_flags);", rt);
case VU0_CR_TPC:
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_tpc);", rt);
case VU0_CR_CMSAR0:
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_cmsar0);", rt);
case VU0_CR_FBRST:
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_fbrst);", rt);
case VU0_CR_VPU_STAT2:
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_vpu_stat2);", rt);
case VU0_CR_TPC2:
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_tpc2);", rt);
case VU0_CR_CMSAR1:
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_cmsar1);", rt);
case VU0_CR_FBRST2:
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_fbrst2);", rt);
case VU0_CR_VPU_STAT3:
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_vpu_stat3);", rt);
case VU0_CR_CMSAR2:
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_cmsar2);", rt);
case VU0_CR_FBRST3:
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_fbrst3);", rt);
case VU0_CR_VPU_STAT4:
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_vpu_stat4);", rt);
case VU0_CR_CMSAR3:
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_cmsar3);", rt);
case VU0_CR_FBRST4:
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_fbrst4);", rt);
case VU0_CR_ACC:
return fmt::format("SET_GPR_VEC(ctx, {}, (__m128i)ctx->vu0_acc);", rt);
case VU0_CR_INFO:
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_info);", rt);
case VU0_CR_CLIP2:
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_clip_flags2);", rt);
case VU0_CR_P:
return fmt::format("SET_GPR_U32(ctx, {}, *(uint32_t*)&ctx->vu0_p);", rt);
case VU0_CR_XITOP:
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_xitop);", rt);
case VU0_CR_ITOP:
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_itop);", rt);
case VU0_CR_TOP:
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_top);", rt);
default:
return fmt::format("// Unhandled CFC2 VU CReg: {}", rd);
return fmt::format("// Unimplemented CFC2 VU CReg: {}", rt);
}
}
case COP2_QMTC2:
@@ -1369,14 +1487,56 @@ namespace ps2recomp
return fmt::format("ctx->vu0_status = GPR_U32(ctx, {}) & 0xFFFF;", rt);
case VU0_CR_MAC:
return fmt::format("ctx->vu0_mac_flags = GPR_U32(ctx, {});", rt);
case VU0_CR_VPU_STAT:
return fmt::format("ctx->vu0_vpu_stat = GPR_U32(ctx, {});", rt);
case VU0_CR_CLIP:
return fmt::format("ctx->vu0_clip_flags = GPR_U32(ctx, {});", rt);
case VU0_CR_R:
return fmt::format("ctx->vu0_r = (__m128)GPR_VEC(ctx, {});", rt);
case VU0_CR_I:
return fmt::format("ctx->vu0_i = *(float*)&GPR_U32(ctx, {});", rt);
case VU0_CR_TPC:
return fmt::format("ctx->vu0_tpc = GPR_U32(ctx, {});", rt);
case VU0_CR_CMSAR0:
return fmt::format("ctx->vu0_cmsar0 = GPR_U32(ctx, {});", rt);
case VU0_CR_FBRST:
return fmt::format("ctx->vu0_fbrst = GPR_U32(ctx, {});", rt);
case VU0_CR_VPU_STAT2:
return fmt::format("ctx->vu0_vpu_stat2 = GPR_U32(ctx, {});", rt);
case VU0_CR_TPC2:
return fmt::format("ctx->vu0_tpc2 = GPR_U32(ctx, {});", rt);
case VU0_CR_CMSAR1:
return fmt::format("ctx->vu0_cmsar1 = GPR_U32(ctx, {});", rt);
case VU0_CR_FBRST2:
return fmt::format("ctx->vu0_fbrst2 = GPR_U32(ctx, {});", rt);
case VU0_CR_VPU_STAT3:
return fmt::format("ctx->vu0_vpu_stat3 = GPR_U32(ctx, {});", rt);
case VU0_CR_CMSAR2:
return fmt::format("ctx->vu0_cmsar2 = GPR_U32(ctx, {});", rt);
case VU0_CR_FBRST3:
return fmt::format("ctx->vu0_fbrst3 = GPR_U32(ctx, {});", rt);
case VU0_CR_VPU_STAT4:
return fmt::format("ctx->vu0_vpu_stat4 = GPR_U32(ctx, {});", rt);
case VU0_CR_CMSAR3:
return fmt::format("ctx->vu0_cmsar3 = GPR_U32(ctx, {});", rt);
case VU0_CR_FBRST4:
return fmt::format("ctx->vu0_fbrst4 = GPR_U32(ctx, {});", rt);
case VU0_CR_ACC:
return fmt::format("ctx->vu0_acc = (__m128)GPR_VEC(ctx, {});", rt);
case VU0_CR_INFO:
return fmt::format("ctx->vu0_info = GPR_U32(ctx, {});", rt);
case VU0_CR_CLIP2:
return fmt::format("ctx->vu0_clip_flags2 = GPR_U32(ctx, {});", rt);
case VU0_CR_P:
return fmt::format("ctx->vu0_p = *(float*)&GPR_U32(ctx, {});", rt);
case VU0_CR_XITOP:
return fmt::format("ctx->vu0_xitop = GPR_U32(ctx, {}) & 0x3FF;", rt);
case VU0_CR_ITOP:
return fmt::format("ctx->vu0_itop = GPR_U32(ctx, {}) & 0x3FF;", rt);
case VU0_CR_TOP:
return fmt::format("ctx->vu0_top = GPR_U32(ctx, {}) & 0x3FF;", rt);
default:
return fmt::format("// Unhandled CTC2 VU CReg: {}", rd);
return fmt::format("// Unimplemented CTC2 VU CReg: {}", rd);
}
}
case COP2_BC:
@@ -1490,6 +1650,27 @@ namespace ps2recomp
return fmt::format("ctx->vu0_vf[{}] = PS2_VSUB(ctx->vu0_vf[{}], _mm_set1_ps(ctx->vu0_i));", inst.rd, inst.rs);
case VU0_S1_VMULi:
return fmt::format("ctx->vu0_vf[{}] = PS2_VMUL(ctx->vu0_vf[{}], _mm_set1_ps(ctx->vu0_i));", inst.rd, inst.rs);
case VU0_S1_VMADDx:
case VU0_S1_VMADDy:
case VU0_S1_VMADDz:
case VU0_S1_VMADDw:
return translateVU_VMADD_Field(inst);
case VU0_S1_VMAXx:
return fmt::format("ctx->vu0_vf[{}] = _mm_max_ps(ctx->vu0_vf[{}], _mm_shuffle_ps(ctx->vu0_vf[{}], ctx->vu0_vf[{}], _MM_SHUFFLE(0,0,0,0)));", inst.rd, inst.rs, inst.rt, inst.rt);
case VU0_S1_VMAXz:
return fmt::format("ctx->vu0_vf[{}] = _mm_max_ps(ctx->vu0_vf[{}], _mm_shuffle_ps(ctx->vu0_vf[{}], ctx->vu0_vf[{}], _MM_SHUFFLE(2,2,2,2)));", inst.rd, inst.rs, inst.rt, inst.rt);
case VU0_S1_VMINIx:
case VU0_S1_VMINIy:
case VU0_S1_VMINIw:
return translateVU_VMINI_Field(inst);
case VU0_S1_VMADD:
return translateVU_VMADD(inst);
case VU0_S1_VMAX:
return translateVU_VMAX(inst);
case VU0_S1_VOPMSUB:
return translateVU_VOPMSUB(inst);
case VU0_S1_VMINI:
return translateVU_VMINI(inst);
default:
return fmt::format("// Unhandled VU0 Special1 function: 0x{:X}", vu_func);
}
@@ -1808,6 +1989,93 @@ namespace ps2recomp
return fmt::format("// Unhandled VU0 VRNEXT instruction: 0x{:X}", inst.function);
}
std::string CodeGenerator::translateVU_VMADD_Field(const Instruction &inst)
{
uint8_t dest_mask = inst.vectorInfo.vectorField;
uint8_t field = inst.function & 0x3; // Extract field from function code
// Pre-construct the shuffle pattern to avoid format string issues
std::string shuffle_pattern = fmt::format("_MM_SHUFFLE({},{},{},{})", field, field, field, field);
return fmt::format("{{ __m128 mul_res = PS2_VMUL(ctx->vu0_vf[{}], _mm_shuffle_ps(ctx->vu0_vf[{}], ctx->vu0_vf[{}], {})); "
"__m128 res = PS2_VADD(ctx->vu0_acc, mul_res); "
"__m128i mask = _mm_set_epi32({}, {}, {}, {}); "
"ctx->vu0_vf[{}] = _mm_blendv_ps(ctx->vu0_vf[{}], res, _mm_castsi128_ps(mask)); "
"ctx->vu0_acc = res; }}",
inst.rs, inst.rt, inst.rt, shuffle_pattern,
(dest_mask & 0x8) ? -1 : 0, (dest_mask & 0x4) ? -1 : 0,
(dest_mask & 0x2) ? -1 : 0, (dest_mask & 0x1) ? -1 : 0,
inst.rd, inst.rd);
}
std::string CodeGenerator::translateVU_VMINI_Field(const Instruction &inst)
{
uint8_t dest_mask = inst.vectorInfo.vectorField;
uint8_t field = inst.function & 0x3;
std::string shuffle_pattern = fmt::format("_MM_SHUFFLE({},{},{},{})", field, field, field, field);
return fmt::format("{{ __m128 res = _mm_min_ps(ctx->vu0_vf[{}], _mm_shuffle_ps(ctx->vu0_vf[{}], ctx->vu0_vf[{}], {})); "
"__m128i mask = _mm_set_epi32({}, {}, {}, {}); "
"ctx->vu0_vf[{}] = _mm_blendv_ps(ctx->vu0_vf[{}], res, _mm_castsi128_ps(mask)); }}",
inst.rs, inst.rt, inst.rt, shuffle_pattern,
(dest_mask & 0x8) ? -1 : 0, (dest_mask & 0x4) ? -1 : 0,
(dest_mask & 0x2) ? -1 : 0, (dest_mask & 0x1) ? -1 : 0,
inst.rd, inst.rd);
}
std::string CodeGenerator::translateVU_VMADD(const Instruction &inst)
{
uint8_t dest_mask = inst.vectorInfo.vectorField;
return fmt::format("{{ __m128 mul_res = PS2_VMUL(ctx->vu0_vf[{}], ctx->vu0_vf[{}]); "
"__m128 res = PS2_VADD(ctx->vu0_acc, mul_res); "
"__m128i mask = _mm_set_epi32({}, {}, {}, {}); "
"ctx->vu0_vf[{}] = _mm_blendv_ps(ctx->vu0_vf[{}], res, _mm_castsi128_ps(mask)); "
"ctx->vu0_acc = res; }}",
inst.rs, inst.rt,
(dest_mask & 0x8) ? -1 : 0, (dest_mask & 0x4) ? -1 : 0,
(dest_mask & 0x2) ? -1 : 0, (dest_mask & 0x1) ? -1 : 0,
inst.rd, inst.rd);
}
std::string CodeGenerator::translateVU_VMAX(const Instruction &inst)
{
uint8_t dest_mask = inst.vectorInfo.vectorField;
return fmt::format("{{ __m128 res = _mm_max_ps(ctx->vu0_vf[{}], ctx->vu0_vf[{}]); "
"__m128i mask = _mm_set_epi32({}, {}, {}, {}); "
"ctx->vu0_vf[{}] = _mm_blendv_ps(ctx->vu0_vf[{}], res, _mm_castsi128_ps(mask)); }}",
inst.rs, inst.rt,
(dest_mask & 0x8) ? -1 : 0, (dest_mask & 0x4) ? -1 : 0,
(dest_mask & 0x2) ? -1 : 0, (dest_mask & 0x1) ? -1 : 0,
inst.rd, inst.rd);
}
std::string CodeGenerator::translateVU_VOPMSUB(const Instruction &inst)
{
uint8_t dest_mask = inst.vectorInfo.vectorField;
return fmt::format("{{ __m128 mul_res = PS2_VMUL(ctx->vu0_vf[{}], ctx->vu0_vf[{}]); "
"__m128 res = PS2_VSUB(ctx->vu0_acc, mul_res); "
"__m128i mask = _mm_set_epi32({}, {}, {}, {}); "
"ctx->vu0_vf[{}] = _mm_blendv_ps(ctx->vu0_vf[{}], res, _mm_castsi128_ps(mask)); "
"ctx->vu0_acc = res; }}",
inst.rs, inst.rt,
(dest_mask & 0x8) ? -1 : 0, (dest_mask & 0x4) ? -1 : 0,
(dest_mask & 0x2) ? -1 : 0, (dest_mask & 0x1) ? -1 : 0,
inst.rd, inst.rd);
}
std::string CodeGenerator::translateVU_VMINI(const Instruction &inst)
{
uint8_t dest_mask = inst.vectorInfo.vectorField;
return fmt::format("{{ __m128 res = _mm_min_ps(ctx->vu0_vf[{}], ctx->vu0_vf[{}]); "
"__m128i mask = _mm_set_epi32({}, {}, {}, {}); "
"ctx->vu0_vf[{}] = _mm_blendv_ps(ctx->vu0_vf[{}], res, _mm_castsi128_ps(mask)); }}",
inst.rs, inst.rt,
(dest_mask & 0x8) ? -1 : 0, (dest_mask & 0x4) ? -1 : 0,
(dest_mask & 0x2) ? -1 : 0, (dest_mask & 0x1) ? -1 : 0,
inst.rd, inst.rd);
}
std::string CodeGenerator::translateVU_VRGET(const Instruction &inst)
{
uint8_t dest_mask = inst.vectorInfo.vectorField;
+12 -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 = 0x1FFFFFF; // 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
@@ -50,6 +50,11 @@ constexpr uint32_t PS2_GS_PRIV_REG_SIZE = 0x2000;
#define PS2_FIO_S_IFDIR 0x1000
#define PS2_FIO_S_IFREG 0x2000
enum PS2Exception
{
EXCEPTION_INTEGER_OVERFLOW = 0x0C, // From MIPS spec
};
// PS2 CPU context (R5900)
struct R5900Context
{
@@ -383,9 +388,15 @@ public:
void registerFunction(uint32_t address, RecompiledFunction func);
RecompiledFunction lookupFunction(uint32_t address);
void SignalException(R5900Context* ctx, PS2Exception exception);
private:
void HandleIntegerOverflow(R5900Context* ctx);
private:
PS2Memory m_memory;
R5900Context m_cpuContext;
bool check_overflow = false;
std::unordered_map<uint32_t, RecompiledFunction> m_functionTable;
+23
View File
@@ -171,6 +171,29 @@ PS2Runtime::RecompiledFunction PS2Runtime::lookupFunction(uint32_t address)
return defaultFunction;
}
void PS2Runtime::SignalException(R5900Context *ctx, PS2Exception exception)
{
if (exception == EXCEPTION_INTEGER_OVERFLOW)
{
// PS2 behavior: jump to exception handler
HandleIntegerOverflow(ctx);
}
}
void PS2Runtime::HandleIntegerOverflow(R5900Context *ctx)
{
std::cerr << "Integer overflow exception at PC: 0x" << std::hex << ctx->pc << std::dec << std::endl;
// Set the EPC (Exception Program Counter) to the current PC
m_cpuContext.cop0_epc = ctx->pc;
// Set the cause register to indicate an integer overflow
m_cpuContext.cop0_cause |= (EXCEPTION_INTEGER_OVERFLOW << 2);
// Jump to the exception handler (usually at 0x80000000)
m_cpuContext.pc = 0x80000000; // Default PS2 exception handler address
}
void PS2Runtime::run()
{
RecompiledFunction entryPoint = lookupFunction(m_cpuContext.pc);