Feature/stub by address (#61)

* feat: split runtime code in small files to be easy to develop

* feat: split stubs in inl files

* feat: function auto link function treat functions with underscore as same as without underscore

* feat: remove underscore prefix from stubs

* feat: thread and flags refactor

* feat: propagate request stop
feat: some elf validation on runtime

* feat: remove Z7 compiler options
feat: added a literal float case error on vu

* fix: fix critical recompiler error on marking pc calls

* feat: better system interrupt
refactor: small refactor on thread system

* feat: stubs implements for resident evil code veronica

* feat: merge fileio

* feat: stub by address

* feat: codegen now auto-routes J/JAL callssites with known relocation symbols to syscalls/stubs
This commit is contained in:
Ranieri
2026-02-18 01:35:20 -03:00
committed by GitHub
parent 4a538d3589
commit 043bf3bf8d
8 changed files with 158 additions and 17 deletions
+54 -10
View File
@@ -2,6 +2,7 @@
#include "ps2recomp/instructions.h"
#include "ps2recomp/ps2_recompiler.h"
#include "ps2recomp/types.h"
#include "ps2_runtime_calls.h"
#include <fmt/format.h>
#include <sstream>
#include <algorithm>
@@ -115,6 +116,11 @@ namespace ps2recomp
m_bootstrapInfo = info;
}
void CodeGenerator::setRelocationCallNames(const std::unordered_map<uint32_t, std::string> &callNames)
{
m_relocationCallNames = callNames;
}
std::string CodeGenerator::getFunctionName(uint32_t address) const
{
auto it = m_renamedFunctions.find(address);
@@ -260,18 +266,54 @@ namespace ps2recomp
}
else
{
ss << " {\n";
ss << fmt::format(" auto targetFn = runtime->lookupFunction(0x{:X}u);\n", target);
ss << " targetFn(rdram, ctx, runtime);\n";
if (branchInst.opcode == OPCODE_J)
bool emittedRelocCall = false;
const auto relocIt = m_relocationCallNames.find(branchInst.address);
if (relocIt != m_relocationCallNames.end() && !relocIt->second.empty())
{
ss << " return;\n";
const std::string_view resolvedSyscallName =
ps2_runtime_calls::resolveSyscallName(relocIt->second);
const std::string_view resolvedStubName =
ps2_runtime_calls::resolveStubName(relocIt->second);
if (!resolvedSyscallName.empty() || !resolvedStubName.empty())
{
const bool isSyscall = !resolvedSyscallName.empty();
const std::string_view handlerName = isSyscall ? resolvedSyscallName : resolvedStubName;
ss << " {\n";
ss << " const uint32_t __entryPc = ctx->pc;\n";
ss << " "
<< (isSyscall ? "ps2_syscalls::" : "ps2_stubs::")
<< handlerName << "(rdram, ctx, runtime);\n";
ss << " if (ctx->pc == __entryPc) { ctx->pc = getRegU32(ctx, 31); }\n";
ss << " }\n";
if (branchInst.opcode == OPCODE_J)
{
ss << " return;\n";
}
else
{
ss << fmt::format(" if (ctx->pc != 0x{:X}u) {{ return; }}\n", fallthroughPc);
}
emittedRelocCall = true;
}
}
else
if (!emittedRelocCall)
{
ss << fmt::format(" if (ctx->pc != 0x{:X}u) {{ return; }}\n", fallthroughPc);
ss << " {\n";
ss << fmt::format(" auto targetFn = runtime->lookupFunction(0x{:X}u);\n", target);
ss << " targetFn(rdram, ctx, runtime);\n";
if (branchInst.opcode == OPCODE_J)
{
ss << " return;\n";
}
else
{
ss << fmt::format(" if (ctx->pc != 0x{:X}u) {{ return; }}\n", fallthroughPc);
}
ss << " }\n";
}
ss << " }\n";
}
}
}
@@ -574,6 +616,8 @@ namespace ps2recomp
ss << "#include \"ps2_runtime.h\"\n";
ss << "#include \"ps2_recompiled_functions.h\"\n";
ss << "#include \"ps2_recompiled_stubs.h\"\n\n";
ss << "#include \"ps2_syscalls.h\"\n";
ss << "#include \"ps2_stubs.h\"\n\n";
}
std::unordered_set<uint32_t> internalTargets = collectInternalBranchTargets(function, instructions);
@@ -2104,7 +2148,7 @@ namespace ps2recomp
default:
return fmt::format("// Unhandled VU0 Special1 function: 0x{:X}", special1_func);
}
}
}
default:
return fmt::format("// Unhandled COP2 format: 0x{:X}", format);
}
@@ -2449,7 +2493,7 @@ namespace ps2recomp
// VCALLMS calls a VU0 microprogram at the specified immediate address.
// VU0 micro memory is 4KB = 512 instructions (8 bytes each). Index is 0-511.
uint16_t instr_index = static_cast<uint16_t>((inst.raw >> 6) & 0x1FF); // imm15[8:0]
uint32_t target_byte_addr = static_cast<uint32_t>(instr_index) << 3; // Convert instruction index to byte address
uint32_t target_byte_addr = static_cast<uint32_t>(instr_index) << 3; // Convert instruction index to byte address
return fmt::format(
"{{ "