feat: added auto function mapper to code gen

This commit is contained in:
Ran-j
2025-04-17 01:54:07 -03:00
parent 23bb92bd4a
commit fa676bd692
3 changed files with 265 additions and 2 deletions
@@ -4,6 +4,7 @@
#include "ps2recomp/types.h"
#include <string>
#include <vector>
#include <map>
namespace ps2recomp
{
@@ -15,6 +16,7 @@ namespace ps2recomp
~CodeGenerator();
std::string generateFunction(const Function &function, const std::vector<Instruction> &instructions, const bool &useHeaders);
std::string generateFunctionRegistration(const std::vector<Function> &functions, const std::map<uint32_t, std::string> &stubs);
std::string generateMacroHeader();
std::string handleBranchDelaySlots(const Instruction &branchInst, const Instruction &delaySlot);
+254
View File
@@ -3,6 +3,7 @@
#include <fmt/format.h>
#include <sstream>
#include <algorithm>
#include <unordered_set>
namespace ps2recomp
{
@@ -2377,6 +2378,259 @@ namespace ps2recomp
return ss.str();
}
std::string CodeGenerator::generateFunctionRegistration(const std::vector<Function> &functions,
const std::map<uint32_t, std::string> &stubs)
{
static const std::unordered_map<std::string, std::pair<uint32_t, std::string>> systemCalls = {
// Memory management
{"FlushCache", {0x0040, "ps2_syscalls::FlushCache"}},
{"ResetEE", {0x0042, "ps2_syscalls::ResetEE"}},
{"SetMemoryMode", {0x0043, "ps2_syscalls::SetMemoryMode"}},
// Thread management
{"CreateThread", {0x0055, "ps2_syscalls::CreateThread"}},
{"DeleteThread", {0x0056, "ps2_syscalls::DeleteThread"}},
{"StartThread", {0x0057, "ps2_syscalls::StartThread"}},
{"ExitThread", {0x003C, "ps2_syscalls::ExitThread"}},
{"ExitDeleteThread", {0x003D, "ps2_syscalls::ExitDeleteThread"}},
{"TerminateThread", {0x0058, "ps2_syscalls::TerminateThread"}},
{"SuspendThread", {0x0059, "ps2_syscalls::SuspendThread"}},
{"ResumeThread", {0x005A, "ps2_syscalls::ResumeThread"}},
{"GetThreadId", {0x0047, "ps2_syscalls::GetThreadId"}},
{"ReferThreadStatus", {0x005B, "ps2_syscalls::ReferThreadStatus"}},
{"SleepThread", {0x005C, "ps2_syscalls::SleepThread"}},
{"WakeupThread", {0x005D, "ps2_syscalls::WakeupThread"}},
{"iWakeupThread", {0x005E, "ps2_syscalls::iWakeupThread"}},
{"ChangeThreadPriority", {0x005F, "ps2_syscalls::ChangeThreadPriority"}},
{"RotateThreadReadyQueue", {0x0060, "ps2_syscalls::RotateThreadReadyQueue"}},
{"ReleaseWaitThread", {0x0061, "ps2_syscalls::ReleaseWaitThread"}},
{"iReleaseWaitThread", {0x0062, "ps2_syscalls::iReleaseWaitThread"}},
// Semaphores
{"CreateSema", {0x0064, "ps2_syscalls::CreateSema"}},
{"DeleteSema", {0x0065, "ps2_syscalls::DeleteSema"}},
{"SignalSema", {0x0066, "ps2_syscalls::SignalSema"}},
{"iSignalSema", {0x0067, "ps2_syscalls::iSignalSema"}},
{"WaitSema", {0x0068, "ps2_syscalls::WaitSema"}},
{"PollSema", {0x0069, "ps2_syscalls::PollSema"}},
{"iPollSema", {0x006A, "ps2_syscalls::iPollSema"}},
{"ReferSemaStatus", {0x006B, "ps2_syscalls::ReferSemaStatus"}},
{"iReferSemaStatus", {0x006C, "ps2_syscalls::iReferSemaStatus"}},
// Event flags
{"CreateEventFlag", {0x006D, "ps2_syscalls::CreateEventFlag"}},
{"DeleteEventFlag", {0x006E, "ps2_syscalls::DeleteEventFlag"}},
{"SetEventFlag", {0x006F, "ps2_syscalls::SetEventFlag"}},
{"iSetEventFlag", {0x0070, "ps2_syscalls::iSetEventFlag"}},
{"ClearEventFlag", {0x0071, "ps2_syscalls::ClearEventFlag"}},
{"iClearEventFlag", {0x0072, "ps2_syscalls::iClearEventFlag"}},
{"WaitEventFlag", {0x0073, "ps2_syscalls::WaitEventFlag"}},
{"PollEventFlag", {0x0074, "ps2_syscalls::PollEventFlag"}},
{"iPollEventFlag", {0x0075, "ps2_syscalls::iPollEventFlag"}},
{"ReferEventFlagStatus", {0x0076, "ps2_syscalls::ReferEventFlagStatus"}},
{"iReferEventFlagStatus", {0x0077, "ps2_syscalls::iReferEventFlagStatus"}},
// Alarm
{"SetAlarm", {0x0078, "ps2_syscalls::SetAlarm"}},
{"iSetAlarm", {0x0079, "ps2_syscalls::iSetAlarm"}},
{"CancelAlarm", {0x007A, "ps2_syscalls::CancelAlarm"}},
{"iCancelAlarm", {0x007B, "ps2_syscalls::iCancelAlarm"}},
// Intr handlers
{"EnableIntc", {0x0080, "ps2_syscalls::EnableIntc"}},
{"DisableIntc", {0x0081, "ps2_syscalls::DisableIntc"}},
{"EnableDmac", {0x0082, "ps2_syscalls::EnableDmac"}},
{"DisableDmac", {0x0083, "ps2_syscalls::DisableDmac"}},
// RPC and IOP
{"SifStopModule", {0x0085, "ps2_syscalls::SifStopModule"}},
{"SifLoadModule", {0x0086, "ps2_syscalls::SifLoadModule"}},
{"SifInitRpc", {0x00A5, "ps2_syscalls::SifInitRpc"}},
{"SifBindRpc", {0x00A6, "ps2_syscalls::SifBindRpc"}},
{"SifCallRpc", {0x00A7, "ps2_syscalls::SifCallRpc"}},
{"SifRegisterRpc", {0x00A8, "ps2_syscalls::SifRegisterRpc"}},
{"SifCheckStatRpc", {0x00A9, "ps2_syscalls::SifCheckStatRpc"}},
{"SifSetRpcQueue", {0x00AA, "ps2_syscalls::SifSetRpcQueue"}},
{"SifRemoveRpcQueue", {0x00AB, "ps2_syscalls::SifRemoveRpcQueue"}},
{"SifRemoveRpc", {0x00AC, "ps2_syscalls::SifRemoveRpc"}},
// IO system calls
{"fioOpen", {0x00B0, "ps2_syscalls::fioOpen"}},
{"fioClose", {0x00B1, "ps2_syscalls::fioClose"}},
{"fioRead", {0x00B2, "ps2_syscalls::fioRead"}},
{"fioWrite", {0x00B3, "ps2_syscalls::fioWrite"}},
{"fioLseek", {0x00B4, "ps2_syscalls::fioLseek"}},
{"fioMkdir", {0x00B5, "ps2_syscalls::fioMkdir"}},
{"fioChdir", {0x00B6, "ps2_syscalls::fioChdir"}},
{"fioRmdir", {0x00B7, "ps2_syscalls::fioRmdir"}},
{"fioGetstat", {0x00B8, "ps2_syscalls::fioGetstat"}},
{"fioRemove", {0x00B9, "ps2_syscalls::fioRemove"}},
// Graphics
{"GsSetCrt", {0x00C0, "ps2_syscalls::GsSetCrt"}},
{"GsGetIMR", {0x00C1, "ps2_syscalls::GsGetIMR"}},
{"GsPutIMR", {0x00C2, "ps2_syscalls::GsPutIMR"}},
{"GsSetVideoMode", {0x00C3, "ps2_syscalls::GsSetVideoMode"}},
// Miscellaneous
{"GetOsdConfigParam", {0x00F0, "ps2_syscalls::GetOsdConfigParam"}},
{"SetOsdConfigParam", {0x00F1, "ps2_syscalls::SetOsdConfigParam"}},
{"GetRomName", {0x00F2, "ps2_syscalls::GetRomName"}},
{"SifLoadElfPart", {0x00F6, "ps2_syscalls::SifLoadElfPart"}},
{"sceSifLoadModule", {0x0122, "ps2_syscalls::sceSifLoadModule"}},
{"TODO", {0x0000, "ps2_syscalls::TODO"}}};
static const std::unordered_map<std::string, std::string> libraryStubs = {
// Memory operations
{"malloc", "ps2_stubs::malloc"},
{"free", "ps2_stubs::free"},
{"calloc", "ps2_stubs::calloc"},
{"realloc", "ps2_stubs::realloc"},
{"memcpy", "ps2_stubs::memcpy"},
{"memset", "ps2_stubs::memset"},
{"memmove", "ps2_stubs::memmove"},
{"memcmp", "ps2_stubs::memcmp"},
// String operations
{"strcpy", "ps2_stubs::strcpy"},
{"strncpy", "ps2_stubs::strncpy"},
{"strlen", "ps2_stubs::strlen"},
{"strcmp", "ps2_stubs::strcmp"},
{"strncmp", "ps2_stubs::strncmp"},
{"strcat", "ps2_stubs::strcat"},
{"strncat", "ps2_stubs::strncat"},
{"strchr", "ps2_stubs::strchr"},
{"strrchr", "ps2_stubs::strrchr"},
{"strstr", "ps2_stubs::strstr"},
// I/O operations
{"printf", "ps2_stubs::printf"},
{"sprintf", "ps2_stubs::sprintf"},
{"snprintf", "ps2_stubs::snprintf"},
{"puts", "ps2_stubs::puts"},
{"fopen", "ps2_stubs::fopen"},
{"fclose", "ps2_stubs::fclose"},
{"fread", "ps2_stubs::fread"},
{"fwrite", "ps2_stubs::fwrite"},
{"fprintf", "ps2_stubs::fprintf"},
{"fseek", "ps2_stubs::fseek"},
{"ftell", "ps2_stubs::ftell"},
{"fflush", "ps2_stubs::fflush"},
// Math functions
{"sqrt", "ps2_stubs::sqrt"},
{"sin", "ps2_stubs::sin"},
{"cos", "ps2_stubs::cos"},
{"tan", "ps2_stubs::tan"},
{"atan2", "ps2_stubs::atan2"},
{"pow", "ps2_stubs::pow"},
{"exp", "ps2_stubs::exp"},
{"log", "ps2_stubs::log"},
{"log10", "ps2_stubs::log10"},
{"ceil", "ps2_stubs::ceil"},
{"floor", "ps2_stubs::floor"},
{"fabs", "ps2_stubs::fabs"},
{"TODO", "ps2_stubs::TODO"}};
std::stringstream ss;
std::unordered_set<uint32_t> registeredAddresses;
// Begin function
ss << "#include \"ps2_runtime.h\"\n";
ss << "#include \"ps2_recompiled_functions.h\"\n";
ss << "#include \"ps2_stubs.h\"\n\n";
ss << "// Default handler for unimplemented syscalls/functions\n";
ss << "void ps2_syscalls::TODO(uint8_t* rdram, R5900Context* ctx) {\n";
ss << " std::cout << \"Unimplemented syscall/function called at PC=0x\" << std::hex << ctx->pc << std::dec << std::endl;\n";
ss << " ctx->r[2] = 0; // Return 0 by default\n";
ss << "}\n\n";
ss << "void ps2_stubs::TODO(uint8_t* rdram, R5900Context* ctx) {\n";
ss << " std::cout << \"Unimplemented library function called at PC=0x\" << std::hex << ctx->pc << std::dec << std::endl;\n";
ss << " ctx->r[2] = 0; // Return 0 by default\n";
ss << "}\n\n";
// Registration function
ss << "void registerAllFunctions(PS2Runtime& runtime) {\n";
std::vector<std::pair<uint32_t, std::string>> normalFunctions;
std::vector<std::pair<uint32_t, std::string>> stubFunctions;
std::vector<std::pair<uint32_t, std::string>> systemCallFunctions;
std::vector<std::pair<uint32_t, std::string>> libraryFunctions;
for (const auto &function : functions)
{
if (!function.isRecompiled)
continue;
bool isSystemCall = systemCalls.find(function.name) != systemCalls.end();
bool isLibCall = libraryStubs.find(function.name) != libraryStubs.end();
if (isSystemCall)
{
const auto &syscallInfo = systemCalls.at(function.name);
systemCallFunctions.push_back({syscallInfo.first, syscallInfo.second});
continue;
}
if (isLibCall)
{
// we need to generate a unique address for each library function because are created at runtime
static uint32_t libBaseAddr = 0x00110000;
static uint32_t libOffset = 0;
uint32_t libAddr = libBaseAddr + (libOffset++ * 4);
libraryFunctions.push_back({libAddr, libraryStubs.at(function.name)});
continue;
}
if (function.isStub)
{
stubFunctions.push_back({function.start, function.name});
}
else
{
normalFunctions.push_back({function.start, function.name});
}
}
ss << " // Register recompiled functions\n";
for (const auto &function : normalFunctions)
{
ss << " runtime.registerFunction(0x" << std::hex << function.first << std::dec
<< ", " << function.second << ");\n";
}
ss << "\n // Register stub functions\n";
for (const auto &function : stubFunctions)
{
ss << " runtime.registerFunction(0x" << std::hex << function.first << std::dec
<< ", " << function.second << ");\n";
}
ss << "\n // Register system call stubs\n";
for (const auto &function : systemCallFunctions)
{
ss << " runtime.registerFunction(0x" << std::hex << function.first << std::dec
<< ", " << function.second << ");\n";
}
ss << "\n // Register library stubs\n";
for (const auto &function : libraryFunctions)
{
ss << " runtime.registerFunction(0x" << std::hex << function.first << std::dec
<< ", " << function.second << ");\n";
}
ss << "}\n";
return ss.str();
}
Symbol *CodeGenerator::findSymbolByAddress(uint32_t address)
{
for (auto &symbol : m_symbols)
+9 -2
View File
@@ -85,7 +85,7 @@ namespace ps2recomp
std::cout << "Stubbing function: " << function.name << std::endl;
function.isStub = true;
function.isRecompiled = true; // we're generating code for it
std::string stubCode = generateStubFunction(function);
m_generatedStubs[function.start] = stubCode;
@@ -150,7 +150,7 @@ namespace ps2recomp
fs::path outputPath = fs::path(m_config.outputPath) / "recompiled.cpp";
writeToFile(outputPath.string(), combinedOutput.str());
std::cout << "Wrote combined output to: " << outputPath << std::endl;
std::cout << "Wrote recompiled to combined output to: " << outputPath << std::endl;
}
else
{
@@ -180,6 +180,13 @@ namespace ps2recomp
std::cout << "Wrote individual function files to: " << m_config.outputPath << std::endl;
}
std::string registerFunctions = m_codeGenerator->generateFunctionRegistration(
m_functions, m_generatedStubs);
fs::path registerPath = fs::path(m_config.outputPath) / "register_functions.cpp";
writeToFile(registerPath.string(), registerFunctions);
std::cout << "Generated function registration file: " << registerPath << std::endl;
}
catch (const std::exception &e)
{