mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-28 02:56:36 -04:00
Add opt-in native guest function replacement service
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
#include "code_generator.h"
|
||||
#include "control_flow.h"
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
static void check(bool condition, const char* message) {
|
||||
if (!condition) {
|
||||
std::fprintf(stderr, "FAIL: %s\n", message);
|
||||
std::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
constexpr uint32_t base = 0x80010000u;
|
||||
PSXRecomp::PS1Executable exe{};
|
||||
exe.header.load_address = exe.header.initial_pc = base;
|
||||
const uint32_t words[] = {0x24020001u, 0x10400002u, 0, 0x24030002u, 0x03E00008u, 0};
|
||||
for (uint32_t word : words)
|
||||
for (unsigned byte = 0; byte < 4; ++byte)
|
||||
exe.code_data.push_back(static_cast<uint8_t>(word >> (byte * 8)));
|
||||
exe.header.file_size = static_cast<uint32_t>(exe.code_data.size());
|
||||
PSXRecomp::Function function{};
|
||||
function.start_addr = base;
|
||||
function.size = exe.header.file_size;
|
||||
function.end_addr = base + function.size;
|
||||
function.name = "replacement_test";
|
||||
PSXRecomp::ControlFlowAnalyzer analyzer(exe);
|
||||
const auto flow = analyzer.analyze_function(function);
|
||||
PSXRecomp::CodeGenConfig config{};
|
||||
config.indent = " ";
|
||||
const auto generate = [&]() {
|
||||
PSXRecomp::CodeGenerator generator(exe, config);
|
||||
return generator.generate_function(function, flow).full_code;
|
||||
};
|
||||
const std::string hook = "if (psx_mod_try_function_replacement(cpu, 0x80010000u)) return;";
|
||||
check(generate().find("psx_mod_try_function_replacement") == std::string::npos,
|
||||
"default configuration emits no replacement call");
|
||||
config.mod_function_entry_funcs.insert(base + 4);
|
||||
check(generate().find("psx_mod_try_function_replacement") == std::string::npos,
|
||||
"listing a different address does not hook this function");
|
||||
config.mod_function_entry_funcs.insert(base);
|
||||
const auto code = generate();
|
||||
const auto at = code.find(hook);
|
||||
check(at != std::string::npos && code.find(hook, at + 1) == std::string::npos,
|
||||
"explicit function entry emits exactly one replacement call");
|
||||
check(code.find("psx_mod_function_entry(cpu, 0x80010000u);") < at,
|
||||
"existing preparation callback runs before replacement");
|
||||
check(at < code.find("block_80010000:"), "fallback body remains after replacement");
|
||||
const auto continuation = code.find("switch (_cont)");
|
||||
check(continuation != std::string::npos && continuation < at,
|
||||
"interior CPS resumes bypass fresh-entry replacement");
|
||||
PSXRecomp::CodeGenerator generator(exe, config);
|
||||
check(generator.build_shared_decls_header({}).find(
|
||||
"extern int psx_mod_try_function_replacement(CPUState* cpu, uint32_t address);") !=
|
||||
std::string::npos,
|
||||
"generated shards declare runtime replacement ABI");
|
||||
std::puts("PASS default-off, exact-entry, fallback and continuation-safe replacement codegen");
|
||||
}
|
||||
Reference in New Issue
Block a user