mirror of
https://github.com/ran-j/PS2Recomp.git
synced 2026-09-26 08:51:05 -04:00
feat: added more instructions with revision
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user