diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp index 6a7ce4312b..5e79dc6e42 100644 --- a/rpcs3/Emu/Cell/PPUModule.cpp +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -94,26 +94,34 @@ void ppu_module_manager::register_module(ppu_static_module* _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]; - if (res.name) + if (for_creation && res.name) { 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; } -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]; - if (res.name) + if (for_creation && res.name) { 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; } @@ -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 struct ppu_linkage_info { diff --git a/rpcs3/Emu/Cell/PPUModule.h b/rpcs3/Emu/Cell/PPUModule.h index fdcd736f38..99e2daedfb 100644 --- a/rpcs3/Emu/Cell/PPUModule.h +++ b/rpcs3/Emu/Cell/PPUModule.h @@ -106,9 +106,9 @@ class ppu_module_manager final 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 template @@ -125,7 +125,7 @@ public: template 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.index = ppu_function_manager::register_function(func); @@ -142,6 +142,11 @@ public: return *registered::info; } + static auto& find_static_function(const char* _module, u32 fnid) + { + return access_static_function(_module, fnid, false); + } + template static auto& register_static_variable(const char* _module, const char* name, u32 vnid) { @@ -149,7 +154,7 @@ public: static_assert(std::is_same_v, "Static variable registration: vm::gvar expected"); - auto& info = access_static_variable(_module, vnid); + auto& info = access_static_variable(_module, vnid, true); info.name = name; info.var = &Var->raw(); @@ -313,6 +318,8 @@ inline RT ppu_execute(ppu_thread& ppu, Args... 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(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)) diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index d1d4ca3fc7..f3057486df 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -2482,12 +2482,18 @@ ppu_thread::ppu_thread(utils::serial& ar) ar(lv2_obj::g_priority_order_tag); } + u32 hle_cia = umax; + if (version >= 3) { // Function and module for HLE function relocation - // TODO: Use it - ar.pop(); - ar.pop(); + ar(last_module_storage); + ar(last_function_storage); + + if (!last_module_storage.empty() && !last_function_storage.empty()) + { + hle_cia = ppu_symbol_addr(last_module_storage, last_function_storage); + } } serialize_common(ar); @@ -2642,6 +2648,12 @@ ppu_thread::ppu_thread(utils::serial& ar) ppu_tname = make_single(ar.pop()); + 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}); } diff --git a/rpcs3/Emu/Cell/PPUThread.h b/rpcs3/Emu/Cell/PPUThread.h index 9f94ad50f6..11a24fe03f 100644 --- a/rpcs3/Emu/Cell/PPUThread.h +++ b/rpcs3/Emu/Cell/PPUThread.h @@ -299,6 +299,8 @@ public: 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* 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 diff --git a/rpcs3/Emu/savestate_utils.cpp b/rpcs3/Emu/savestate_utils.cpp index c1b5c953fb..da3c17e333 100644 --- a/rpcs3/Emu/savestate_utils.cpp +++ b/rpcs3/Emu/savestate_utils.cpp @@ -42,7 +42,7 @@ static std::array s_serial_versions; 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(spu, 2, 1) SERIALIZATION_VER(lv2_sync, 3, 1)