SaveStates: Support relocatable HLE code

This commit is contained in:
Elad 2025-01-30 13:53:15 +02:00
parent 665bb83297
commit 545e971ba2
5 changed files with 46 additions and 12 deletions

View file

@ -94,26 +94,34 @@ void ppu_module_manager::register_module(ppu_static_module* _module)
ppu_module_manager::get().emplace(_module->name, _module); ppu_module_manager::get().emplace(_module->name, _module);
} }
ppu_static_function& ppu_module_manager::access_static_function(const char* _module, u32 fnid) ppu_static_function& ppu_module_manager::access_static_function(const char* _module, u32 fnid, bool for_creation)
{ {
auto& res = ::at32(ppu_module_manager::get(), _module)->functions[fnid]; auto& res = ::at32(ppu_module_manager::get(), _module)->functions[fnid];
if (res.name) if (for_creation && res.name)
{ {
fmt::throw_exception("PPU FNID duplication in module %s (%s, 0x%x)", _module, res.name, fnid); fmt::throw_exception("PPU FNID duplication in module %s (%s, 0x%x)", _module, res.name, fnid);
} }
else if (!for_creation && !res.name)
{
fmt::throw_exception("PPU FNID unregistered in module %s (%s, 0x%x)", _module, res.name, fnid);
}
return res; return res;
} }
ppu_static_variable& ppu_module_manager::access_static_variable(const char* _module, u32 vnid) ppu_static_variable& ppu_module_manager::access_static_variable(const char* _module, u32 vnid, bool for_creation)
{ {
auto& res = ::at32(ppu_module_manager::get(), _module)->variables[vnid]; auto& res = ::at32(ppu_module_manager::get(), _module)->variables[vnid];
if (res.name) if (for_creation && res.name)
{ {
fmt::throw_exception("PPU VNID duplication in module %s (%s, 0x%x)", _module, res.name, vnid); fmt::throw_exception("PPU VNID duplication in module %s (%s, 0x%x)", _module, res.name, vnid);
} }
else if (!for_creation && !res.name)
{
fmt::throw_exception("PPU VNID unregistered in module %s (%s, 0x%x)", _module, res.name, vnid);
}
return res; return res;
} }
@ -133,6 +141,11 @@ void ppu_module_manager::initialize_modules()
} }
} }
u32 ppu_symbol_addr(std::string_view _module, std::string_view nid) noexcept
{
return *ppu_module_manager::find_static_function(_module.data(), ppu_generate_id(nid)).export_addr;
}
// Global linkage information // Global linkage information
struct ppu_linkage_info struct ppu_linkage_info
{ {

View file

@ -106,9 +106,9 @@ class ppu_module_manager final
static void register_module(ppu_static_module*); static void register_module(ppu_static_module*);
static ppu_static_function& access_static_function(const char* _module, u32 fnid); static ppu_static_function& access_static_function(const char* _module, u32 fnid, bool for_creation);
static ppu_static_variable& access_static_variable(const char* _module, u32 vnid); static ppu_static_variable& access_static_variable(const char* _module, u32 vnid, bool for_creation);
// Global variable for each registered function // Global variable for each registered function
template <auto* Func> template <auto* Func>
@ -125,7 +125,7 @@ public:
template <auto* Func> template <auto* Func>
static auto& register_static_function(const char* _module, const char* name, ppu_intrp_func_t func, u32 fnid) static auto& register_static_function(const char* _module, const char* name, ppu_intrp_func_t func, u32 fnid)
{ {
auto& info = access_static_function(_module, fnid); auto& info = access_static_function(_module, fnid, true);
info.name = name; info.name = name;
info.index = ppu_function_manager::register_function<decltype(Func), Func>(func); info.index = ppu_function_manager::register_function<decltype(Func), Func>(func);
@ -142,6 +142,11 @@ public:
return *registered<Func>::info; return *registered<Func>::info;
} }
static auto& find_static_function(const char* _module, u32 fnid)
{
return access_static_function(_module, fnid, false);
}
template <auto* Var> template <auto* Var>
static auto& register_static_variable(const char* _module, const char* name, u32 vnid) static auto& register_static_variable(const char* _module, const char* name, u32 vnid)
{ {
@ -149,7 +154,7 @@ public:
static_assert(std::is_same_v<u32, typename gvar::addr_type>, "Static variable registration: vm::gvar<T> expected"); static_assert(std::is_same_v<u32, typename gvar::addr_type>, "Static variable registration: vm::gvar<T> expected");
auto& info = access_static_variable(_module, vnid); auto& info = access_static_variable(_module, vnid, true);
info.name = name; info.name = name;
info.var = &Var->raw(); info.var = &Var->raw();
@ -313,6 +318,8 @@ inline RT ppu_execute(ppu_thread& ppu, Args... args)
return func(ppu, args...); return func(ppu, args...);
} }
u32 ppu_symbol_addr(std::string_view _module, std::string_view name) noexcept;
#define BIND_FUNC_WITH_BLR(func, _module) BIND_FUNC(func, if (cpu_flag::again - ppu.state) ppu.cia = static_cast<u32>(ppu.lr) & ~3; else ppu.current_module = _module) #define BIND_FUNC_WITH_BLR(func, _module) BIND_FUNC(func, if (cpu_flag::again - ppu.state) ppu.cia = static_cast<u32>(ppu.lr) & ~3; else ppu.current_module = _module)
#define REG_FNID(_module, nid, func) ppu_module_manager::register_static_function<&func>(#_module, ppu_select_name(#func, nid), BIND_FUNC_WITH_BLR(func, #_module), ppu_generate_id(nid)) #define REG_FNID(_module, nid, func) ppu_module_manager::register_static_function<&func>(#_module, ppu_select_name(#func, nid), BIND_FUNC_WITH_BLR(func, #_module), ppu_generate_id(nid))

View file

@ -2482,12 +2482,18 @@ ppu_thread::ppu_thread(utils::serial& ar)
ar(lv2_obj::g_priority_order_tag); ar(lv2_obj::g_priority_order_tag);
} }
u32 hle_cia = umax;
if (version >= 3) if (version >= 3)
{ {
// Function and module for HLE function relocation // Function and module for HLE function relocation
// TODO: Use it ar(last_module_storage);
ar.pop<std::string>(); ar(last_function_storage);
ar.pop<std::string>();
if (!last_module_storage.empty() && !last_function_storage.empty())
{
hle_cia = ppu_symbol_addr(last_module_storage, last_function_storage);
}
} }
serialize_common(ar); serialize_common(ar);
@ -2642,6 +2648,12 @@ ppu_thread::ppu_thread(utils::serial& ar)
ppu_tname = make_single<std::string>(ar.pop<std::string>()); ppu_tname = make_single<std::string>(ar.pop<std::string>());
if (hle_cia != cia)
{
ppu_log.success("PPU HLE function has been relocated: OG-CIA: 0x%x, NEW-CIA=0x%x (function: %s)", cia, hle_cia, last_function_storage);
cia = hle_cia;
}
ppu_log.notice("Loading PPU Thread [0x%x: %s]: cia=0x%x, state=%s, status=%s", id, *ppu_tname.load(), cia, +state, ppu_thread_status{status}); ppu_log.notice("Loading PPU Thread [0x%x: %s]: cia=0x%x, state=%s, status=%s", id, *ppu_tname.load(), cia, +state, ppu_thread_status{status});
} }

