Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 10 additions & 11 deletions ps2xRecomp/src/lib/vu_translation_helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,17 +164,16 @@ namespace ps2recomp

std::string CodeGenerator::translateVU_VCALLMSR(const Instruction &inst)
{
// VCALLMSR calls a VU0 microprogram at address stored in integer register
uint8_t vis_reg_idx = inst.rd; // Source integer register (vis)

return fmt::format(
"{{ "
" uint16_t instr_index = ctx->vi[{}] & 0x1FF; " // Get instruction index from VI[IS], mask to 9 bits
" uint32_t target_byte_addr = (uint32_t)instr_index << 3; " // Convert to byte address
" ctx->vu0_pc = target_byte_addr; "
" runtime->vu0StartMicroProgram(rdram, ctx, target_byte_addr); "
"}}",
vis_reg_idx);
// VCALLMSR calls a VU0 microprogram at the address held in CMSAR0. CMSAR0 is VU0 control register 27
// (written by CTC2 $vi27, see VU0_CR_CMSAR0), not one of the 16 VI registers, so it lives in ctx->vu0_cmsar0.
(void)inst;

return "{ "
" uint16_t instr_index = (uint16_t)(ctx->vu0_cmsar0 & 0x1FF); " // Get instruction index from CMSAR0, mask to 9 bits
" uint32_t target_byte_addr = (uint32_t)instr_index << 3; " // Convert to byte address
" ctx->vu0_pc = target_byte_addr; "
" runtime->vu0StartMicroProgram(rdram, ctx, target_byte_addr); "
"}";
}

std::string CodeGenerator::translateVU_VRNEXT(const Instruction &inst)
Expand Down
19 changes: 19 additions & 0 deletions ps2xTest/src/code_generator_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2035,6 +2035,25 @@ void register_code_generator_tests()
"VRXOR should keep the LFSR comment on its own line");
});

tc.Run("VCALLMSR starts the microprogram from CMSAR0, not a VI array slot", [](TestCase &t) {
CodeGenerator gen({}, {});

// VCALLMSR has no register operand; $vi27 in the assembly is CMSAR0 (VU0 control register 27).
Instruction inst{};
inst.opcode = OPCODE_COP2;
inst.function = VU0_S1_VCALLMSR;
inst.rd = 27;

const std::string generated = gen.translateVU_VCALLMSR(inst);
printGeneratedCode("VCALLMSR starts the microprogram from CMSAR0, not a VI array slot", generated);
t.IsTrue(generated.find("ctx->vu0_cmsar0") != std::string::npos,
"VCALLMSR should read the start address from CMSAR0");
t.IsTrue(generated.find("ctx->vi[") == std::string::npos,
"VCALLMSR must not index the 16-entry vi[] array with a control register number");
t.IsTrue(generated.find("runtime->vu0StartMicroProgram(") != std::string::npos,
"VCALLMSR should still start the VU0 microprogram");
});

tc.Run("resolveStubTarget allows leading underscore alias", [](TestCase &t) {
t.Equals(PS2Recompiler::resolveStubTarget("_rand"), StubTarget::Stub,
"_rand should resolve via rand stub alias");
Expand Down