Add guarded native draw replay, motion interpolation and stable world filtering

This commit is contained in:
Matthew Stanley
2026-10-03 23:35:11 -07:00
parent 030cb00c45
commit d2c8f03e76
66 changed files with 3454 additions and 76 deletions
+13 -3
View File
@@ -895,6 +895,13 @@ std::string CodeGenerator::generate_branch_condition(uint32_t instr, uint32_t ad
return keep_branch_if_wide("0 /* unknown branch condition: defaults to not-taken */");
}
std::string CodeGenerator::mod_instruction_call(uint32_t addr, uint32_t instr) const {
const bool selected = std::any_of(config_.mod_instruction_sites.begin(),
config_.mod_instruction_sites.end(), [=](uint32_t site) {
return (site & 0x1FFFFFFFu) == (addr & 0x1FFFFFFFu);
});
return selected ? fmt::format("psx_mod_instruction(cpu, 0x{:08X}u, 0x{:08X}u);\n", addr, instr) : "";
}
// [[draw_distance.clamp]]: a main-EXE ordering-table range guard. While a
// mod has the clamps on, the site's register is clamped to `max` before the
// instruction runs, so the guard keeps a far primitive in the last OT slot
@@ -935,9 +942,10 @@ std::string CodeGenerator::draw_distance_clamp_prefix(uint32_t addr,
std::string CodeGenerator::translate_instruction(uint32_t addr, uint32_t instr) {
std::string clamp = draw_distance_clamp_prefix(addr, instr);
if (clamp.empty()) return translate_instruction_core(addr, instr);
const std::string hook = mod_instruction_call(addr, instr);
if (clamp.empty()) return hook + translate_instruction_core(addr, instr);
// The core translation carries its own indent; give the clamp the same.
return config_.indent + clamp + "\n" + translate_instruction_core(addr, instr);
return hook + config_.indent + clamp + "\n" + translate_instruction_core(addr, instr);
}
std::string CodeGenerator::translate_instruction_core(uint32_t addr, uint32_t instr) {
@@ -1673,7 +1681,7 @@ std::string CodeGenerator::translate_instruction_core(uint32_t addr, uint32_t in
case 0x2A: code = translate_slt(instr); break; // slt
case 0x2B: code = translate_sltu(instr); break; // sltu
default:
code = fmt::format("/* TODO: SPECIAL funct=0x{:02X} */", funct);
code = fmt::format("/* undefined SPECIAL funct=0x{:02X}: R3000A-compatible no-op */", funct);
}
}
// Immediate and load/store instructions
@@ -2204,6 +2212,7 @@ std::string CodeGenerator::translate_basic_block(
// Jumps (j/jal/jr/jalr) and reserved words never reach
// generate_branch_condition; check them here.
check_explicit_branch_site(addr, block.exit_instr.instruction);
ss << config_.indent << mod_instruction_call(addr, instr);
std::string delay_saved_cond; // branch condition captured before delay
std::string delay_saved_target; // JR/JALR target captured before delay
@@ -3518,6 +3527,7 @@ void CodeGenerator::emit_runtime_externs(std::ostream& ss) const {
ss << "#endif\n";
ss << "extern int psx_game_text_native_ok(uint32_t addr); /* stale-static guard (dispatch shard) */\n";
ss << "extern int psx_datashard_enter(CPUState* cpu, uint32_t key); /* data-shard replay/capture (data_shards.c) */\n";
ss << "extern void psx_mod_instruction(CPUState*, uint32_t, uint32_t);\n";
ss << "extern int psx_mod_function_entry(CPUState* cpu, uint32_t address); /* trusted opt-in game-mod hook */\n";
ss << "extern int psx_ws_masked_reject(uint32_t flags, uint32_t mask); /* guarded packed-coordinate reject */\n";
ss << "extern int psx_ws_nclip_branch(uint32_t pc, uint32_t instr, int32_t mac0, int vanilla);\n";