View file

@ -299,6 +299,8 @@ public:
const char* current_function{}; // Current function name for diagnosis, optimized for speed. const char* current_function{}; // Current function name for diagnosis, optimized for speed.
const char* last_function{}; // Sticky copy of current_function, is not cleared on function return const char* last_function{}; // Sticky copy of current_function, is not cleared on function return
const char* current_module{}; // Current module name, for savestates. const char* current_module{}; // Current module name, for savestates.
std::string last_module_storage{}; // Possible storage for current_module
std::string last_function_storage{}; // Possible storage for last_function
const bool is_interrupt_thread; // True for interrupts-handler threads const bool is_interrupt_thread; // True for interrupts-handler threads

View file

@ -42,7 +42,7 @@ static std::array<serial_ver_t, 27> s_serial_versions;
return ::s_serial_versions[identifier].current_version;\ return ::s_serial_versions[identifier].current_version;\
} }
SERIALIZATION_VER(global_version, 0, 19) // For stuff not listed here SERIALIZATION_VER(global_version, 0, 20) // For stuff not listed here
SERIALIZATION_VER(ppu, 1, 1, 2/*PPU sleep order*/, 3/*PPU FNID and module*/) SERIALIZATION_VER(ppu, 1, 1, 2/*PPU sleep order*/, 3/*PPU FNID and module*/)
SERIALIZATION_VER(spu, 2, 1) SERIALIZATION_VER(spu, 2, 1)
SERIALIZATION_VER(lv2_sync, 3, 1) SERIALIZATION_VER(lv2_sync, 3, 1)