#pragma once #include "Emu/SysCalls/SC_FUNC.h" #include "Emu/SysCalls/CB_FUNC.h" #include "ErrorCodes.h" namespace vm { using namespace ps3; } template class Module; struct ModuleFunc { u32 id; u32 flags; Module<>* module; const char* name; ppu_func_caller func; vm::ptr lle_func; ModuleFunc() { } ModuleFunc(u32 id, u32 flags, Module<>* module, const char* name, ppu_func_caller func, vm::ptr lle_func = vm::null) : id(id) , flags(flags) , module(module) , name(name) , func(func) , lle_func(lle_func) { } }; struct ModuleVariable { u32 id; Module<>* module; const char* name; u32(*retrieve_addr)(); }; enum : u32 { SPET_MASKED_OPCODE, SPET_OPTIONAL_MASKED_OPCODE, SPET_LABEL, SPET_BRANCH_TO_LABEL, SPET_BRANCH_TO_FUNC, }; struct SearchPatternEntry { u32 type; be_t data; be_t mask; u32 num; // supplement info }; struct StaticFunc { u32 index; const char* name; std::vector ops; u32 found; std::unordered_map labels; }; template<> class Module : public _log::channel { friend class ModuleManager; bool m_is_loaded; void(*m_init)(); protected: std::function on_alloc; public: Module(const std::string& name, void(*init)()); Module(const Module&) = delete; // Delete copy/move constructors and copy/move operators ~Module(); std::function on_load; std::function on_unload; std::function on_stop; std::function on_error; void Init(); void Load(); void Unload(); void SetLoaded(bool loaded = true); bool IsLoaded() const; }; // Module<> with an instance of specified type in PS3 memory template class Module : public Module { u32 m_addr; public: Module(const char* name, void(*init)()) : Module(name, init) { on_alloc = [this] { static_assert(std::is_trivially_destructible::value, "Module<> instance must be trivially destructible"); //static_assert(std::is_trivially_copy_assignable::value, "Module<> instance must be trivially copy-assignable"); // Allocate module instance and call the default constructor #include "restore_new.h" new(vm::base(m_addr = vm::alloc(sizeof(T), vm::main))) T(); #include "define_new_memleakdetect.h" }; } T* operator ->() const { return vm::_ptr(m_addr); } }; u32 add_ppu_func(ModuleFunc func); void add_variable(u32 nid, Module<>* module, const char* name, u32(*addr)()); ModuleFunc* get_ppu_func_by_nid(u32 nid, u32* out_index = nullptr); ModuleFunc* get_ppu_func_by_index(u32 index); ModuleVariable* get_variable_by_nid(u32 nid); void execute_ppu_func_by_index(PPUThread& ppu, u32 id); extern std::string get_ps3_function_name(u64 fid); void clear_ppu_functions(); u32 get_function_id(const char* name); u32 add_ppu_func_sub(StaticFunc sf); u32 add_ppu_func_sub(const std::initializer_list& ops, const char* name, Module<>* module, ppu_func_caller func); void hook_ppu_funcs(vm::ptr base, u32 size); bool patch_ppu_import(u32 addr, u32 index); // Variable associated with registered HLE function template struct ppu_func_by_func { static u32 index; }; template u32 ppu_func_by_func::index = 0xffffffffu; template> inline RT call_ppu_func(PPUThread& ppu, Args&&... args) { const auto mfunc = get_ppu_func_by_index(ppu_func_by_func::index); if (mfunc && mfunc->lle_func && (mfunc->flags & MFF_FORCED_HLE) == 0 && (mfunc->flags & MFF_NO_RETURN) == 0) { const u32 pc = vm::read32(mfunc->lle_func.addr()); const u32 rtoc = vm::read32(mfunc->lle_func.addr() + 4); return cb_call(ppu, pc, rtoc, std::forward(args)...); } else { return Func(std::forward(args)...); } } // Call specified function directly if LLE is not available, call LLE equivalent in callback style otherwise #define CALL_FUNC(ppu, func, ...) call_ppu_func(ppu, __VA_ARGS__) #define REG_FNID(module, nid, func, ...) (ppu_func_by_func::index = add_ppu_func(ModuleFunc(nid, { __VA_ARGS__ }, &module, #func, BIND_FUNC(func)))) #define REG_FUNC(module, func, ...) REG_FNID(module, get_function_id(#func), func, __VA_ARGS__) #define REG_VNID(module, nid, var) add_variable(nid, &module, #var, []{ return vm::get_addr(&module->var); }) #define REG_VARIABLE(module, var) REG_VNID(module, get_function_id(#var), var) #define REG_SUB(module, ns, name, ...) add_ppu_func_sub({ __VA_ARGS__ }, #name, &module, BIND_FUNC(ns::name)) #define SP_OP(type, op, sup) []() { s32 XXX = 0; SearchPatternEntry res = { (type), (op), 0, (sup) }; XXX = -1; res.mask = (op) ^ ~res.data; return res; }() #define SP_I(op) SP_OP(SPET_MASKED_OPCODE, op, 0) #define OPT_SP_I(op) SP_OP(SPET_OPTIONAL_MASKED_OPCODE, op, 0) #define SET_LABEL(label) { SPET_LABEL, (label) } #define SP_LABEL_BR(op, label) SP_OP(SPET_BRANCH_TO_LABEL, op, label) #define SP_CALL(op, name) SP_OP(SPET_BRANCH_TO_FUNC, op, get_function_id(#name)) #define UNIMPLEMENTED_FUNC(module) module.todo("%s", __FUNCTION__)