diff --git a/rpcs3/Emu/CPU/CPUDecoder.h b/rpcs3/Emu/CPU/CPUDecoder.h deleted file mode 100644 index 4a6d0021b0..0000000000 --- a/rpcs3/Emu/CPU/CPUDecoder.h +++ /dev/null @@ -1,951 +0,0 @@ -#pragma once -#include "CPUInstrTable.h" - -class CPUDecoder -{ -public: - virtual u32 DecodeMemory(const u32 address) = 0; - - virtual ~CPUDecoder() = default; -}; - -template -class InstrCaller -{ -public: - virtual ~InstrCaller() = default; - - virtual void operator ()(TO* op, u32 code) const = 0; - - virtual u32 operator [](u32) const - { - return 0; - } -}; - -template -class InstrBinder_0 : public InstrCaller -{ - typedef void (TO::*func_t)(); - func_t m_func; - -public: - InstrBinder_0(func_t func) - : InstrCaller() - , m_func(func) - { - } - - virtual void operator ()(TO* op, u32 code) const - { - (op->*m_func)(); - } -}; - -template -class InstrBinder_1 : public InstrCaller -{ - typedef void (TO::*func_t)(T1); - func_t m_func; - const CodeFieldBase& m_arg_func_1; - -public: - InstrBinder_1(func_t func, const CodeFieldBase& arg_func_1) - : InstrCaller() - , m_func(func) - , m_arg_func_1(arg_func_1) - { - } - - virtual void operator ()(TO* op, u32 code) const - { - (op->*m_func)(static_cast(m_arg_func_1(code))); - } -}; - -template -class InstrBinder_2 : public InstrCaller -{ - typedef void (TO::*func_t)(T1, T2); - func_t m_func; - const CodeFieldBase& m_arg_func_1; - const CodeFieldBase& m_arg_func_2; - -public: - InstrBinder_2(func_t func, const CodeFieldBase& arg_func_1, const CodeFieldBase& arg_func_2) - : InstrCaller() - , m_func(func) - , m_arg_func_1(arg_func_1) - , m_arg_func_2(arg_func_2) - { - } - - virtual void operator ()(TO* op, u32 code) const - { - (op->*m_func)( - static_cast(m_arg_func_1(code)), - static_cast(m_arg_func_2(code)) - ); - } -}; - -template -class InstrBinder_3 : public InstrCaller -{ - typedef void (TO::*func_t)(T1, T2, T3); - func_t m_func; - const CodeFieldBase& m_arg_func_1; - const CodeFieldBase& m_arg_func_2; - const CodeFieldBase& m_arg_func_3; - -public: - InstrBinder_3(func_t func, - const CodeFieldBase& arg_func_1, - const CodeFieldBase& arg_func_2, - const CodeFieldBase& arg_func_3) - : InstrCaller() - , m_func(func) - , m_arg_func_1(arg_func_1) - , m_arg_func_2(arg_func_2) - , m_arg_func_3(arg_func_3) - { - } - - virtual void operator ()(TO* op, u32 code) const - { - (op->*m_func)( - static_cast(m_arg_func_1(code)), - static_cast(m_arg_func_2(code)), - static_cast(m_arg_func_3(code)) - ); - } -}; - -template -class InstrBinder_4 : public InstrCaller -{ - typedef void (TO::*func_t)(T1, T2, T3, T4); - func_t m_func; - const CodeFieldBase& m_arg_func_1; - const CodeFieldBase& m_arg_func_2; - const CodeFieldBase& m_arg_func_3; - const CodeFieldBase& m_arg_func_4; - -public: - InstrBinder_4(func_t func, - const CodeFieldBase& arg_func_1, - const CodeFieldBase& arg_func_2, - const CodeFieldBase& arg_func_3, - const CodeFieldBase& arg_func_4) - : InstrCaller() - , m_func(func) - , m_arg_func_1(arg_func_1) - , m_arg_func_2(arg_func_2) - , m_arg_func_3(arg_func_3) - , m_arg_func_4(arg_func_4) - { - } - - virtual void operator ()(TO* op, u32 code) const - { - (op->*m_func)( - static_cast(m_arg_func_1(code)), - static_cast(m_arg_func_2(code)), - static_cast(m_arg_func_3(code)), - static_cast(m_arg_func_4(code)) - ); - } -}; - -template -class InstrBinder_5 : public InstrCaller -{ - typedef void (TO::*func_t)(T1, T2, T3, T4, T5); - func_t m_func; - const CodeFieldBase& m_arg_func_1; - const CodeFieldBase& m_arg_func_2; - const CodeFieldBase& m_arg_func_3; - const CodeFieldBase& m_arg_func_4; - const CodeFieldBase& m_arg_func_5; - -public: - InstrBinder_5(func_t func, - const CodeFieldBase& arg_func_1, - const CodeFieldBase& arg_func_2, - const CodeFieldBase& arg_func_3, - const CodeFieldBase& arg_func_4, - const CodeFieldBase& arg_func_5) - : InstrCaller() - , m_func(func) - , m_arg_func_1(arg_func_1) - , m_arg_func_2(arg_func_2) - , m_arg_func_3(arg_func_3) - , m_arg_func_4(arg_func_4) - , m_arg_func_5(arg_func_5) - { - } - - virtual void operator ()(TO* op, u32 code) const - { - (op->*m_func)( - static_cast(m_arg_func_1(code)), - static_cast(m_arg_func_2(code)), - static_cast(m_arg_func_3(code)), - static_cast(m_arg_func_4(code)), - static_cast(m_arg_func_5(code)) - ); - } -}; - -template -class InstrBinder_6 : public InstrCaller -{ - typedef void (TO::*func_t)(T1, T2, T3, T4, T5, T6); - func_t m_func; - const CodeFieldBase& m_arg_func_1; - const CodeFieldBase& m_arg_func_2; - const CodeFieldBase& m_arg_func_3; - const CodeFieldBase& m_arg_func_4; - const CodeFieldBase& m_arg_func_5; - const CodeFieldBase& m_arg_func_6; - -public: - InstrBinder_6(func_t func, - const CodeFieldBase& arg_func_1, - const CodeFieldBase& arg_func_2, - const CodeFieldBase& arg_func_3, - const CodeFieldBase& arg_func_4, - const CodeFieldBase& arg_func_5, - const CodeFieldBase& arg_func_6) - : InstrCaller() - , m_func(func) - , m_arg_func_1(arg_func_1) - , m_arg_func_2(arg_func_2) - , m_arg_func_3(arg_func_3) - , m_arg_func_4(arg_func_4) - , m_arg_func_5(arg_func_5) - , m_arg_func_6(arg_func_6) - { - } - - virtual void operator ()(TO* op, u32 code) const - { - (op->*m_func)( - static_cast(m_arg_func_1(code)), - static_cast(m_arg_func_2(code)), - static_cast(m_arg_func_3(code)), - static_cast(m_arg_func_4(code)), - static_cast(m_arg_func_5(code)), - static_cast(m_arg_func_6(code)) - ); - } -}; - -template -InstrCaller* instr_bind(void (TO::*func)()) -{ - return new InstrBinder_0(func); -} - -template -InstrCaller* instr_bind(void (TO::*func)(T1), const CodeFieldBase& arg_func_1) -{ - return new InstrBinder_1(func, arg_func_1); -} - -template -InstrCaller* instr_bind(void (TO::*func)(T1, T2), - const CodeFieldBase& arg_func_1, - const CodeFieldBase& arg_func_2) -{ - return new InstrBinder_2(func, arg_func_1, arg_func_2); -} - -template -InstrCaller* instr_bind(void (TO::*func)(T1, T2, T3), - const CodeFieldBase& arg_func_1, - const CodeFieldBase& arg_func_2, - const CodeFieldBase& arg_func_3) -{ - return new InstrBinder_3(func, arg_func_1, arg_func_2, arg_func_3); -} - -template -InstrCaller* instr_bind(void (TO::*func)(T1, T2, T3, T4), - const CodeFieldBase& arg_func_1, - const CodeFieldBase& arg_func_2, - const CodeFieldBase& arg_func_3, - const CodeFieldBase& arg_func_4) -{ - return new InstrBinder_4(func, arg_func_1, arg_func_2, arg_func_3, arg_func_4); -} - -template -InstrCaller* instr_bind(void (TO::*func)(T1, T2, T3, T4, T5), - const CodeFieldBase& arg_func_1, - const CodeFieldBase& arg_func_2, - const CodeFieldBase& arg_func_3, - const CodeFieldBase& arg_func_4, - const CodeFieldBase& arg_func_5) -{ - return new InstrBinder_5(func, arg_func_1, arg_func_2, arg_func_3, arg_func_4, arg_func_5); -} - -template -InstrCaller* instr_bind(void (TO::*func)(T1, T2, T3, T4, T5, T6), - const CodeFieldBase& arg_func_1, - const CodeFieldBase& arg_func_2, - const CodeFieldBase& arg_func_3, - const CodeFieldBase& arg_func_4, - const CodeFieldBase& arg_func_5, - const CodeFieldBase& arg_func_6) -{ - return new InstrBinder_6(func, arg_func_1, arg_func_2, arg_func_3, arg_func_4, arg_func_5, arg_func_6); -} - -template -class InstrBase : public InstrCaller -{ -protected: - std::string m_name; - const u32 m_opcode; - CodeFieldBase** m_args; - const uint m_args_count; - -public: - InstrBase(const std::string& name, int opcode, uint args_count) - : InstrCaller() - , m_name(name) - , m_opcode(opcode) - , m_args_count(args_count) - , m_args(args_count ? new CodeFieldBase*[args_count] : nullptr) - { - std::transform( - name.begin(), - name.end(), - m_name.begin(), - [](const char &a) - { - char b = tolower(a); - if (b == '_') b = '.'; - return b; - }); - } - - InstrBase(const InstrBase &source) - : InstrCaller(source) - , m_name(source.m_name) - , m_opcode(source.m_opcode) - , m_args_count(source.m_args_count) - , m_args(source.m_args_count ? new CodeFieldBase*[source.m_args_count] : nullptr) - { - for(uint i = 0; i < source.m_args_count; ++i) - m_args[i] = source.m_args[i]; - } - - virtual ~InstrBase() - { - if (m_args) { - // m_args contains pointers to statically allocated CodeFieldBase objects - // We shouldn't call delete on these, they aren't allocated with new - - // The m_args array itself, however, should be deleted - delete[] m_args; - } - } - - force_inline const std::string& GetName() const - { - return m_name; - } - - force_inline const uint GetArgCount() const - { - return m_args_count; - } - - force_inline const CodeFieldBase& GetArg(uint index) const - { - assert(index < m_args_count); - return *m_args[index]; - } - - void operator ()(TO* op, u32 code) const - { - decode(op, code); - } - - u32 operator()(const std::vector& args) const - { - return encode(args); - } - - virtual void decode(TO* op, u32 code) const=0; - virtual u32 encode(const std::vector& args) const=0; -}; - -template -class InstrList : public InstrCaller -{ -public: - static const int count = _count; - -protected: - const CodeFieldBase& m_func; - InstrCaller* m_instrs[count]; - InstrBase* m_instrs_info[count]; - InstrCaller* m_error_func; - InstrCaller* m_parent; - int m_opcode; - -public: - InstrList(const CodeFieldBase& func, InstrCaller* error_func) - : InstrCaller() - , m_func(func) - , m_error_func(error_func) - , m_parent(nullptr) - , m_opcode(-1) - { - for(int i=0; i*) * count); - } - - virtual ~InstrList() - { - bool deletedErrorFunc = false; - - // Clean up m_instrs - for(int i = 0; i < count; ++i) - { - InstrCaller* deleteMe = m_instrs[i]; - - if (deleteMe) { // deleteMe will be a nullptr if we've already deleted it through another reference - // Remove any instances of pointers to this instruction caller from our m_instrs list - m_instrs[i] = nullptr; - for (int j = i + 1; j < count; j++) { - if (m_instrs[j] == deleteMe) { - m_instrs[j] = nullptr; - } - } - - // If we're deleting the error handler here, remember it so we don't try to delete it again later - if (deleteMe == m_error_func) { - deletedErrorFunc = true; - } - - // Delete the instruction caller - delete deleteMe; - } - } - - // Clean up m_instrs_info - for (int i = 0; i < count; ++i) - { - InstrBase* deleteMe = m_instrs_info[i]; - - if (deleteMe) { - m_instrs_info[i] = nullptr; - for (int j = i + 1; j < count; j++) { - if (m_instrs_info[j] == deleteMe) { - m_instrs[j] = nullptr; - } - } - - delete deleteMe; - } - } - - // If we haven't already deleted our error handler, and we have one, then delete it now - if (!deletedErrorFunc && m_error_func) - { - delete m_error_func; - } - } - - void set_parent(InstrCaller* parent, int opcode) - { - m_opcode = opcode; - m_parent = parent; - } - - InstrCaller* get_parent() const - { - return m_parent; - } - - u32 get_opcode() const - { - return m_opcode; - } - - void set_error_func(InstrCaller* error_func) - { - for(int i=0; i* func, InstrBase* info = nullptr) - { - assert(pos < count); - m_instrs[pos] = func; - m_instrs_info[pos] = info; - } - - InstrCaller* get_instr(int pos) const - { - assert(pos < count); - return m_instrs[pos]; - } - - InstrBase* get_instr_info(int pos) const - { - assert(pos < count); - return m_instrs_info[pos]; - } - - u32 encode(u32 entry) const - { - return m_func[entry] | (m_parent ? (*m_parent)[m_opcode] : 0); - } - - void decode(TO* op, u32 entry, u32 code) const - { - (*m_instrs[entry])(op, code); - } - - virtual void operator ()(TO* op, u32 code) const - { - decode(op, m_func(code) & (count - 1), code); - } - - virtual u32 operator [](u32 entry) const - { - return encode(entry); - } -}; - -template -static InstrList* connect_list(InstrList* parent, InstrList* child, int opcode) -{ - parent->set_instr(opcode, child); - child->set_parent(parent, opcode); - return child; -} - -template -static InstrList* connect_list(InstrList* parent, InstrList* child) -{ - parent->set_error_func(child); - child->set_parent(parent->get_parent(), parent->get_opcode()); - return child; -} - -template -class Instr0 : public InstrBase -{ - InstrList& m_list; - -public: - Instr0(InstrList* list, const std::string& name, - void (TO::*func)()) - : InstrBase(name, opcode, 0) - , m_list(*list) - { - m_list.set_instr(opcode, instr_bind(func), this); - } - - virtual void decode(TO* op, u32 code) const - { - m_list.decode(op, opcode, code); - } - - virtual u32 encode(const std::vector& args) const - { - assert(args.size() == InstrBase::m_args_count); - return m_list.encode(opcode); - } - - u32 encode() const - { - return m_list.encode(opcode); - } - - u32 operator()() const - { - return encode(); - } -}; - -template -class Instr1 : public InstrBase -{ - InstrList& m_list; - -public: - Instr1(InstrList* list, const std::string& name, - void (TO::*func)(T1), - CodeFieldBase& arg_1) - : InstrBase(name, opcode, 1) - , m_list(*list) - { - InstrBase::m_args[0] = &arg_1; - - m_list.set_instr(opcode, instr_bind(func, arg_1), this); - } - - virtual void decode(TO* op, u32 code) const - { - m_list.decode(op, opcode, code); - } - - virtual u32 encode(const std::vector& args) const - { - assert(args.size() == InstrBase::m_args_count); - return m_list.encode(opcode) | (*InstrBase::m_args[0])[args[0]]; - } - - u32 encode(T1 a1) const - { - return m_list.encode(opcode) | (*InstrBase::m_args[0])[a1]; - } - - u32 operator()(T1 a1) const - { - return encode(a1); - } -}; - -template -class Instr2 : public InstrBase -{ - InstrList& m_list; - -public: - Instr2(InstrList* list, const std::string& name, - void (TO::*func)(T1, T2), - CodeFieldBase& arg_1, - CodeFieldBase& arg_2) - : InstrBase(name, opcode, 2) - , m_list(*list) - { - InstrBase::m_args[0] = &arg_1; - InstrBase::m_args[1] = &arg_2; - - m_list.set_instr(opcode, instr_bind(func, arg_1, arg_2), this); - } - - virtual void decode(TO* op, u32 code) const - { - m_list.decode(op, opcode, code); - } - - virtual u32 encode(const std::vector& args) const - { - assert(args.size() == InstrBase::m_args_count); - return m_list.encode(opcode) | (*InstrBase::m_args[0])[args[0]] | (*InstrBase::m_args[1])[args[1]]; - } - - u32 encode(T1 a1, T2 a2) const - { - return m_list.encode(opcode) | (*InstrBase::m_args[0])[a1] | (*InstrBase::m_args[1])[a2]; - } - - u32 operator()(T1 a1, T2 a2) const - { - return encode(a1, a2); - } -}; - -template -class Instr3 : public InstrBase -{ - InstrList& m_list; - -public: - Instr3(InstrList* list, const std::string& name, - void (TO::*func)(T1, T2, T3), - CodeFieldBase& arg_1, - CodeFieldBase& arg_2, - CodeFieldBase& arg_3) - : InstrBase(name, opcode, 3) - , m_list(*list) - { - InstrBase::m_args[0] = &arg_1; - InstrBase::m_args[1] = &arg_2; - InstrBase::m_args[2] = &arg_3; - - m_list.set_instr(opcode, instr_bind(func, arg_1, arg_2, arg_3), this); - } - - virtual void decode(TO* op, u32 code) const - { - m_list.decode(op, opcode, code); - } - - virtual u32 encode(const std::vector& args) const - { - assert(args.size() == InstrBase::m_args_count); - return m_list.encode(opcode) | (*InstrBase::m_args[0])[args[0]] | (*InstrBase::m_args[1])[args[1]] | (*InstrBase::m_args[2])[args[2]]; - } - - u32 encode(T1 a1, T2 a2, T3 a3) const - { - return m_list.encode(opcode) | (*InstrBase::m_args[0])[a1] | (*InstrBase::m_args[1])[a2] | (*InstrBase::m_args[2])[a3]; - } - - u32 operator()(T1 a1, T2 a2, T3 a3) const - { - return encode(a1, a2, a3); - } -}; - -template -class Instr4 : public InstrBase -{ - InstrList& m_list; - -public: - Instr4(InstrList* list, const std::string& name, - void (TO::*func)(T1, T2, T3, T4), - CodeFieldBase& arg_1, - CodeFieldBase& arg_2, - CodeFieldBase& arg_3, - CodeFieldBase& arg_4) - : InstrBase(name, opcode, 4) - , m_list(*list) - { - InstrBase::m_args[0] = &arg_1; - InstrBase::m_args[1] = &arg_2; - InstrBase::m_args[2] = &arg_3; - InstrBase::m_args[3] = &arg_4; - - m_list.set_instr(opcode, instr_bind(func, arg_1, arg_2, arg_3, arg_4), this); - } - - virtual void decode(TO* op, u32 code) const - { - m_list.decode(op, opcode, code); - } - - virtual u32 encode(const std::vector& args) const - { - assert(args.size() == InstrBase::m_args_count); - return m_list.encode(opcode) | - (*InstrBase::m_args[0])[args[0]] | - (*InstrBase::m_args[1])[args[1]] | - (*InstrBase::m_args[2])[args[2]] | - (*InstrBase::m_args[3])[args[3]]; - } - - u32 encode(T1 a1, T2 a2, T3 a3, T4 a4) const - { - return m_list.encode(opcode) | - (*InstrBase::m_args[0])[a1] | - (*InstrBase::m_args[1])[a2] | - (*InstrBase::m_args[2])[a3] | - (*InstrBase::m_args[3])[a4]; - } - - u32 operator()(T1 a1, T2 a2, T3 a3, T4 a4) const - { - return encode(a1, a2, a3, a4); - } -}; - -template -class Instr5 : public InstrBase -{ - InstrList& m_list; - -public: - Instr5(InstrList* list, const std::string& name, - void (TO::*func)(T1, T2, T3, T4, T5), - CodeFieldBase& arg_1, - CodeFieldBase& arg_2, - CodeFieldBase& arg_3, - CodeFieldBase& arg_4, - CodeFieldBase& arg_5) - : InstrBase(name, opcode, 5) - , m_list(*list) - { - InstrBase::m_args[0] = &arg_1; - InstrBase::m_args[1] = &arg_2; - InstrBase::m_args[2] = &arg_3; - InstrBase::m_args[3] = &arg_4; - InstrBase::m_args[4] = &arg_5; - - m_list.set_instr(opcode, instr_bind(func, arg_1, arg_2, arg_3, arg_4, arg_5), this); - } - - virtual void decode(TO* op, u32 code) const - { - m_list.decode(op, opcode, code); - } - - virtual u32 encode(const std::vector& args) const - { - assert(args.size() == InstrBase::m_args_count); - return m_list.encode(opcode) | - (*InstrBase::m_args[0])[args[0]] | - (*InstrBase::m_args[1])[args[1]] | - (*InstrBase::m_args[2])[args[2]] | - (*InstrBase::m_args[3])[args[3]] | - (*InstrBase::m_args[4])[args[4]]; - } - - u32 encode(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) const - { - return m_list.encode(opcode) | - (*InstrBase::m_args[0])[a1] | - (*InstrBase::m_args[1])[a2] | - (*InstrBase::m_args[2])[a3] | - (*InstrBase::m_args[3])[a4] | - (*InstrBase::m_args[4])[a5]; - } - - u32 operator()(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) const - { - return encode(a1, a2, a3, a4, a5); - } -}; - -template -class Instr6 : public InstrBase -{ - InstrList& m_list; - -public: - Instr6(InstrList* list, const std::string& name, - void (TO::*func)(T1, T2, T3, T4, T5, T6), - CodeFieldBase& arg_1, - CodeFieldBase& arg_2, - CodeFieldBase& arg_3, - CodeFieldBase& arg_4, - CodeFieldBase& arg_5, - CodeFieldBase& arg_6) - : InstrBase(name, opcode, 6) - , m_list(*list) - { - InstrBase::m_args[0] = &arg_1; - InstrBase::m_args[1] = &arg_2; - InstrBase::m_args[2] = &arg_3; - InstrBase::m_args[3] = &arg_4; - InstrBase::m_args[4] = &arg_5; - InstrBase::m_args[5] = &arg_6; - - m_list.set_instr(opcode, instr_bind(func, arg_1, arg_2, arg_3, arg_4, arg_5, arg_6), this); - } - - virtual void decode(TO* op, u32 code) const - { - m_list.decode(op, opcode, code); - } - - virtual u32 encode(const std::vector& args) const - { - assert(args.size() == InstrBase::m_args_count); - return m_list.encode(opcode) | - (*InstrBase::m_args[0])[args[0]] | - (*InstrBase::m_args[1])[args[1]] | - (*InstrBase::m_args[2])[args[2]] | - (*InstrBase::m_args[3])[args[3]] | - (*InstrBase::m_args[4])[args[4]] | - (*InstrBase::m_args[5])[args[5]]; - } - - u32 encode(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T5 a6) const - { - return m_list.encode(opcode) | - (*InstrBase::m_args[0])[a1] | - (*InstrBase::m_args[1])[a2] | - (*InstrBase::m_args[2])[a3] | - (*InstrBase::m_args[3])[a4] | - (*InstrBase::m_args[4])[a5] | - (*InstrBase::m_args[5])[a6]; - } - - u32 operator()(T1 a1, T2 a2, T3 a3, T4 a4, T4 a5, T4 a6) const - { - return encode(a1, a2, a3, a4, a5, a6); - } -}; - -template -static Instr0& make_instr(InstrList* list, const std::string& name, void (TO::*func)()) -{ - return *new Instr0(list, name, func); -} - -template -static Instr1& make_instr(InstrList* list, const std::string& name, - void (TO::*func)(T1), - CodeFieldBase& arg_1) -{ - return *new Instr1(list, name, func, arg_1); -} - -template -static Instr2& make_instr(InstrList* list, const std::string& name, - void (TO::*func)(T1, T2), - CodeFieldBase& arg_1, - CodeFieldBase& arg_2) -{ - return *new Instr2(list, name, func, arg_1, arg_2); -} - -template -static Instr3& make_instr(InstrList* list, const std::string& name, - void (TO::*func)(T1, T2, T3), - CodeFieldBase& arg_1, - CodeFieldBase& arg_2, - CodeFieldBase& arg_3) -{ - return *new Instr3(list, name, func, arg_1, arg_2, arg_3); -} - -template -static Instr4& make_instr(InstrList* list, const std::string& name, - void (TO::*func)(T1, T2, T3, T4), - CodeFieldBase& arg_1, - CodeFieldBase& arg_2, - CodeFieldBase& arg_3, - CodeFieldBase& arg_4) -{ - return *new Instr4(list, name, func, arg_1, arg_2, arg_3, arg_4); -} - -template -static Instr5& make_instr(InstrList* list, const std::string& name, - void (TO::*func)(T1, T2, T3, T4, T5), - CodeFieldBase& arg_1, - CodeFieldBase& arg_2, - CodeFieldBase& arg_3, - CodeFieldBase& arg_4, - CodeFieldBase& arg_5) -{ - return *new Instr5(list, name, func, arg_1, arg_2, arg_3, arg_4, arg_5); -} - -template -static Instr6& make_instr(InstrList* list, const std::string& name, - void (TO::*func)(T1, T2, T3, T4, T5, T6), - CodeFieldBase& arg_1, - CodeFieldBase& arg_2, - CodeFieldBase& arg_3, - CodeFieldBase& arg_4, - CodeFieldBase& arg_5, - CodeFieldBase& arg_6) -{ - return *new Instr6(list, name, func, arg_1, arg_2, arg_3, arg_4, arg_5, arg_6); -} diff --git a/rpcs3/Emu/CPU/CPUDisAsm.h b/rpcs3/Emu/CPU/CPUDisAsm.h index 7c4d9badb0..8991f55c84 100644 --- a/rpcs3/Emu/CPU/CPUDisAsm.h +++ b/rpcs3/Emu/CPU/CPUDisAsm.h @@ -51,11 +51,14 @@ protected: { } - virtual u32 DisAsmBranchTarget(const s32 imm)=0; + virtual u32 DisAsmBranchTarget(const s32 imm) = 0; std::string FixOp(std::string op) { - op.append(std::max(10 - (int)op.length(), 0),' '); + op.resize(std::max(op.length(), 10), ' '); return op; } + +public: + virtual u32 disasm(u32 pc) = 0; }; diff --git a/rpcs3/Emu/CPU/CPUInstrTable.h b/rpcs3/Emu/CPU/CPUInstrTable.h deleted file mode 100644 index 1402a94cf5..0000000000 --- a/rpcs3/Emu/CPU/CPUInstrTable.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -template force_inline static T sign(const T value) -{ - static_assert(size > 0 && size < sizeof(T) * 8, "Bad sign size"); - - if(value & (T(1) << (size - 1))) - { - return value - (T(1) << size); - } - - return value; -} - -class CodeFieldBase -{ -public: - u32 m_type; - -public: - CodeFieldBase(u32 type) : m_type(type) - { - } - - virtual u32 operator ()(u32 data) const=0; - virtual void operator()(u32& data, u32 value) const=0; - - virtual u32 operator[](u32 value) const - { - u32 result = 0; - (*this)(result, value); - return result; - } -}; diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index 23959d5070..b80cc30c93 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -1,14 +1,16 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "CPUDecoder.h" +#include "Emu/Cell/PPUThread.h" +#include "Emu/Cell/SPUThread.h" +#include "Emu/Cell/RawSPUThread.h" +#include "Emu/ARMv7/ARMv7Thread.h" #include "CPUThread.h" -thread_local CPUThread* g_tls_current_cpu_thread = nullptr; +thread_local cpu_thread* g_tls_current_cpu_thread = nullptr; -void CPUThread::on_task() +void cpu_thread::on_task() { g_tls_current_cpu_thread = this; @@ -16,13 +18,13 @@ void CPUThread::on_task() std::unique_lock lock(mutex); - // check thread status - while (is_alive()) + // Check thread status + while (!(state & cpu_state::exit)) { CHECK_EMU_STATUS; // check stop status - if (!is_stopped()) + if (!(state & cpu_state::stop)) { if (lock) lock.unlock(); @@ -30,26 +32,17 @@ void CPUThread::on_task() { cpu_task(); } - catch (CPUThreadReturn) + catch (cpu_state _s) { - ; + state += _s; } - catch (CPUThreadStop) + catch (const std::exception&) { - m_state |= CPU_STATE_STOPPED; - } - catch (CPUThreadExit) - { - m_state |= CPU_STATE_DEAD; - break; - } - catch (...) - { - dump_info(); + LOG_NOTICE(GENERAL, "\n%s", dump()); throw; } - m_state &= ~CPU_STATE_RETURN; + state -= cpu_state::ret; continue; } @@ -63,201 +56,7 @@ void CPUThread::on_task() } } -CPUThread::CPUThread(CPUThreadType type, const std::string& name) - : m_id(idm::get_last_id()) - , m_type(type) - , m_name(name) -{ -} - -CPUThread::~CPUThread() -{ - Emu.SendDbgCommand(DID_REMOVE_THREAD, this); -} - -std::string CPUThread::get_name() const -{ - return m_name; -} - -bool CPUThread::is_paused() const -{ - return (m_state & CPU_STATE_PAUSED) != 0 || Emu.IsPaused(); -} - -void CPUThread::dump_info() const -{ - if (!Emu.IsStopped()) - { - LOG_NOTICE(GENERAL, "%s", RegsToString()); - } -} - -void CPUThread::run() -{ - Emu.SendDbgCommand(DID_START_THREAD, this); - - init_stack(); - init_regs(); - do_run(); - - Emu.SendDbgCommand(DID_STARTED_THREAD, this); -} - -void CPUThread::pause() -{ - Emu.SendDbgCommand(DID_PAUSE_THREAD, this); - - m_state |= CPU_STATE_PAUSED; - - Emu.SendDbgCommand(DID_PAUSED_THREAD, this); -} - -void CPUThread::resume() -{ - Emu.SendDbgCommand(DID_RESUME_THREAD, this); - - { - // lock for reliable notification - std::lock_guard lock(mutex); - - m_state &= ~CPU_STATE_PAUSED; - - cv.notify_one(); - } - - Emu.SendDbgCommand(DID_RESUMED_THREAD, this); -} - -void CPUThread::stop() -{ - Emu.SendDbgCommand(DID_STOP_THREAD, this); - - if (is_current()) - { - throw CPUThreadStop{}; - } - else - { - // lock for reliable notification - std::lock_guard lock(mutex); - - m_state |= CPU_STATE_STOPPED; - - cv.notify_one(); - } - - Emu.SendDbgCommand(DID_STOPED_THREAD, this); -} - -void CPUThread::exec() -{ - Emu.SendDbgCommand(DID_EXEC_THREAD, this); - - m_state &= ~CPU_STATE_STOPPED; - - { - // lock for reliable notification - std::lock_guard lock(mutex); - - cv.notify_one(); - } -} - -void CPUThread::exit() -{ - m_state |= CPU_STATE_DEAD; - - if (!is_current()) - { - // lock for reliable notification - std::lock_guard lock(mutex); - - cv.notify_one(); - } -} - -void CPUThread::step() -{ - if (m_state.atomic_op([](u64& state) -> bool - { - const bool was_paused = (state & CPU_STATE_PAUSED) != 0; - - state |= CPU_STATE_STEP; - state &= ~CPU_STATE_PAUSED; - - return was_paused; - })) - { - if (is_current()) return; - - // lock for reliable notification (only if PAUSE was removed) - std::lock_guard lock(mutex); - - cv.notify_one(); - } -} - -void CPUThread::sleep() -{ - m_state += CPU_STATE_MAX; - m_state |= CPU_STATE_SLEEP; -} - -void CPUThread::awake() -{ - // must be called after the balanced sleep() call - - if (m_state.atomic_op([](u64& state) -> bool - { - if (state < CPU_STATE_MAX) - { - throw EXCEPTION("sleep()/awake() inconsistency"); - } - - if ((state -= CPU_STATE_MAX) < CPU_STATE_MAX) - { - state &= ~CPU_STATE_SLEEP; - - // notify the condition variable as well - return true; - } - - return false; - })) - { - if (is_current()) return; - - // lock for reliable notification; the condition being checked is probably externally set - std::lock_guard lock(mutex); - - cv.notify_one(); - } -} - -bool CPUThread::signal() -{ - // try to set SIGNAL - if (m_state._or(CPU_STATE_SIGNAL) & CPU_STATE_SIGNAL) - { - return false; - } - else - { - // not truly responsible for signal delivery, requires additional measures like LV2_LOCK - cv.notify_one(); - - return true; - } -} - -bool CPUThread::unsignal() -{ - // remove SIGNAL and return its old value - return (m_state._and_not(CPU_STATE_SIGNAL) & CPU_STATE_SIGNAL) != 0; -} - -bool CPUThread::check_status() +bool cpu_thread::check_status() { std::unique_lock lock(mutex, std::defer_lock); @@ -265,12 +64,12 @@ bool CPUThread::check_status() { CHECK_EMU_STATUS; // check at least once - if (!is_alive()) + if (state & cpu_state::exit) { return true; } - if (!is_paused() && (m_state & CPU_STATE_INTR) == 0) + if (!state.test(cpu_state_pause) && !state.test(cpu_state::interrupt)) { break; } @@ -281,7 +80,7 @@ bool CPUThread::check_status() continue; } - if (!is_paused() && (m_state & CPU_STATE_INTR) != 0 && handle_interrupt()) + if (!state.test(cpu_state_pause) && state & cpu_state::interrupt && handle_interrupt()) { continue; } @@ -289,17 +88,45 @@ bool CPUThread::check_status() cv.wait(lock); } - if (m_state & CPU_STATE_RETURN || is_stopped()) + const auto state_ = state.load(); + + if (state_ & to_mset(cpu_state::ret, cpu_state::stop)) { return true; } - if (m_state & CPU_STATE_STEP) + if (state_ & cpu_state::dbg_step) { - // set PAUSE, but allow to execute once - m_state |= CPU_STATE_PAUSED; - m_state &= ~CPU_STATE_STEP; + state += cpu_state::dbg_pause; + state -= cpu_state::dbg_step; } return false; } + +std::vector> get_all_cpu_threads() +{ + std::vector> result; + + for (auto& t : idm::get_all()) + { + result.emplace_back(t); + } + + for (auto& t : idm::get_all()) + { + result.emplace_back(t); + } + + for (auto& t : idm::get_all()) + { + result.emplace_back(t); + } + + for (auto& t : idm::get_all()) + { + result.emplace_back(t); + } + + return result; +} diff --git a/rpcs3/Emu/CPU/CPUThread.h b/rpcs3/Emu/CPU/CPUThread.h index 1cfdd0e793..8baa65b03e 100644 --- a/rpcs3/Emu/CPU/CPUThread.h +++ b/rpcs3/Emu/CPU/CPUThread.h @@ -2,174 +2,97 @@ #include "Utilities/Thread.h" -enum CPUThreadType +// CPU Thread Type +enum class cpu_type : u32 { - CPU_THREAD_PPU, - CPU_THREAD_SPU, - CPU_THREAD_RAW_SPU, - CPU_THREAD_ARMv7, + ppu, // PPU Thread + spu, // SPU Thread + arm, // ARMv7 Thread }; -// CPU Thread State Flags -enum : u64 +// CPU Thread State flags +enum struct cpu_state : u32 { - CPU_STATE_STOPPED = (1ull << 0), // basic execution state (stopped by default), removed by Exec() - CPU_STATE_PAUSED = (1ull << 1), // pauses thread execution, set by the debugger (manually or after step execution) - CPU_STATE_SLEEP = (1ull << 2), // shouldn't affect thread execution, set by sleep(), removed by the latest awake(), may possibly indicate waiting state of the thread - CPU_STATE_STEP = (1ull << 3), // forces the thread to pause after executing just one instruction or something appropriate, set by the debugger - CPU_STATE_DEAD = (1ull << 4), // indicates irreversible exit of the thread - CPU_STATE_RETURN = (1ull << 5), // used for callback return - CPU_STATE_SIGNAL = (1ull << 6), // used for HLE signaling - CPU_STATE_INTR = (1ull << 7), // thread interrupted + stop, // Thread not running (HLE, initial state) + exit, // Irreversible exit + suspend, // Thread paused + ret, // Callback return requested + signal, // Thread received a signal (HLE) + interrupt, // Thread interrupted - CPU_STATE_MAX = (1ull << 8), // added to (subtracted from) m_state by sleep()/awake() calls to trigger status check + dbg_global_pause, // Emulation paused + dbg_global_stop, // Emulation stopped + dbg_pause, // Thread paused + dbg_step, // Thread forced to pause after one step (one instruction, etc) }; -class CPUThreadReturn {}; // "HLE return" exception event -class CPUThreadStop {}; // CPUThread::Stop exception event -class CPUThreadExit {}; // CPUThread::Exit exception event +// CPU Thread State flags: pause state union +constexpr mset cpu_state_pause = to_mset(cpu_state::suspend, cpu_state::dbg_global_pause, cpu_state::dbg_pause); -class CPUDecoder; - -class CPUThread : public named_thread_t +class cpu_thread : public named_thread { void on_task() override; - void on_id_aux_finalize() override { exit(); } // call exit() instead of join() - -protected: - atomic_t m_state{ CPU_STATE_STOPPED }; // thread state flags - - std::unique_ptr m_dec; - - const u32 m_id; - const CPUThreadType m_type; - const std::string m_name; // changing m_name is unsafe because it can be read at any moment - - CPUThread(CPUThreadType type, const std::string& name); public: - virtual ~CPUThread() override; + virtual void on_init() override + { + named_thread::on_init(); + } - virtual std::string get_name() const override; - u32 get_id() const { return m_id; } - CPUThreadType get_type() const { return m_type; } + virtual void on_stop() override + { + state += cpu_state::exit; + safe_notify(); + } - bool is_alive() const { return (m_state & CPU_STATE_DEAD) == 0; } - bool is_stopped() const { return (m_state & CPU_STATE_STOPPED) != 0; } - virtual bool is_paused() const; + const std::string name; + const u32 id{}; + const cpu_type type; - virtual void dump_info() const; - virtual u32 get_pc() const = 0; - virtual u32 get_offset() const = 0; - virtual void do_run() = 0; - virtual void cpu_task() = 0; + cpu_thread(cpu_type type, const std::string& name) + : type(type) + , name(name) + { + } - virtual void init_regs() = 0; - virtual void init_stack() = 0; - virtual void close_stack() = 0; + // Public thread state + atomic_t> state{ cpu_state::stop }; - // initialize thread - void run(); + // Recursively enter sleep state + void sleep() + { + if (!++m_sleep) xsleep(); + } - // called by the debugger, don't use - void pause(); + // Leave sleep state + void awake() + { + if (!m_sleep--) xsleep(); + } - // called by the debugger, don't use - void resume(); - - // stop thread execution - void stop(); - - // start thread execution (removing STOP status) - void exec(); - - // exit thread execution - void exit(); - - // called by the debugger, don't use - void step(); - - // trigger thread status check - void sleep(); - - // untrigger thread status check - void awake(); - - // set SIGNAL and notify (returns true if set) - bool signal(); - - // test SIGNAL and reset - bool unsignal(); - - // process m_state flags, returns true if the checker must return + // Process thread state, return true if the checker must return bool check_status(); + virtual std::string dump() const = 0; // Print CPU state + virtual void cpu_init() {} + virtual void cpu_task() = 0; virtual bool handle_interrupt() { return false; } - std::string GetFName() const +private: + [[noreturn]] void xsleep() { - return fmt::format("%s[0x%x] Thread (%s)", GetTypeString(), m_id, m_name); + throw std::runtime_error("cpu_thread: sleep()/awake() inconsistency"); } - static const char* CPUThreadTypeToString(CPUThreadType type) - { - switch (type) - { - case CPU_THREAD_PPU: return "PPU"; - case CPU_THREAD_SPU: return "SPU"; - case CPU_THREAD_RAW_SPU: return "RawSPU"; - case CPU_THREAD_ARMv7: return "ARMv7"; - } - - return "Unknown"; - } - - const char* ThreadStatusToString() const - { - // TODO - - //switch (ThreadStatus()) - //{ - //case CPUThread_Ready: return "Ready"; - //case CPUThread_Running: return "Running"; - //case CPUThread_Paused: return "Paused"; - //case CPUThread_Stopped: return "Stopped"; - //case CPUThread_Sleeping: return "Sleeping"; - //case CPUThread_Break: return "Break"; - //case CPUThread_Step: return "Step"; - //} - - return "Unknown"; - } - - const char* GetTypeString() const - { - return CPUThreadTypeToString(m_type); - } - - CPUDecoder* GetDecoder() - { - return m_dec.get(); - }; - - virtual std::string RegsToString() const = 0; - virtual std::string ReadRegString(const std::string& reg) const = 0; - virtual bool WriteRegString(const std::string& reg, std::string value) = 0; + // Sleep/Awake counter + atomic_t m_sleep{}; }; -inline CPUThread* get_current_cpu_thread() +inline cpu_thread* get_current_cpu_thread() noexcept { - extern thread_local CPUThread* g_tls_current_cpu_thread; + extern thread_local cpu_thread* g_tls_current_cpu_thread; return g_tls_current_cpu_thread; } -class cpu_thread -{ -protected: - std::shared_ptr thread; - -public: - virtual cpu_thread& args(std::initializer_list values) = 0; - virtual cpu_thread& run() = 0; -}; +extern std::vector> get_all_cpu_threads(); diff --git a/rpcs3/Emu/CPU/CPUThreadManager.cpp b/rpcs3/Emu/CPU/CPUThreadManager.cpp deleted file mode 100644 index e02f653c0e..0000000000 --- a/rpcs3/Emu/CPU/CPUThreadManager.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/System.h" -#include "Emu/IdManager.h" - -#include "Emu/Cell/PPUThread.h" -#include "Emu/Cell/SPUThread.h" -#include "Emu/Cell/RawSPUThread.h" -#include "Emu/ARMv7/ARMv7Thread.h" -#include "CPUThreadManager.h" - -CPUThreadManager::CPUThreadManager() -{ -} - -CPUThreadManager::~CPUThreadManager() -{ -} - -void CPUThreadManager::Close() -{ - std::lock_guard lock(m_mutex); - - for (auto& x : m_raw_spu) - { - x.reset(); - } -} - -std::vector> CPUThreadManager::GetAllThreads() -{ - std::vector> result; - - for (auto& t : idm::get_all()) - { - result.emplace_back(t); - } - - for (auto& t : idm::get_all()) - { - result.emplace_back(t); - } - - for (auto& t : idm::get_all()) - { - result.emplace_back(t); - } - - for (auto& t : idm::get_all()) - { - result.emplace_back(t); - } - - return result; -} - -void CPUThreadManager::Exec() -{ - for (auto& t : idm::get_all()) - { - t->exec(); - } - - for (auto& t : idm::get_all()) - { - t->exec(); - } -} - -std::shared_ptr CPUThreadManager::NewRawSPUThread() -{ - std::lock_guard lock(m_mutex); - - std::shared_ptr result; - - for (u32 i = 0; i < m_raw_spu.size(); i++) - { - if (m_raw_spu[i].expired()) - { - m_raw_spu[i] = result = idm::make_ptr(std::to_string(i), i); - break; - } - } - - return result; -} - -std::shared_ptr CPUThreadManager::GetRawSPUThread(u32 index) -{ - if (index >= m_raw_spu.size()) - { - return nullptr; - } - - std::lock_guard lock(m_mutex); - - return m_raw_spu[index].lock(); -} diff --git a/rpcs3/Emu/CPU/CPUThreadManager.h b/rpcs3/Emu/CPU/CPUThreadManager.h deleted file mode 100644 index 5fa772e971..0000000000 --- a/rpcs3/Emu/CPU/CPUThreadManager.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -class CPUThread; -class RawSPUThread; - -class CPUThreadManager final -{ - std::mutex m_mutex; - - std::array, 5> m_raw_spu; - -public: - CPUThreadManager(); - ~CPUThreadManager(); - - void Close(); - - static std::vector> GetAllThreads(); - - static void Exec(); - - std::shared_ptr NewRawSPUThread(); - - std::shared_ptr GetRawSPUThread(u32 index); -}; diff --git a/rpcs3/Emu/Event.cpp b/rpcs3/Emu/Event.cpp deleted file mode 100644 index 8c9ceae8cc..0000000000 --- a/rpcs3/Emu/Event.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/System.h" - -#include "Emu/SysCalls/lv2/sys_event.h" -#include "Event.h" - -void EventManager::Init() -{ -} - -void EventManager::Clear() -{ - m_map.clear(); -} - -bool EventManager::UnregisterKey(u64 key) -{ - if (!key) - { - // always ok - return true; - } - - std::lock_guard lock(m_mutex); - - auto f = m_map.find(key); - if (f != m_map.end()) - { - m_map.erase(f); - return true; - } - - return false; -} - -std::shared_ptr EventManager::GetEventQueue(u64 key) -{ - if (!key) - { - // never exists - return nullptr; - } - - std::lock_guard lock(m_mutex); - - auto f = m_map.find(key); - if (f != m_map.end()) - { - return f->second; - } - - return nullptr; -} diff --git a/rpcs3/Emu/Event.h b/rpcs3/Emu/Event.h deleted file mode 100644 index 754b526bad..0000000000 --- a/rpcs3/Emu/Event.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include "Emu/IdManager.h" - -struct lv2_event_queue_t; - -class EventManager -{ - std::mutex m_mutex; - std::unordered_map> m_map; - -public: - void Init(); - void Clear(); - bool UnregisterKey(u64 key); - - template::value>> std::shared_ptr MakeEventQueue(u64 key, Args&&... args) - { - std::lock_guard lock(m_mutex); - - if (key && m_map.find(key) != m_map.end()) - { - return nullptr; - } - - auto queue = idm::make_ptr(std::forward(args)...); - - if (key) - { - m_map[key] = queue; - } - - return queue; - } - - std::shared_ptr GetEventQueue(u64 key); -}; diff --git a/rpcs3/Emu/HDD/HDD.cpp b/rpcs3/Emu/HDD/HDD.cpp deleted file mode 100644 index 5c4cf61145..0000000000 --- a/rpcs3/Emu/HDD/HDD.cpp +++ /dev/null @@ -1,820 +0,0 @@ -#include "stdafx.h" -#include "HDD.h" - -void vfsHDDManager::CreateBlock(vfsHDD_Block& block) -{ - block.is_used = true; - block.next_block = 0; -} - -void vfsHDDManager::CreateEntry(vfsHDD_Entry& entry) -{ - memset(&entry, 0, sizeof(vfsHDD_Entry)); - u64 ctime = time(nullptr); - entry.atime = ctime; - entry.ctime = ctime; - entry.mtime = ctime; - entry.access = 0666; - CreateBlock(entry); -} - -void vfsHDDManager::CreateHDD(const std::string& path, u64 size, u64 block_size) -{ - fs::file f(path, fom::rewrite); - - static const u64 cur_dir_block = 1; - - vfsHDD_Hdr hdr; - CreateBlock(hdr); - hdr.next_block = cur_dir_block; - hdr.magic = g_hdd_magic; - hdr.version = g_hdd_version; - hdr.block_count = (size + block_size) / block_size; - hdr.block_size = block_size; - f.write(&hdr, sizeof(vfsHDD_Hdr)); - - { - vfsHDD_Entry entry; - CreateEntry(entry); - entry.type = vfsHDD_Entry_Dir; - entry.data_block = hdr.next_block; - entry.next_block = 0; - - f.seek(cur_dir_block * hdr.block_size); - f.write(&entry, sizeof(vfsHDD_Entry)); - f.write(".", 1); - } - - u8 null = 0; - - CHECK_ASSERTION(f.seek(hdr.block_count * hdr.block_size - sizeof(null)) != -1); - - f.write(&null, sizeof(null)); -} - -void vfsHDDManager::Format() -{ -} - -void vfsHDDManager::AppendEntry(vfsHDD_Entry entry) -{ -} - -bool vfsHDDFile::goto_block(u64 n) -{ - vfsHDD_Block block_info; - - if (m_info.data_block >= m_hdd_info.block_count) - { - return false; - } - - CHECK_ASSERTION(m_hdd.Seek(m_info.data_block * m_hdd_info.block_size) != -1); - - block_info.next_block = m_info.data_block; - - for (u64 i = 0; i < n; ++i) - { - if (!block_info.next_block || !block_info.is_used || block_info.next_block >= m_hdd_info.block_count) - { - return false; - } - - CHECK_ASSERTION(m_hdd.Seek(block_info.next_block * m_hdd_info.block_size) != -1); - - m_hdd.Read(&block_info, sizeof(vfsHDD_Block)); - } - - return true; -} - -void vfsHDDFile::RemoveBlocks(u64 start_block) -{ - vfsHDD_Block block_info; - block_info.next_block = start_block; - - while (block_info.next_block && block_info.is_used) - { - u64 offset = block_info.next_block * m_hdd_info.block_size; - - ReadBlock(offset, block_info); - WriteBlock(offset, g_null_block); - } -} - -void vfsHDDFile::WriteBlock(u64 block, const vfsHDD_Block& data) -{ - CHECK_ASSERTION(m_hdd.Seek(block * m_hdd_info.block_size) != -1); - - m_hdd.Write(&data, sizeof(vfsHDD_Block)); -} - -void vfsHDDFile::ReadBlock(u64 block, vfsHDD_Block& data) -{ - CHECK_ASSERTION(m_hdd.Seek(block * m_hdd_info.block_size) != -1); - - m_hdd.Read(&data, sizeof(vfsHDD_Block)); -} - -void vfsHDDFile::WriteEntry(u64 block, const vfsHDD_Entry& data) -{ - CHECK_ASSERTION(m_hdd.Seek(block * m_hdd_info.block_size) != -1); - - m_hdd.Write(&data, sizeof(vfsHDD_Entry)); -} - -void vfsHDDFile::ReadEntry(u64 block, vfsHDD_Entry& data) -{ - CHECK_ASSERTION(m_hdd.Seek(block * m_hdd_info.block_size) != -1); - - m_hdd.Read(&data, sizeof(vfsHDD_Entry)); -} - -void vfsHDDFile::ReadEntry(u64 block, vfsHDD_Entry& data, std::string& name) -{ - CHECK_ASSERTION(m_hdd.Seek(block * m_hdd_info.block_size) != -1); - - m_hdd.Read(&data, sizeof(vfsHDD_Entry)); - name.resize(GetMaxNameLen()); - m_hdd.Read(&name.front(), GetMaxNameLen()); -} - -void vfsHDDFile::ReadEntry(u64 block, std::string& name) -{ - CHECK_ASSERTION(m_hdd.Seek(block * m_hdd_info.block_size + sizeof(vfsHDD_Entry)) != -1); - - name.resize(GetMaxNameLen()); - m_hdd.Read(&name.front(), GetMaxNameLen()); -} - -void vfsHDDFile::WriteEntry(u64 block, const vfsHDD_Entry& data, const std::string& name) -{ - CHECK_ASSERTION(m_hdd.Seek(block * m_hdd_info.block_size) != -1); - - m_hdd.Write(&data, sizeof(vfsHDD_Entry)); - m_hdd.Write(name.c_str(), std::min(GetMaxNameLen() - 1, name.length() + 1)); -} - -void vfsHDDFile::Open(u64 info_block) -{ - m_info_block = info_block; - ReadEntry(m_info_block, m_info); - m_position = 0; - m_cur_block = m_info.data_block; -} - -u64 vfsHDDFile::FindFreeBlock() -{ - vfsHDD_Block block_info; - - for (u64 i = 0; i < m_hdd_info.block_count; ++i) - { - ReadBlock(i, block_info); - - if (!block_info.is_used) - { - return i; - } - } - - return 0; -} - -bool vfsHDDFile::Seek(u64 pos) -{ - if (!goto_block(pos / m_hdd_info.block_size)) - { - return false; - } - - m_position = pos % m_hdd_info.block_size; - return true; -} - -void vfsHDDFile::SaveInfo() -{ - CHECK_ASSERTION(m_hdd.Seek(m_info_block * m_hdd_info.block_size) != -1); - - CHECK_ASSERTION(m_hdd.Seek(m_info_block * m_hdd_info.block_size) != -1); - - m_hdd.Write(&m_info, sizeof(vfsHDD_Entry)); -} - -u64 vfsHDDFile::Read(void* dst, u64 size) -{ - if (!size) - return 0; - - //vfsDeviceLocker lock(m_hdd); - - const u32 block_size = m_hdd_info.block_size - sizeof(vfsHDD_Block); - u64 rsize = std::min(block_size - m_position, size); - - vfsHDD_Block cur_block_info; - - CHECK_ASSERTION(m_hdd.Seek(m_cur_block * m_hdd_info.block_size) != -1); - - m_hdd.Read(&cur_block_info, sizeof(vfsHDD_Block)); - - CHECK_ASSERTION(m_hdd.Seek(m_cur_block * m_hdd_info.block_size + sizeof(vfsHDD_Block) + m_position) != -1); - - m_hdd.Read(dst, rsize); - size -= rsize; - m_position += rsize; - if (!size) - { - return rsize; - } - - u64 offset = rsize; - - for (; size; size -= rsize, offset += rsize) - { - if (!cur_block_info.is_used || !cur_block_info.next_block || cur_block_info.next_block >= m_hdd_info.block_count) - { - return offset; - } - - m_cur_block = cur_block_info.next_block; - rsize = std::min(block_size, size); - - CHECK_ASSERTION(m_hdd.Seek(cur_block_info.next_block * m_hdd_info.block_size) != -1); - - m_hdd.Read(&cur_block_info, sizeof(vfsHDD_Block)); - - if (m_hdd.Read((u8*)dst + offset, rsize) != rsize) - { - return offset; - } - } - - m_position = rsize; - - return offset; -} - -u64 vfsHDDFile::Write(const void* src, u64 size) -{ - if (!size) - return 0; - - //vfsDeviceLocker lock(m_hdd); - - const u32 block_size = m_hdd_info.block_size - sizeof(vfsHDD_Block); - - if (!m_cur_block) - { - if (!m_info.data_block) - { - u64 new_block = FindFreeBlock(); - - if (!new_block) - { - return 0; - } - - WriteBlock(new_block, g_used_block); - m_info.data_block = new_block; - m_info.size = 0; - SaveInfo(); - } - - m_cur_block = m_info.data_block; - m_position = 0; - } - - u64 wsize = std::min(block_size - m_position, size); - - vfsHDD_Block block_info; - ReadBlock(m_cur_block, block_info); - - if (wsize) - { - CHECK_ASSERTION(m_hdd.Seek(m_cur_block * m_hdd_info.block_size + sizeof(vfsHDD_Block) + m_position) != -1); - - m_hdd.Write(src, wsize); - size -= wsize; - m_info.size += wsize; - m_position += wsize; - SaveInfo(); - - if (!size) - return wsize; - } - - u64 last_block = m_cur_block; - block_info.is_used = true; - u64 offset = wsize; - - for (; size; size -= wsize, offset += wsize, m_info.size += wsize) - { - u64 new_block = FindFreeBlock(); - - if (!new_block) - { - m_position = 0; - SaveInfo(); - return offset; - } - - m_cur_block = new_block; - wsize = std::min(block_size, size); - - block_info.next_block = m_cur_block; - - CHECK_ASSERTION(m_hdd.Seek(last_block * m_hdd_info.block_size) != -1); - - if (m_hdd.Write(&block_info, sizeof(vfsHDD_Block)) != sizeof(vfsHDD_Block)) - { - m_position = 0; - SaveInfo(); - return offset; - } - - block_info.next_block = 0; - - CHECK_ASSERTION(m_hdd.Seek(m_cur_block * m_hdd_info.block_size) != -1); - - if (m_hdd.Write(&block_info, sizeof(vfsHDD_Block)) != sizeof(vfsHDD_Block)) - { - m_position = 0; - SaveInfo(); - return offset; - } - - if ((m_position = m_hdd.Write((u8*)src + offset, wsize)) != wsize) - { - m_info.size += wsize; - SaveInfo(); - return offset; - } - - last_block = m_cur_block; - } - - SaveInfo(); - m_position = wsize; - return offset; -} - -vfsDeviceHDD::vfsDeviceHDD(const std::string& hdd_path) : m_hdd_path(hdd_path) -{ -} - -vfsFileBase* vfsDeviceHDD::GetNewFileStream() -{ - return new vfsHDD(this, m_hdd_path); -} - -vfsDirBase* vfsDeviceHDD::GetNewDirStream() -{ - return nullptr; -} - -vfsHDD::vfsHDD(vfsDevice* device, const std::string& hdd_path) - : m_hdd_file(device) - , m_file(m_hdd_file, m_hdd_info) - , m_hdd_path(hdd_path) - , vfsFileBase(device) -{ - m_hdd_file.Open(hdd_path, fom::read | fom::write); - m_hdd_file.Read(&m_hdd_info, sizeof(vfsHDD_Hdr)); - m_cur_dir_block = m_hdd_info.next_block; - if (!m_hdd_info.block_size) - { - LOG_ERROR(HLE, "Bad block size!"); - m_hdd_info.block_size = 2048; - } - - CHECK_ASSERTION(m_hdd_file.Seek(m_cur_dir_block * m_hdd_info.block_size) != -1); - - m_hdd_file.Read(&m_cur_dir, sizeof(vfsHDD_Entry)); -} - -bool vfsHDD::SearchEntry(const std::string& name, u64& entry_block, u64* parent_block) -{ - u64 last_block = 0; - u64 block = m_cur_dir_block; - vfsHDD_Entry entry; - std::string buf; - - while (block) - { - ReadEntry(block, entry, buf); - - if (fmt::CmpNoCase(name, buf) == 0) - { - entry_block = block; - if (parent_block) - *parent_block = last_block; - - return true; - } - - last_block = block; - block = entry.is_used ? entry.next_block : 0ULL; - } - - return false; -} - -s32 vfsHDD::OpenDir(const std::string& name) -{ - LOG_WARNING(HLE, "OpenDir(%s)", name.c_str()); - u64 entry_block; - - if (!SearchEntry(name, entry_block)) - { - return -1; - } - - CHECK_ASSERTION(m_hdd_file.Seek(entry_block * m_hdd_info.block_size) != -1); - - vfsHDD_Entry entry; - m_hdd_file.Read(&entry, sizeof(vfsHDD_Entry)); - - if (entry.type == vfsHDD_Entry_File) - { - return 1; - } - - m_cur_dir_block = entry.data_block; - ReadEntry(m_cur_dir_block, m_cur_dir); - - return 0; -} - -bool vfsHDD::Rename(const std::string& from, const std::string& to) -{ - u64 entry_block; - if (!SearchEntry(from, entry_block)) - { - return false; - } - - vfsHDD_Entry entry; - ReadEntry(entry_block, entry); - WriteEntry(entry_block, entry, to); - - return true; -} - -u64 vfsHDD::FindFreeBlock() -{ - vfsHDD_Block block_info; - - for (u64 i = 0; i < m_hdd_info.block_count; ++i) - { - ReadBlock(i, block_info); - - if (!block_info.is_used) - { - return i; - } - } - - return 0; -} - -void vfsHDD::WriteBlock(u64 block, const vfsHDD_Block& data) -{ - CHECK_ASSERTION(m_hdd_file.Seek(block * m_hdd_info.block_size) != -1); - - m_hdd_file.Write(&data, sizeof(vfsHDD_Block)); -} - -void vfsHDD::ReadBlock(u64 block, vfsHDD_Block& data) -{ - CHECK_ASSERTION(m_hdd_file.Seek(block * m_hdd_info.block_size) != -1); - - m_hdd_file.Read(&data, sizeof(vfsHDD_Block)); -} - -void vfsHDD::WriteEntry(u64 block, const vfsHDD_Entry& data) -{ - CHECK_ASSERTION(m_hdd_file.Seek(block * m_hdd_info.block_size) != -1); - - m_hdd_file.Write(&data, sizeof(vfsHDD_Entry)); -} - -void vfsHDD::ReadEntry(u64 block, vfsHDD_Entry& data) -{ - CHECK_ASSERTION(m_hdd_file.Seek(block * m_hdd_info.block_size) != -1); - - m_hdd_file.Read(&data, sizeof(vfsHDD_Entry)); -} - -void vfsHDD::ReadEntry(u64 block, vfsHDD_Entry& data, std::string& name) -{ - CHECK_ASSERTION(m_hdd_file.Seek(block * m_hdd_info.block_size) != -1); - - m_hdd_file.Read(&data, sizeof(vfsHDD_Entry)); - name.resize(GetMaxNameLen()); - m_hdd_file.Read(&name.front(), GetMaxNameLen()); -} - -void vfsHDD::ReadEntry(u64 block, std::string& name) -{ - CHECK_ASSERTION(m_hdd_file.Seek(block * m_hdd_info.block_size + sizeof(vfsHDD_Entry)) != -1); - - name.resize(GetMaxNameLen()); - m_hdd_file.Read(&name.front(), GetMaxNameLen()); -} - -void vfsHDD::WriteEntry(u64 block, const vfsHDD_Entry& data, const std::string& name) -{ - CHECK_ASSERTION(m_hdd_file.Seek(block * m_hdd_info.block_size) != -1); - - m_hdd_file.Write(&data, sizeof(vfsHDD_Entry)); - m_hdd_file.Write(name.c_str(), std::min(GetMaxNameLen() - 1, name.length() + 1)); -} - -bool vfsHDD::Create(vfsHDD_EntryType type, const std::string& name) -{ - if (HasEntry(name)) - { - return false; - } - - u64 new_block = FindFreeBlock(); - if (!new_block) - { - return false; - } - - LOG_NOTICE(HLE, "CREATING ENTRY AT 0x%llx", new_block); - WriteBlock(new_block, g_used_block); - - { - vfsHDD_Entry new_entry; - vfsHDDManager::CreateEntry(new_entry); - new_entry.next_block = 0; - new_entry.type = type; - - if (type == vfsHDD_Entry_Dir) - { - u64 block_cur = FindFreeBlock(); - - if (!block_cur) - { - return false; - } - - WriteBlock(block_cur, g_used_block); - - u64 block_last = FindFreeBlock(); - - if (!block_last) - { - return false; - } - - WriteBlock(block_last, g_used_block); - - vfsHDD_Entry entry_cur, entry_last; - vfsHDDManager::CreateEntry(entry_cur); - vfsHDDManager::CreateEntry(entry_last); - - entry_cur.type = vfsHDD_Entry_Dir; - entry_cur.data_block = block_cur; - entry_cur.next_block = block_last; - - entry_last.type = vfsHDD_Entry_Dir; - entry_last.data_block = m_cur_dir_block; - entry_last.next_block = 0; - - new_entry.data_block = block_cur; - - WriteEntry(block_cur, entry_cur, "."); - WriteEntry(block_last, entry_last, ".."); - } - - WriteEntry(new_block, new_entry, name); - } - - { - u64 block = m_cur_dir_block; - - vfsHDD_Block tmp; - while (block) - { - ReadBlock(block, tmp); - - if (!tmp.next_block) - break; - - block = tmp.next_block; - } - - tmp.next_block = new_block; - WriteBlock(block, tmp); - } - - return true; -} - -bool vfsHDD::GetFirstEntry(u64& block, vfsHDD_Entry& entry, std::string& name) -{ - if (!m_cur_dir_block) - { - return false; - } - - ReadEntry(m_cur_dir_block, entry, name); - block = entry.is_used ? entry.next_block : 0; - - return true; -} - -bool vfsHDD::GetNextEntry(u64& block, vfsHDD_Entry& entry, std::string& name) -{ - if (!block) - { - return false; - } - - ReadEntry(block, entry, name); - - block = entry.is_used ? entry.next_block : 0; - return true; -} - -bool vfsHDD::Open(const std::string& path, u32 mode) -{ - const char* s = path.c_str(); - u64 from = 0; - u64 pos = 0; - u64 file_pos = -1; - - do - { - if (s[pos] == '\\' || s[pos] == '/' || s[pos] == '\0') // ??? - { - if (file_pos != -1) - { - return false; - } - - if (from != -1) - { - if (pos - from > 1) - { - s32 res = OpenDir(std::string(s + from, pos)); - - if (res == -1) - { - return false; - } - else if (res == 1) - { - file_pos = from; - } - } - - from = pos; - } - else - { - from = pos; - } - } - } while (s[pos++] != '\0'); - - if (file_pos == -1) - { - return false; - } - - u64 file_block; - if (!SearchEntry(std::string(s + file_pos), file_block)) - { - return false; - } - - LOG_NOTICE(HLE, "ENTRY FOUND AT 0x%llx", file_block); - m_file.Open(file_block); - - return vfsFileBase::Open(path, mode); -} - -bool vfsHDD::HasEntry(const std::string& name) -{ - u64 file_block; - if (!SearchEntry(name, file_block)) - { - return false; - } - - return true; -} - -void vfsHDD::RemoveBlocksDir(u64 start_block) -{ - std::string name; - u64 block = start_block; - vfsHDD_Entry entry; - - while (block) - { - ReadEntry(block, entry, name); - WriteBlock(block, g_null_block); - - if (entry.type == vfsHDD_Entry_Dir && name != "." && name != "..") - { - LOG_WARNING(HLE, "Removing sub folder '%s'", name.c_str()); - RemoveBlocksDir(entry.data_block); - } - else if (entry.type == vfsHDD_Entry_File) - { - RemoveBlocksFile(entry.data_block); - } - - block = entry.next_block; - } -} - -void vfsHDD::RemoveBlocksFile(u64 start_block) -{ - u64 block = start_block; - vfsHDD_Block block_data; - - while (block) - { - ReadBlock(block, block_data); - WriteBlock(block, g_null_block); - - block = block_data.next_block; - } -} - -bool vfsHDD::RemoveEntry(const std::string& name) -{ - u64 entry_block, parent_entry; - if (!SearchEntry(name, entry_block, &parent_entry)) - { - return false; - } - - vfsHDD_Entry entry; - ReadEntry(entry_block, entry); - if (entry.type == vfsHDD_Entry_Dir) - { - RemoveBlocksDir(entry.data_block); - } - else if (entry.type == vfsHDD_Entry_File) - { - RemoveBlocksFile(entry.data_block); - } - - if (parent_entry) - { - u64 next = entry.next_block; - ReadEntry(parent_entry, entry); - entry.next_block = next; - WriteEntry(parent_entry, entry); - } - WriteBlock(entry_block, g_null_block); - return true; -} - -u64 vfsHDD::Write(const void* src, u64 size) -{ - return m_file.Write(src, size); // ??? -} - -u64 vfsHDD::Read(void* dst, u64 size) -{ - return m_file.Read(dst, size); // ??? -} - -u64 vfsHDD::Seek(s64 offset, fs::seek_mode whence) -{ - switch (whence) - { - case fs::seek_set: return m_file.Seek(offset); - case fs::seek_cur: return m_file.Seek(Tell() + offset); - case fs::seek_end: return m_file.Seek(m_file.GetSize() + offset); - } - - throw EXCEPTION("Unknown whence (0x%x)", whence); -} - -u64 vfsHDD::Tell() const -{ - return m_file.Tell(); // ??? -} - -bool vfsHDD::Eof() const -{ - return m_file.Eof(); -} - -bool vfsHDD::IsOpened() const -{ - return true; // ??? -} - -u64 vfsHDD::GetSize() const -{ - return m_file.GetSize(); -} diff --git a/rpcs3/Emu/HDD/HDD.h b/rpcs3/Emu/HDD/HDD.h deleted file mode 100644 index a192de41e5..0000000000 --- a/rpcs3/Emu/HDD/HDD.h +++ /dev/null @@ -1,208 +0,0 @@ -#pragma once -#include "Emu/FS/vfsDevice.h" -#include "Emu/FS/vfsLocalFile.h" - -static const u64 g_hdd_magic = *(u64*)"PS3eHDD\0"; -static const u16 g_hdd_version = 0x0001; - -struct vfsHDD_Block -{ - struct - { - u64 is_used : 1; - u64 next_block : 63; - }; -} static const g_null_block = {0}, g_used_block = {1}; - -struct vfsHDD_Hdr : public vfsHDD_Block -{ - u64 magic; - u16 version; - u64 block_count; - u32 block_size; -}; - -enum vfsHDD_EntryType : u8 -{ - vfsHDD_Entry_Dir = 0, - vfsHDD_Entry_File = 1, - vfsHDD_Entry_Link = 2, -}; - -struct vfsHDD_Entry : public vfsHDD_Block -{ - u64 data_block; - u32 access; - vfsHDD_EntryType type; - u64 size; - u64 ctime; - u64 mtime; - u64 atime; -}; - -class vfsHDDManager -{ -public: - static void CreateBlock(vfsHDD_Block& block); - - static void CreateEntry(vfsHDD_Entry& entry); - - static void CreateHDD(const std::string& path, u64 size, u64 block_size); - - void Format(); - - void AppendEntry(vfsHDD_Entry entry); -}; - - -class vfsHDDFile -{ - u64 m_info_block; - vfsHDD_Entry m_info; - const vfsHDD_Hdr& m_hdd_info; - vfsLocalFile& m_hdd; - u32 m_position; - u64 m_cur_block; - - bool goto_block(u64 n); - - void RemoveBlocks(u64 start_block); - - void WriteBlock(u64 block, const vfsHDD_Block& data); - - void ReadBlock(u64 block, vfsHDD_Block& data); - - void WriteEntry(u64 block, const vfsHDD_Entry& data); - - void ReadEntry(u64 block, vfsHDD_Entry& data); - - void ReadEntry(u64 block, vfsHDD_Entry& data, std::string& name); - - void ReadEntry(u64 block, std::string& name); - - void WriteEntry(u64 block, const vfsHDD_Entry& data, const std::string& name); - - force_inline u32 GetMaxNameLen() const - { - return m_hdd_info.block_size - sizeof(vfsHDD_Entry); - } - -public: - vfsHDDFile(vfsLocalFile& hdd, const vfsHDD_Hdr& hdd_info) - : m_hdd(hdd) - , m_hdd_info(hdd_info) - { - } - - ~vfsHDDFile() - { - } - - void Open(u64 info_block); - - u64 FindFreeBlock(); - - u64 GetSize() const - { - return m_info.size; - } - - bool Seek(u64 pos); - - u64 Tell() const - { - return m_cur_block * m_hdd_info.block_size + m_position; // ??? - } - - void SaveInfo(); - - u64 Read(void* dst, u64 size); - - u64 Write(const void* src, u64 size); - - bool Eof() const - { - return m_info.size <= (m_cur_block * m_hdd_info.block_size + m_position); - } -}; - -class vfsDeviceHDD : public vfsDevice -{ - std::string m_hdd_path; - -public: - vfsDeviceHDD(const std::string& hdd_path); - - virtual vfsFileBase* GetNewFileStream() override; - virtual vfsDirBase* GetNewDirStream() override; -}; - -class vfsHDD : public vfsFileBase -{ - vfsHDD_Hdr m_hdd_info; - vfsLocalFile m_hdd_file; - const std::string& m_hdd_path; - vfsHDD_Entry m_cur_dir; - u64 m_cur_dir_block; - vfsHDDFile m_file; - -public: - vfsHDD(vfsDevice* device, const std::string& hdd_path); - - force_inline u32 GetMaxNameLen() const - { - return m_hdd_info.block_size - sizeof(vfsHDD_Entry); - } - - bool SearchEntry(const std::string& name, u64& entry_block, u64* parent_block = nullptr); - - s32 OpenDir(const std::string& name); - - bool Rename(const std::string& from, const std::string& to); - - u64 FindFreeBlock(); - - void WriteBlock(u64 block, const vfsHDD_Block& data); - - void ReadBlock(u64 block, vfsHDD_Block& data); - - void WriteEntry(u64 block, const vfsHDD_Entry& data); - - void ReadEntry(u64 block, vfsHDD_Entry& data); - - void ReadEntry(u64 block, vfsHDD_Entry& data, std::string& name); - - void ReadEntry(u64 block, std::string& name); - - void WriteEntry(u64 block, const vfsHDD_Entry& data, const std::string& name); - - bool Create(vfsHDD_EntryType type, const std::string& name); - - bool GetFirstEntry(u64& block, vfsHDD_Entry& entry, std::string& name); - - bool GetNextEntry(u64& block, vfsHDD_Entry& entry, std::string& name); - - virtual bool Open(const std::string& path, u32 mode = fom::read) override; - - bool HasEntry(const std::string& name); - - void RemoveBlocksDir(u64 start_block); - - void RemoveBlocksFile(u64 start_block); - - bool RemoveEntry(const std::string& name); - - virtual u64 Write(const void* src, u64 count) override; - - virtual u64 Read(void* dst, u64 count) override; - - virtual u64 Seek(s64 offset, fs::seek_mode whence = fs::seek_set) override; - - virtual u64 Tell() const override; - - virtual bool Eof() const override; - - virtual bool IsOpened() const override; - - virtual u64 GetSize() const override; -}; diff --git a/rpcs3/Emu/IdManager.cpp b/rpcs3/Emu/IdManager.cpp deleted file mode 100644 index 1f7dc195f7..0000000000 --- a/rpcs3/Emu/IdManager.cpp +++ /dev/null @@ -1,156 +0,0 @@ -#include "stdafx.h" -#include "IdManager.h" - -namespace idm -{ - shared_mutex g_mutex; - - idm::map_t g_map; - - u32 g_last_raw_id = 0; - - thread_local u32 g_tls_last_id = 0xdeadbeef; -} - -namespace fxm -{ - shared_mutex g_mutex; - - fxm::map_t g_map; -} - -void idm::clear() -{ - std::lock_guard lock(g_mutex); - - // Call recorded finalization functions for all IDs - for (auto& id : idm::map_t(std::move(g_map))) - { - (*id.second.type_index)(id.second.data.get()); - } - - g_last_raw_id = 0; -} - -bool idm::check(u32 in_id, id_type_index_t type) -{ - reader_lock lock(g_mutex); - - const auto found = g_map.find(in_id); - - return found != g_map.end() && found->second.type_index == type; -} - -const std::type_info* idm::get_type(u32 raw_id) -{ - reader_lock lock(g_mutex); - - const auto found = g_map.find(raw_id); - - return found == g_map.end() ? nullptr : found->second.info; -} - -std::shared_ptr idm::get(u32 in_id, id_type_index_t type) -{ - reader_lock lock(g_mutex); - - const auto found = g_map.find(in_id); - - if (found == g_map.end() || found->second.type_index != type) - { - return nullptr; - } - - return found->second.data; -} - -idm::map_t idm::get_all(id_type_index_t type) -{ - reader_lock lock(g_mutex); - - idm::map_t result; - - for (auto& id : g_map) - { - if (id.second.type_index == type) - { - result.insert(id); - } - } - - return result; -} - -std::shared_ptr idm::withdraw(u32 in_id, id_type_index_t type) -{ - std::lock_guard lock(g_mutex); - - const auto found = g_map.find(in_id); - - if (found == g_map.end() || found->second.type_index != type) - { - return nullptr; - } - - auto ptr = std::move(found->second.data); - - g_map.erase(found); - - return ptr; -} - -u32 idm::get_count(id_type_index_t type) -{ - reader_lock lock(g_mutex); - - u32 result = 0; - - for (auto& id : g_map) - { - if (id.second.type_index == type) - { - result++; - } - } - - return result; -} - - -void fxm::clear() -{ - std::lock_guard lock(g_mutex); - - // Call recorded finalization functions for all IDs - for (auto& id : fxm::map_t(std::move(g_map))) - { - if (id.second) (*id.first)(id.second.get()); - } -} - -bool fxm::check(id_type_index_t type) -{ - reader_lock lock(g_mutex); - - const auto found = g_map.find(type); - - return found != g_map.end() && found->second; -} - -std::shared_ptr fxm::get(id_type_index_t type) -{ - reader_lock lock(g_mutex); - - const auto found = g_map.find(type); - - return found != g_map.end() ? found->second : nullptr; -} - -std::shared_ptr fxm::withdraw(id_type_index_t type) -{ - std::unique_lock lock(g_mutex); - - const auto found = g_map.find(type); - - return found != g_map.end() ? std::move(found->second) : nullptr; -} diff --git a/rpcs3/Emu/IdManager.h b/rpcs3/Emu/IdManager.h index 347fa2b5b1..25604293ee 100644 --- a/rpcs3/Emu/IdManager.h +++ b/rpcs3/Emu/IdManager.h @@ -2,86 +2,154 @@ #include "Utilities/SharedMutex.h" -#define ID_MANAGER_INCLUDED +#include +#include -// TODO: make id_aux_initialize and id_aux_finalize safer against a possible ODR violation - -// Function called after the successfull creation of an ID (does nothing by default, provide an overload) -inline void id_aux_initialize(void*) +// Mostly helper namespace +namespace id_manager { - ; -} - -// Function called after the ID removal (does nothing by default, provide an overload) -inline void id_aux_finalize(void*) -{ - ; -} - -// Type-erased id_aux_* function type -using id_aux_func_t = void(*)(void*); - -template -struct id_type_info_t -{ - static const auto size = sizeof(T); // forbid forward declarations - - static const id_aux_func_t on_remove; -}; - -// Type-erased finalization function -template -const id_aux_func_t id_type_info_t::on_remove = [](void* ptr) -{ - return id_aux_finalize(static_cast(ptr)); -}; - -using id_type_index_t = const id_aux_func_t*; - -// Get a unique pointer to the on_remove value (will be unique for each type) -template -inline constexpr id_type_index_t get_id_type_index() -{ - return &id_type_info_t::on_remove; -} - -// Default ID traits for any arbitrary type -template -struct id_traits -{ - static const auto size = sizeof(T); // forbid forward declarations - - // Get next mapped id (may return 0 if out of IDs) - static u32 next_id(u32 raw_id) { return raw_id < 0x80000000 ? (raw_id + 1) & 0x7fffffff : 0; } - - // Convert "public" id to mapped id (may return 0 if invalid) - static u32 in_id(u32 id) { return id; } - - // Convert mapped id to "public" id - static u32 out_id(u32 raw_id) { return raw_id; } -}; - -// ID Manager -// 0 is invalid ID -// 1..0x7fffffff : general purpose IDs -// 0x80000000+ : reserved (may be used through id_traits specializations) -namespace idm -{ - struct id_data_t final + // Optional ID traits + template + struct id_traits { - std::shared_ptr data; - const std::type_info* info; - id_type_index_t type_index; + using tag = void; - template id_data_t(const std::shared_ptr& data) - : data(data) - , info(&typeid(T)) - , type_index(get_id_type_index()) + static constexpr u32 min = 1; + static constexpr u32 max = 0x7fffffff; + }; + + template + struct id_traits> + { + using tag = typename T::id_base; + + static constexpr u32 min = T::id_min; + static constexpr u32 max = T::id_max; + }; + + // Optional ID storage + template + struct id_storage + { + static const u32* get(T*) + { + return nullptr; + } + }; + + template + struct id_storage> + { + static const u32* get(T* ptr) + { + return &ptr->id; + } + }; + + // Optional object initialization function (called after ID registration) + template + struct on_init + { + static void func(T*) { } }; - // Custom hasher for ID values (map to itself) + template + struct on_init().on_init())> + { + static void func(T* ptr) + { + ptr->on_init(); + } + }; + + // Optional object finalization function (called after ID removal) + template + struct on_stop + { + static void func(T*) + { + } + }; + + template + struct on_stop().on_stop())> + { + static void func(T* ptr) + { + ptr->on_stop(); + } + }; + + template + class typeinfo + { + // Global variable for each registered type + template + struct registered + { + static const u32 index; + }; + + // Access global type list + static never_inline auto& access() + { + static std::vector list; + + return list; + } + + static never_inline u32 add_type(typeinfo info) + { + auto& list = access(); + + list.emplace_back(info); + + return ::size32(list) - 1; + } + + public: + const std::type_info* info; + void(*on_init)(void*); + void(*on_stop)(void*); + + // Get type index + template + static inline u32 get_index() + { + // Forbid forward declarations (It'd be better to allow them sometimes but it seems too dangerous) + static constexpr auto size = sizeof(std::conditional_t::value, void*, T>); + + return registered::index; + } + + // Read all registered types + static inline const auto& get() + { + return access(); + } + }; + + template template + const u32 typeinfo::registered::index = typeinfo::add_type( + { + &typeid(T), + PURE_EXPR(id_manager::on_init::func(static_cast(ptr)), void* ptr), + PURE_EXPR(id_manager::on_stop::func(static_cast(ptr)), void* ptr), + }); +} + +// Object manager for emulated process. Multiple objects of specified arbitrary type are given unique IDs. +class idm +{ + // Rules for ID allocation: + // 0) Individual ID counter may be specified for each type by defining 'using id_base = ...;' + // 1) If no id_base specified, void is assumed. + // 2) g_id[id_base] indicates next ID allocated in g_map. + // 3) g_map[id_base] contains the additional copy of object pointer. + + // Custom hasher for ID values struct id_hash_t final { std::size_t operator ()(u32 value) const @@ -90,82 +158,157 @@ namespace idm } }; - using map_t = std::unordered_map; + using map_type = std::unordered_map, id_hash_t>; - // Can be called from the constructor called through make() or make_ptr() to get the ID of the object being created - inline u32 get_last_id() + // Type Index -> ID -> Object. Use global since only one process is supported atm. + static std::vector g_map; + + // Next ID for each category + static std::vector g_id; + + static shared_mutex g_mutex; + + static const auto& get_types() { - extern thread_local u32 g_tls_last_id; - - return g_tls_last_id; + return id_manager::typeinfo::get(); } - // Remove all objects - void clear(); - - // Internal - bool check(u32 in_id, id_type_index_t type); - - // Check if an ID of specified type exists template - bool check(u32 id) + static inline u32 get_type() { - return check(id_traits::in_id(id), get_id_type_index()); + return id_manager::typeinfo::get_index(); } - // Check if an ID exists and return its type or nullptr - const std::type_info* get_type(u32 raw_id); - - // Internal - template - std::shared_ptr add(Ptr&& get_ptr) + template + static inline u32 get_tag() { - extern shared_mutex g_mutex; - extern idm::map_t g_map; - extern u32 g_last_raw_id; - extern thread_local u32 g_tls_last_id; + return get_type::tag>(); + } + // Prepares new ID, returns nullptr if out of resources + static map_type::pointer allocate_id(u32 tag, u32 min, u32 max) + { + // Check all IDs starting from "next id" + for (u32 i = 0; i <= max - min; i++) + { + // Fix current ID (wrap around) + if (g_id[tag] < min || g_id[tag] > max) g_id[tag] = min; + + // Get ID + const auto r = g_map[tag].emplace(g_id[tag]++, nullptr); + + if (r.second) + { + return &*r.first; + } + } + + // Nothing found + return nullptr; + } + + // Deallocate ID, returns object + static std::shared_ptr deallocate_id(u32 tag, u32 id) + { + const auto found = g_map[tag].find(id); + + if (found == g_map[tag].end()) return nullptr; + + auto ptr = std::move(found->second); + + g_map[tag].erase(found); + + return ptr; + } + + // Allocate new ID and construct it from the provider() + template> + static map_type::pointer create_id(F&& provider) + { std::lock_guard lock(g_mutex); - for (u32 raw_id = g_last_raw_id; (raw_id = id_traits::next_id(raw_id)); /**/) + if (auto place = allocate_id(get_tag(), id_manager::id_traits::min, id_manager::id_traits::max)) { - if (g_map.find(raw_id) != g_map.end()) continue; + try + { + // Get object, write it + place->second = provider(); + + // Update ID storage if available + if (const u32* id = id_manager::id_storage::get(static_cast(place->second.get()))) + { + *const_cast(id) = place->first; + } - g_tls_last_id = id_traits::out_id(raw_id); - - std::shared_ptr ptr = get_ptr(); - - g_map.emplace(raw_id, id_data_t(ptr)); - - if (raw_id < 0x80000000) g_last_raw_id = raw_id; - - return ptr; + return &*g_map[get_type()].emplace(*place).first; + } + catch (...) + { + deallocate_id(get_tag(), place->first); + throw; + } } return nullptr; } - // Add a new ID of specified type with specified constructor arguments (returns object or nullptr) - template - std::enable_if_t::value, std::shared_ptr> make_ptr(Args&&... args) + // Remove ID and return object + static std::shared_ptr delete_id(u32 type, u32 tag, u32 id) { - if (auto ptr = add(WRAP_EXPR(std::make_shared(std::forward(args)...)))) + std::lock_guard lock(g_mutex); + + auto&& ptr = deallocate_id(tag, id); + + g_map[type].erase(id); + + return ptr; + } + +public: + // Initialize object manager + static void init() + { + g_map.resize(get_types().size(), {}); + g_id.resize(get_types().size(), 0); + } + + // Remove all objects + static void clear() + { + // Call recorded finalization functions for all IDs + for (std::size_t i = 0; i < g_map.size(); i++) { - id_aux_initialize(ptr.get()); - return ptr; + for (auto& id : g_map[i]) + { + get_types()[i].on_stop(id.second.get()); + } + + g_map[i].clear(); + g_id[i] = 0; + } + } + + // Add a new ID of specified type with specified constructor arguments (returns object or nullptr) + template + static std::enable_if_t::value, std::shared_ptr> make_ptr(Args&&... args) + { + if (auto pair = create_id(WRAP_EXPR(std::make_shared(std::forward(args)...)))) + { + id_manager::on_init::func(static_cast(pair->second.get())); + return{ pair->second, static_cast(pair->second.get()) }; } return nullptr; } // Add a new ID of specified type with specified constructor arguments (returns id) - template - std::enable_if_t::value, u32> make(Args&&... args) + template + static std::enable_if_t::value, u32> make(Args&&... args) { - if (auto ptr = add(WRAP_EXPR(std::make_shared(std::forward(args)...)))) + if (auto pair = create_id(WRAP_EXPR(std::make_shared(std::forward(args)...)))) { - id_aux_initialize(ptr.get()); - return get_last_id(); + id_manager::on_init::func(static_cast(pair->second.get())); + return pair->first; } throw EXCEPTION("Out of IDs ('%s')", typeid(T).name()); @@ -173,93 +316,118 @@ namespace idm // Add a new ID for an existing object provided (returns new id) template - u32 import(const std::shared_ptr& ptr) + static u32 import_existing(const std::shared_ptr& ptr) { - static const auto size = sizeof(T); // forbid forward declarations - - if (add(WRAP_EXPR(ptr))) + if (auto pair = create_id(WRAP_EXPR(ptr))) { - id_aux_initialize(ptr.get()); - return get_last_id(); + id_manager::on_init::func(static_cast(pair->second.get())); + return pair->first; } throw EXCEPTION("Out of IDs ('%s')", typeid(T).name()); } - // Internal - std::shared_ptr get(u32 in_id, id_type_index_t type); - - // Get ID of specified type - template - std::shared_ptr get(u32 id) + // Add a new ID for an object returned by provider() + template> + static std::shared_ptr import(F&& provider) { - return std::static_pointer_cast(get(id_traits::in_id(id), get_id_type_index())); - } - - // Internal - idm::map_t get_all(id_type_index_t type); - - // Get all IDs of specified type T (unsorted) - template - std::vector> get_all() - { - std::vector> result; - - for (auto& id : get_all(get_id_type_index())) + if (auto pair = create_id(std::forward(provider))) { - result.emplace_back(std::static_pointer_cast(id.second.data)); - } - - return result; - } - - std::shared_ptr withdraw(u32 in_id, id_type_index_t type); - - // Remove the ID created with type T - template - bool remove(u32 id) - { - if (auto ptr = withdraw(id_traits::in_id(id), get_id_type_index())) - { - id_aux_finalize(static_cast(ptr.get())); - - return true; - } - - return false; - } - - // Remove the ID created with type T and return it - template - std::shared_ptr withdraw(u32 id) - { - if (auto ptr = std::static_pointer_cast(withdraw(id_traits::in_id(id), get_id_type_index()))) - { - id_aux_finalize(ptr.get()); - - return ptr; + id_manager::on_init::func(static_cast(pair->second.get())); + return { pair->second, static_cast(pair->second.get()) }; } return nullptr; } - u32 get_count(id_type_index_t type); + // Check whether ID exists + template + static bool check(u32 id) + { + reader_lock lock(g_mutex); + + return g_map[get_type()].count(id) != 0; + } + + // Get ID + template + static std::shared_ptr get(u32 id) + { + reader_lock lock(g_mutex); + + const auto found = g_map[get_type()].find(id); + + if (found == g_map[get_type()].end()) + { + return nullptr; + } + + return{ found->second, static_cast(found->second.get()) }; + } + + // Get all IDs (unsorted) + template + static std::vector> get_all() + { + reader_lock lock(g_mutex); + + std::vector> result; + + for (auto& id : g_map[get_type()]) + { + result.emplace_back(id.second, static_cast(id.second.get())); + } + + return result; + } + + // Remove the ID + template + static bool remove(u32 id) + { + auto&& ptr = delete_id(get_type(), get_tag(), id); + + if (ptr) + { + id_manager::on_stop::func(static_cast(ptr.get())); + } + + return ptr.operator bool(); + } + + // Remove the ID and return it + template + static std::shared_ptr withdraw(u32 id) + { + auto&& ptr = delete_id(get_type(), get_tag(), id); + + if (ptr) + { + id_manager::on_stop::func(static_cast(ptr.get())); + } + + return{ ptr, static_cast(ptr.get()) }; + } template - u32 get_count() + static u32 get_count() { - return get_count(get_id_type_index()); + reader_lock lock(g_mutex); + + return ::size32(g_map[get_type()]); } // Get sorted list of all IDs of specified type template - std::set get_set() + static std::set get_set() { + reader_lock lock(g_mutex); + std::set result; - for (auto& id : get_all(get_id_type_index())) + for (auto& id : g_map[get_type()]) { - result.emplace(id_traits::out_id(id.first)); + result.emplace(id.first); } return result; @@ -267,188 +435,234 @@ namespace idm // Get sorted map (ID value -> ID data) of all IDs of specified type template - std::map> get_map() + static std::map> get_map() { + reader_lock lock(g_mutex); + std::map> result; - for (auto& id : get_all(get_id_type_index())) + for (auto& id : g_map[get_type()]) { - result[id_traits::out_id(id.first)] = std::static_pointer_cast(id.second.data); + result[id.first] = { id.second, static_cast(id.second.get()) }; } return result; } -} +}; -// Fixed Object Manager -// allows to manage shared objects of any specified type, but only one object per type; -// object are deleted when the emulation is stopped -namespace fxm +// Object manager for emulated process. One unique object per type, or zero. +class fxm { - // Custom hasher for aligned pointer values - struct hash_t final + // Type Index -> Object. Use global since only one process is supported atm. + static std::vector> g_map; + + static shared_mutex g_mutex; + + static inline const auto& get_types() { - std::size_t operator()(id_type_index_t value) const - { - return reinterpret_cast(value) >> 3; - } - }; + return id_manager::typeinfo::get(); + } - using map_t = std::unordered_map, hash_t>; - - // Remove all objects - void clear(); - - // Internal (returns old and new pointers) - template - std::pair, std::shared_ptr> add(Ptr&& get_ptr) + template + static inline u32 get_type() { - extern shared_mutex g_mutex; - extern fxm::map_t g_map; + return id_manager::typeinfo::get_index(); + } + static std::shared_ptr remove(u32 type) + { std::lock_guard lock(g_mutex); - auto& item = g_map[get_id_type_index()]; + return std::move(g_map[type]); + } - if (Always || !item) +public: + // Initialize object manager + static void init() + { + g_map.resize(get_types().size(), {}); + } + + // Remove all objects + static void clear() + { + // Call recorded finalization functions for all IDs + for (std::size_t i = 0; i < g_map.size(); i++) { - std::shared_ptr old = std::static_pointer_cast(std::move(item)); - std::shared_ptr ptr = get_ptr(); + if (g_map[i]) + { + get_types()[i].on_stop(g_map[i].get()); + } - // Set new object - item = ptr; - - return{ std::move(old), std::move(ptr) }; - } - else - { - return{ std::static_pointer_cast(item), nullptr }; + g_map[i].reset(); } } // Create the object (returns nullptr if it already exists) - template - std::enable_if_t::value, std::shared_ptr> make(Args&&... args) + template + static std::enable_if_t::value, std::shared_ptr> make(Args&&... args) { - auto pair = add(WRAP_EXPR(std::make_shared(std::forward(args)...))); - - if (pair.second) + std::shared_ptr ptr; { - id_aux_initialize(pair.second.get()); + std::lock_guard lock(g_mutex); + + if (!g_map[get_type()]) + { + ptr = std::make_shared(std::forward(args)...); + + g_map[get_type()] = ptr; + } } - return std::move(pair.second); + if (ptr) + { + id_manager::on_init::func(ptr.get()); + } + + return ptr; } // Create the object unconditionally (old object will be removed if it exists) - template - std::enable_if_t::value, std::shared_ptr> make_always(Args&&... args) + template + static std::enable_if_t::value, std::shared_ptr> make_always(Args&&... args) { - auto pair = add(WRAP_EXPR(std::make_shared(std::forward(args)...))); - - if (pair.first) + std::shared_ptr ptr; + std::shared_ptr old; { - id_aux_finalize(pair.first.get()); + std::lock_guard lock(g_mutex); + + old = std::move(g_map[get_type()]); + ptr = std::make_shared(std::forward(args)...); + + g_map[get_type()] = ptr; } - id_aux_initialize(pair.second.get()); - return std::move(pair.second); + if (old) + { + id_manager::on_stop::func(static_cast(old.get())); + } + + id_manager::on_init::func(ptr.get()); + return ptr; } // Emplace the object returned by provider() and return it if no object exists template - auto import(F&& provider) -> decltype(static_cast>(provider())) + static auto import(F&& provider) -> decltype(static_cast>(provider())) { - static const auto size = sizeof(T); // forbid forward declarations - - auto pair = add(std::forward(provider)); - - if (pair.second) + std::shared_ptr ptr; { - id_aux_initialize(pair.second.get()); + std::lock_guard lock(g_mutex); + + if (!g_map[get_type()]) + { + ptr = provider(); + + g_map[get_type()] = ptr; + } } - return std::move(pair.second); + if (ptr) + { + id_manager::on_init::func(ptr.get()); + } + + return ptr; } // Emplace the object return by provider() (old object will be removed if it exists) template - auto import_always(F&& provider) -> decltype(static_cast>(provider())) + static auto import_always(F&& provider) -> decltype(static_cast>(provider())) { - static const auto size = sizeof(T); // forbid forward declarations - - auto pair = add(std::forward(provider)); - - if (pair.first) + std::shared_ptr ptr; + std::shared_ptr old; { - id_aux_finalize(pair.first.get()); + std::lock_guard lock(g_mutex); + + old = std::move(g_map[get_type()]); + ptr = provider(); + + g_map[get_type()] = ptr; } - id_aux_initialize(pair.second.get()); - return std::move(pair.second); + if (old) + { + id_manager::on_stop::func(static_cast(old.get())); + } + + id_manager::on_init::func(ptr.get()); + return ptr; } // Get the object unconditionally (create an object if it doesn't exist) - template - std::enable_if_t::value, std::shared_ptr> get_always(Args&&... args) + template + static std::enable_if_t::value, std::shared_ptr> get_always(Args&&... args) { - auto pair = add(WRAP_EXPR(std::make_shared(std::forward(args)...))); - - if (pair.second) + std::shared_ptr ptr; { - id_aux_initialize(pair.second.get()); - return std::move(pair.second); + std::lock_guard lock(g_mutex); + + if (auto& value = g_map[get_type()]) + { + return{ value, static_cast(value.get()) }; + } + else + { + ptr = std::make_shared(std::forward(args)...); + + g_map[get_type()] = ptr; + } } - return std::move(pair.first); + id_manager::on_init::func(ptr.get()); + return ptr; } - // Internal - bool check(id_type_index_t type); - // Check whether the object exists template - bool check() + static bool check() { - return check(get_id_type_index()); - } + reader_lock lock(g_mutex); - // Internal - std::shared_ptr get(id_type_index_t type); + return g_map[get_type()].operator bool(); + } // Get the object (returns nullptr if it doesn't exist) template - std::shared_ptr get() + static std::shared_ptr get() { - return std::static_pointer_cast(get(get_id_type_index())); - } + reader_lock lock(g_mutex); - // Internal - std::shared_ptr withdraw(id_type_index_t type); + auto& ptr = g_map[get_type()]; + + return{ ptr, static_cast(ptr.get()) }; + } // Delete the object template - bool remove() + static bool remove() { - if (auto ptr = withdraw(get_id_type_index())) + auto&& ptr = remove(get_type()); + + if (ptr) { - id_aux_finalize(static_cast(ptr.get())); - return true; + id_manager::on_stop::func(static_cast(ptr.get())); } - return false; + return ptr.operator bool(); } // Delete the object and return it template - std::shared_ptr withdraw() + static std::shared_ptr withdraw() { - if (auto ptr = std::static_pointer_cast(withdraw(get_id_type_index()))) + auto&& ptr = remove(get_type()); + + if (ptr) { - id_aux_finalize(ptr.get()); - return ptr; + id_manager::on_stop::func(static_cast(ptr.get())); } - return nullptr; + return{ ptr, static_cast(ptr.get()) }; } -} +}; diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 445ebd4613..cad2d7f48c 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -1,92 +1,62 @@ #include "stdafx.h" - -#include "config.h" -#include "events.h" -#include "state.h" - +#include "Utilities/Config.h" +#include "Utilities/AutoPause.h" +#include "Utilities/event.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/GameInfo.h" -#include "Emu/SysCalls/ModuleManager.h" #include "Emu/Cell/PPUThread.h" +#include "Emu/Cell/PPUCallback.h" +#include "Emu/Cell/PPUOpcodes.h" #include "Emu/Cell/SPUThread.h" -#include "Emu/Cell/PPUInstrTable.h" -#include "Emu/FS/vfsFile.h" -#include "Emu/FS/vfsLocalFile.h" -#include "Emu/FS/vfsDeviceLocalFile.h" +#include "Emu/Cell/lv2/sys_sync.h" -#include "Emu/CPU/CPUThreadManager.h" -#include "Emu/SysCalls/Callback.h" #include "Emu/IdManager.h" -#include "Emu/Io/Pad.h" -#include "Emu/Io/Keyboard.h" -#include "Emu/Io/Mouse.h" -#include "Emu/RSX/GSManager.h" -#include "Emu/Audio/AudioManager.h" -#include "Emu/FS/VFS.h" -#include "Emu/Event.h" +#include "Emu/RSX/GSRender.h" #include "Loader/PSF.h" -#include "Loader/ELF64.h" -#include "Loader/ELF32.h" +#include "Loader/ELF.h" #include "../Crypto/unself.h" -using namespace PPU_instr; +cfg::bool_entry g_cfg_autostart(cfg::root.misc, "Always start after boot"); +cfg::bool_entry g_cfg_autoexit(cfg::root.misc, "Exit RPCS3 when process finishes"); -static const std::string& BreakPointsDBName = "BreakPoints.dat"; -static const u16 bpdb_version = 0x1000; +std::string g_cfg_defaults; -// Draft (not used) -struct bpdb_header_t -{ - le_t magic; - le_t version; - le_t count; - le_t marked; +extern cfg::string_entry g_cfg_vfs_dev_bdvd; +extern cfg::string_entry g_cfg_vfs_app_home; - // POD - bpdb_header_t() = default; - - bpdb_header_t(u32 count, u32 marked) - : magic(*reinterpret_cast("BPDB")) - , version(0x00010000) - , count(count) - , marked(marked) - { - } -}; - -extern std::atomic g_thread_count; +extern atomic_t g_thread_count; extern u64 get_system_time(); -extern void finalize_psv_modules(); + +namespace rpcs3 +{ + event& on_run() { static event on_run; return on_run; } + event& on_stop() { static event on_stop; return on_stop; } + event& on_pause() { static event on_pause; return on_pause; } + event& on_resume() { static event on_resume; return on_resume; } +} Emulator::Emulator() : m_status(Stopped) - , m_mode(DisAsm) - , m_rsx_callback(0) , m_cpu_thr_stop(0) - , m_thread_manager(new CPUThreadManager()) - , m_pad_manager(new PadManager()) - , m_keyboard_manager(new KeyboardManager()) - , m_mouse_manager(new MouseManager()) - , m_gs_manager(new GSManager()) - , m_audio_manager(new AudioManager()) , m_callback_manager(new CallbackManager()) - , m_event_manager(new EventManager()) - , m_module_manager(new ModuleManager()) - , m_vfs(new VFS()) { - m_loader.register_handler(new loader::handlers::elf32); - m_loader.register_handler(new loader::handlers::elf64); } void Emulator::Init() { - rpcs3::config.load(); - rpcs3::oninit(); + idm::init(); + fxm::init(); + + // Reset defaults, cache them + cfg::root.from_default(); + g_cfg_defaults = cfg::root.to_string(); + + // Reload global configuration + cfg::root.from_string(fs::file(fs::get_config_dir() + "/config.yml", fs::read + fs::create).to_string()); } void Emulator::SetPath(const std::string& path, const std::string& elf_path) @@ -95,31 +65,6 @@ void Emulator::SetPath(const std::string& path, const std::string& elf_path) m_elf_path = elf_path; } -void Emulator::SetTitleID(const std::string& id) -{ - m_title_id = id; -} - -void Emulator::SetTitle(const std::string& title) -{ - m_title = title; -} - -void Emulator::CreateConfig(const std::string& name) -{ - const std::string& path = fs::get_config_dir() + "data/" + name; - const std::string& ini_file = path + "/settings.ini"; - - if (!fs::is_dir("data")) - fs::create_dir("data"); - - if (!fs::is_dir(path)) - fs::create_dir(path); - - if (!fs::is_file(ini_file)) - rpcs3::config_t{ ini_file }.save(); -} - bool Emulator::BootGame(const std::string& path, bool direct) { static const char* boot_list[] = @@ -158,141 +103,161 @@ bool Emulator::BootGame(const std::string& path, bool direct) void Emulator::Load() { - m_status = Ready; + Stop(); - if (!fs::is_file(m_path)) + try { - m_status = Stopped; - return; - } + Init(); - const std::string& elf_dir = fs::get_parent_dir(m_path); - - if (IsSelf(m_path)) - { - const std::size_t elf_ext_pos = m_path.find_last_of('.'); - const std::string& elf_ext = fmt::toupper(m_path.substr(elf_ext_pos != -1 ? elf_ext_pos : m_path.size())); - const std::string& elf_name = m_path.substr(elf_dir.size()); - - if (elf_name.compare(elf_name.find_last_of("/\\", -1, 2) + 1, 9, "EBOOT.BIN", 9) == 0) + if (!fs::is_file(m_path)) { - m_path.erase(m_path.size() - 9, 1); // change EBOOT.BIN to BOOT.BIN + LOG_ERROR(LOADER, "File not found: %s", m_path); + return; } - else if (elf_ext == ".SELF" || elf_ext == ".SPRX") + + const std::string& elf_dir = fs::get_parent_dir(m_path); + + if (IsSelf(m_path)) { - m_path.erase(m_path.size() - 4, 1); // change *.self to *.elf, *.sprx to *.prx + const std::size_t elf_ext_pos = m_path.find_last_of('.'); + const std::string& elf_ext = fmt::to_upper(m_path.substr(elf_ext_pos != -1 ? elf_ext_pos : m_path.size())); + const std::string& elf_name = m_path.substr(elf_dir.size()); + + if (elf_name.compare(elf_name.find_last_of("/\\", -1, 2) + 1, 9, "EBOOT.BIN", 9) == 0) + { + m_path.erase(m_path.size() - 9, 1); // change EBOOT.BIN to BOOT.BIN + } + else if (elf_ext == ".SELF" || elf_ext == ".SPRX") + { + m_path.erase(m_path.size() - 4, 1); // change *.self to *.elf, *.sprx to *.prx + } + else + { + m_path += ".decrypted.elf"; + } + + if (!DecryptSelf(m_path, elf_dir + elf_name)) + { + LOG_ERROR(LOADER, "Failed to decrypt %s", elf_dir + elf_name); + return; + } + } + + ResetInfo(); + + LOG_NOTICE(LOADER, "Path: %s", m_path); + + // Load custom config + if (fs::file cfg_file{ m_path + ".yml" }) + { + LOG_NOTICE(LOADER, "Custom config: %s.yml", m_path); + cfg::root.from_string(cfg_file.to_string()); + } + + const fs::file elf_file(m_path); + ppu_exec_loader ppu_exec; + ppu_prx_loader ppu_prx; + spu_exec_loader spu_exec; + arm_exec_loader arm_exec; + + if (!elf_file) + { + LOG_ERROR(LOADER, "Failed to open %s", m_path); + return; + } + else if (ppu_exec.open(elf_file) == elf_error::ok) + { + // PS3 executable + m_status = Ready; + vm::ps3::init(); + + if (m_elf_path.empty()) + { + m_elf_path = "/host_root/" + m_path; + LOG_NOTICE(LOADER, "Elf path: %s", m_elf_path); + } + + // Load PARAM.SFO + m_psf = psf::load_object(fs::file(elf_dir + "/../PARAM.SFO")); + m_title = psf::get_string(m_psf, "TITLE", m_path); + m_title_id = psf::get_string(m_psf, "TITLE_ID"); + LOG_NOTICE(LOADER, "Title: %s", GetTitle()); + LOG_NOTICE(LOADER, "Serial: %s", GetTitleID()); + LOG_NOTICE(LOADER, ""); + + LOG_NOTICE(LOADER, "Used configuration:\n%s\n", cfg::root.to_string()); + + // Mount /dev_bdvd/ + if (g_cfg_vfs_dev_bdvd.size() == 0 && fs::is_file(elf_dir + "/../../PS3_DISC.SFB")) + { + const auto dir_list = fmt::split(elf_dir, { "/", "\\" }); + + // Check latest two directories + if (dir_list.size() >= 2 && dir_list.back() == "USRDIR" && *(dir_list.end() - 2) == "PS3_GAME") + { + g_cfg_vfs_dev_bdvd = elf_dir.substr(0, elf_dir.length() - 15); + } + else + { + g_cfg_vfs_dev_bdvd = elf_dir + "/../../"; + } + } + + // Mount /app_home/ + if (g_cfg_vfs_app_home.size() == 0) + { + g_cfg_vfs_app_home = elf_dir + '/'; + } + + vfs::dump(); + + ppu_exec.load(); + + Emu.GetCallbackManager().Init(); + fxm::import(PURE_EXPR(Emu.GetCallbacks().get_gs_render())); // TODO: must be created in appropriate sys_rsx syscall + } + else if (ppu_prx.open(elf_file) == elf_error::ok) + { + // PPU PRX (experimental) + m_status = Ready; + vm::ps3::init(); + ppu_prx.load(); + GetCallbackManager().Init(); + } + else if (spu_exec.open(elf_file) == elf_error::ok) + { + // SPU executable (experimental) + m_status = Ready; + vm::ps3::init(); + spu_exec.load(); + } + else if (arm_exec.open(elf_file) == elf_error::ok) + { + // ARMv7 executable + m_status = Ready; + vm::psv::init(); + arm_exec.load(); } else { - m_path += ".decrypted.elf"; - } + LOG_ERROR(LOADER, "Invalid or unsupported file format: %s", m_path); - if (!DecryptSelf(m_path, elf_dir + elf_name)) - { - m_status = Stopped; + LOG_WARNING(LOADER, "** ppu_exec_loader -> %s", bijective_find(ppu_exec, "???")); + LOG_WARNING(LOADER, "** ppu_prx_loader -> %s", bijective_find(ppu_prx, "???")); + LOG_WARNING(LOADER, "** spu_exec_loader -> %s", bijective_find(spu_exec, "???")); + LOG_WARNING(LOADER, "** arm_exec_loader -> %s", bijective_find(arm_exec, "???")); return; } + + debug::autopause::reload(); + SendDbgCommand(DID_READY_EMU); + if (g_cfg_autostart) Run(); } - - ResetInfo(); - GetVFS().Init(elf_dir); - - LOG_NOTICE(LOADER, "Loading '%s'...", m_path.c_str()); - - // /dev_bdvd/ mounting - vfsFile f("/app_home/../dev_bdvd.path"); - if (f.IsOpened()) + catch (const std::exception& e) { - // load specified /dev_bdvd/ directory and mount it - std::string bdvd; - bdvd.resize(f.GetSize()); - f.Read(&bdvd[0], bdvd.size()); - - Emu.GetVFS().Mount("/dev_bdvd/", bdvd, new vfsDeviceLocalFile()); + LOG_FATAL(LOADER, "%s thrown: %s", typeid(e).name(), e.what()); + Stop(); } - else if (fs::is_file(elf_dir + "/../../PS3_DISC.SFB")) // guess loading disc game - { - const auto dir_list = fmt::split(elf_dir, { "/", "\\" }); - - // check latest two directories - if (dir_list.size() >= 2 && dir_list.back() == "USRDIR" && *(dir_list.end() - 2) == "PS3_GAME") - { - // mount detected /dev_bdvd/ directory - Emu.GetVFS().Mount("/dev_bdvd/", elf_dir.substr(0, elf_dir.length() - 16), new vfsDeviceLocalFile()); - } - } - - LOG_NOTICE(LOADER, ""); - LOG_NOTICE(LOADER, "Mount info:"); - for (uint i = 0; i < GetVFS().m_devices.size(); ++i) - { - LOG_NOTICE(LOADER, "%s -> %s", GetVFS().m_devices[i]->GetPs3Path().c_str(), GetVFS().m_devices[i]->GetLocalPath().c_str()); - } - - LOG_NOTICE(LOADER, ""); - f.Open("/app_home/../PARAM.SFO"); - const auto& psf = psf::load(f.VRead()); - std::string title = psf::get_string(psf, "TITLE"); - std::string title_id = psf::get_string(psf, "TITLE_ID"); - LOG_NOTICE(LOADER, "Title: %s", title.c_str()); - LOG_NOTICE(LOADER, "Serial: %s", title_id.c_str()); - - title.length() ? SetTitle(title) : SetTitle(m_path); - SetTitleID(title_id); - - rpcs3::state.config = rpcs3::config; - - // load custom config - if (!rpcs3::config.misc.use_default_ini.value()) - { - if (title_id.size()) - { - title_id = title_id.substr(0, 4) + "-" + title_id.substr(4, 5); - CreateConfig(title_id); - rpcs3::config_t custom_config { fs::get_config_dir() + "data/" + title_id + "/settings.ini" }; - custom_config.load(); - rpcs3::state.config = custom_config; - } - } - - LOG_NOTICE(LOADER, "Used configuration: '%s'", rpcs3::state.config.path().c_str()); - LOG_NOTICE(LOADER, ""); - LOG_NOTICE(LOADER, rpcs3::state.config.to_string().c_str()); - - if (m_elf_path.empty()) - { - GetVFS().GetDeviceLocal(m_path, m_elf_path); - - LOG_NOTICE(LOADER, "Elf path: %s", m_elf_path); - LOG_NOTICE(LOADER, ""); - } - - f.Open(m_elf_path); - - if (!f.IsOpened()) - { - LOG_ERROR(LOADER, "Opening '%s' failed", m_path.c_str()); - m_status = Stopped; - return; - } - - if (!m_loader.load(f)) - { - LOG_ERROR(LOADER, "Loading '%s' failed", m_path.c_str()); - LOG_NOTICE(LOADER, ""); - m_status = Stopped; - vm::close(); - return; - } - - LoadPoints(fs::get_config_dir() + BreakPointsDBName); - - GetGSManager().Init(); - GetCallbackManager().Init(); - GetAudioManager().Init(); - GetEventManager().Init(); - - SendDbgCommand(DID_READY_EMU); } void Emulator::Run() @@ -311,7 +276,7 @@ void Emulator::Run() return; } - rpcs3::onstart(); + rpcs3::on_run()(); SendDbgCommand(DID_START_EMU); @@ -319,7 +284,12 @@ void Emulator::Run() m_pause_amend_time = 0; m_status = Running; - GetCPU().Exec(); + for (auto& thread : get_all_cpu_threads()) + { + thread->state -= cpu_state::stop; + thread->safe_notify(); + } + SendDbgCommand(DID_STARTED_EMU); } @@ -327,15 +297,15 @@ bool Emulator::Pause() { const u64 start = get_system_time(); - // try to set Paused status - if (!sync_bool_compare_and_swap(&m_status, Running, Paused)) + // Try to pause + if (!m_status.compare_and_swap_test(Running, Paused)) { return false; } - rpcs3::onpause(); + rpcs3::on_pause()(); - // update pause start time + // Update pause start time if (m_pause_start_time.exchange(start)) { LOG_ERROR(GENERAL, "Emulator::Pause() error: concurrent access"); @@ -343,9 +313,9 @@ bool Emulator::Pause() SendDbgCommand(DID_PAUSE_EMU); - for (auto& t : GetCPU().GetAllThreads()) + for (auto& thread : get_all_cpu_threads()) { - t->sleep(); // trigger status check + thread->state += cpu_state::dbg_global_pause; } SendDbgCommand(DID_PAUSED_EMU); @@ -355,17 +325,17 @@ bool Emulator::Pause() void Emulator::Resume() { - // get pause start time + // Get pause start time const u64 time = m_pause_start_time.exchange(0); - // try to increment summary pause time + // Try to increment summary pause time if (time) { m_pause_amend_time += get_system_time() - time; } - // try to resume - if (!sync_bool_compare_and_swap(&m_status, Paused, Running)) + // Try to resume + if (!m_status.compare_and_swap_test(Paused, Running)) { return; } @@ -377,41 +347,36 @@ void Emulator::Resume() SendDbgCommand(DID_RESUME_EMU); - for (auto& t : GetCPU().GetAllThreads()) + for (auto& thread : get_all_cpu_threads()) { - t->awake(); // untrigger status check and signal + thread->state -= cpu_state::dbg_global_pause; + thread->safe_notify(); } - rpcs3::onstart(); + rpcs3::on_resume()(); SendDbgCommand(DID_RESUMED_EMU); } -extern std::map g_armv7_dump; - void Emulator::Stop() { - LOG_NOTICE(GENERAL, "Stopping emulator..."); - - if (sync_lock_test_and_set(&m_status, Stopped) == Stopped) + if (m_status.exchange(Stopped) == Stopped) { return; } - rpcs3::onstop(); + LOG_NOTICE(GENERAL, "Stopping emulator..."); + + rpcs3::on_stop()(); SendDbgCommand(DID_STOP_EMU); { LV2_LOCK; - // notify all threads - for (auto& t : GetCPU().GetAllThreads()) + for (auto& thread : get_all_cpu_threads()) { - std::lock_guard lock(t->mutex); - - t->sleep(); // trigger status check - - t->cv.notify_one(); // signal + thread->state += cpu_state::dbg_global_stop; + thread->safe_notify(); } } @@ -431,86 +396,34 @@ void Emulator::Stop() LOG_NOTICE(GENERAL, "Objects cleared..."); - finalize_psv_modules(); - - for (auto& v : decltype(g_armv7_dump)(std::move(g_armv7_dump))) - { - LOG_NOTICE(ARMv7, "%s", v.second); - } - - m_rsx_callback = 0; - m_cpu_thr_stop = 0; - - // TODO: check finalization order - - SavePoints(fs::get_config_dir() + BreakPointsDBName); - m_break_points.clear(); - m_marked_points.clear(); - - GetVFS().UnMountAll(); - - GetGSManager().Close(); - GetAudioManager().Close(); - GetEventManager().Clear(); - GetCPU().Close(); - GetPadManager().Close(); - GetKeyboardManager().Close(); - GetMouseManager().Close(); GetCallbackManager().Clear(); - GetModuleManager().Close(); RSXIOMem.Clear(); vm::close(); SendDbgCommand(DID_STOPPED_EMU); -} -void Emulator::SavePoints(const std::string& path) -{ - const u32 break_count = size32(m_break_points); - const u32 marked_count = size32(m_marked_points); - - fs::file(path, fom::rewrite) - .write(bpdb_version) - .write(break_count) - .write(marked_count) - .write(m_break_points) - .write(m_marked_points); -} - -bool Emulator::LoadPoints(const std::string& path) -{ - if (fs::file f{ path }) + if (g_cfg_autoexit) { - u16 version; - u32 break_count; - u32 marked_count; - - if (!f.read(version) || !f.read(break_count) || !f.read(marked_count)) - { - LOG_ERROR(LOADER, "BP file '%s' is broken (length=0x%llx)", path, f.size()); - return false; - } - - if (version != bpdb_version) - { - LOG_ERROR(LOADER, "BP file '%s' has unsupported version (version=0x%x)", path, version); - return false; - } - - m_break_points.resize(break_count); - m_marked_points.resize(marked_count); - - if (!f.read(m_break_points) || !f.read(m_marked_points)) - { - LOG_ERROR(LOADER, "'BP file %s' is broken (length=0x%llx, break_count=%u, marked_count=%u)", path, f.size(), break_count, marked_count); - return false; - } - - return true; + GetCallbacks().exit(); + } + else + { + Init(); } - - return false; } Emulator Emu; + +DECLARE(idm::g_map); +DECLARE(idm::g_id); +DECLARE(idm::g_mutex); + +DECLARE(fxm::g_map); +DECLARE(fxm::g_mutex); + +#ifndef _MSC_VER +constexpr std::pair bijective::map[]; +constexpr std::pair<_log::level, const char*> bijective<_log::level, const char*>::map[]; +constexpr std::pair bijective::map[]; +#endif diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index 2f731afe3b..ce13e581b8 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -1,7 +1,8 @@ #pragma once -#include "Loader/Loader.h" +#include "VFS.h" #include "DbgCommand.h" +#include "Loader/PSF.h" enum class frame_type; @@ -9,11 +10,12 @@ struct EmuCallbacks { std::function)> call_after; std::function process_events; - std::function send_dbg_command; - std::function()> get_kb_handler; - std::function()> get_mouse_handler; - std::function()> get_pad_handler; - std::function(frame_type)> get_gs_frame; + std::function exit; + std::function send_dbg_command; + std::function()> get_kb_handler; + std::function()> get_mouse_handler; + std::function()> get_pad_handler; + std::function(frame_type, size2i)> get_gs_frame; std::function()> get_gs_render; std::function()> get_audio; std::function()> get_msg_dialog; @@ -31,17 +33,7 @@ enum Status : u32 // Emulation Stopped exception event class EmulationStopped {}; -class CPUThreadManager; -class PadManager; -class KeyboardManager; -class MouseManager; -class GSManager; -class AudioManager; class CallbackManager; -class CPUThread; -class EventManager; -class ModuleManager; -struct VFS; struct EmuInfo { @@ -64,47 +56,24 @@ public: class Emulator final { + atomic_t m_status; + EmuCallbacks m_cb; - enum Mode - { - DisAsm, - InterpreterDisAsm, - Interpreter, - }; - - volatile u32 m_status; - uint m_mode; + atomic_t m_pause_start_time; // set when paused + atomic_t m_pause_amend_time; // increased when resumed - std::atomic m_pause_start_time; // set when paused - std::atomic m_pause_amend_time; // increased when resumed - - u32 m_rsx_callback; u32 m_cpu_thr_stop; - std::vector m_break_points; - std::vector m_marked_points; - - std::mutex m_core_mutex; - - std::unique_ptr m_thread_manager; - std::unique_ptr m_pad_manager; - std::unique_ptr m_keyboard_manager; - std::unique_ptr m_mouse_manager; - std::unique_ptr m_gs_manager; - std::unique_ptr m_audio_manager; std::unique_ptr m_callback_manager; - std::unique_ptr m_event_manager; - std::unique_ptr m_module_manager; - std::unique_ptr m_vfs; EmuInfo m_info; - loader::loader m_loader; std::string m_path; std::string m_elf_path; std::string m_title_id; std::string m_title; + psf::registry m_psf; public: Emulator(); @@ -119,36 +88,15 @@ public: return m_cb; } - void SendDbgCommand(DbgCommand cmd, class CPUThread* thread = nullptr) + void SendDbgCommand(DbgCommand cmd, class cpu_thread* thread = nullptr) { if (m_cb.send_dbg_command) m_cb.send_dbg_command(cmd, thread); } - // Returns a future object associated with the result of the function called from the GUI thread - template - std::future CallAfter(F&& func) const + // Call from the GUI thread + void CallAfter(std::function&& func) const { - // Make "shared" promise to workaround std::function limitation - auto spr = std::make_shared>(); - - // Get future - std::future future = spr->get_future(); - - // Run asynchronously in GUI thread - m_cb.call_after([spr = std::move(spr), task = std::forward(func)]() - { - try - { - task(); - spr->set_value(); - } - catch (...) - { - spr->set_exception(std::current_exception()); - } - }); - - return future; + return m_cb.call_after(std::move(func)); } /** Set emulator mode to running unconditionnaly. @@ -160,10 +108,7 @@ public: } void Init(); - void SetPath(const std::string& path, const std::string& elf_path = ""); - void SetTitleID(const std::string& id); - void SetTitle(const std::string& title); - void CreateConfig(const std::string& name); + void SetPath(const std::string& path, const std::string& elf_path = {}); const std::string& GetPath() const { @@ -180,24 +125,20 @@ public: return m_title; } + const psf::registry& GetPSF() const + { + return m_psf; + } + u64 GetPauseTime() { return m_pause_amend_time; } - std::mutex& GetCoreMutex() { return m_core_mutex; } - CPUThreadManager& GetCPU() { return *m_thread_manager; } - PadManager& GetPadManager() { return *m_pad_manager; } - KeyboardManager& GetKeyboardManager() { return *m_keyboard_manager; } - MouseManager& GetMouseManager() { return *m_mouse_manager; } - GSManager& GetGSManager() { return *m_gs_manager; } - AudioManager& GetAudioManager() { return *m_audio_manager; } - CallbackManager& GetCallbackManager() { return *m_callback_manager; } - VFS& GetVFS() { return *m_vfs; } - std::vector& GetBreakPoints() { return m_break_points; } - std::vector& GetMarkedPoints() { return m_marked_points; } - EventManager& GetEventManager() { return *m_event_manager; } - ModuleManager& GetModuleManager() { return *m_module_manager; } + CallbackManager& GetCallbackManager() + { + return *m_callback_manager; + } void ResetInfo() { @@ -219,11 +160,6 @@ public: m_info.m_primary_prio = prio; } - void SetRSXCallback(u32 addr) - { - m_rsx_callback = addr; - } - void SetCPUThreadStop(u32 addr) { m_cpu_thr_stop = addr; @@ -238,7 +174,6 @@ public: u32 GetPrimaryStackSize() { return m_info.m_primary_stacksize; } s32 GetPrimaryPrio() { return m_info.m_primary_prio; } - u32 GetRSXCallback() const { return m_rsx_callback; } u32 GetCPUThreadStop() const { return m_cpu_thr_stop; } bool BootGame(const std::string& path, bool direct = false); @@ -249,9 +184,6 @@ public: void Resume(); void Stop(); - void SavePoints(const std::string& path); - bool LoadPoints(const std::string& path); - force_inline bool IsRunning() const { return m_status == Running; } force_inline bool IsPaused() const { return m_status == Paused; } force_inline bool IsStopped() const { return m_status == Stopped; } @@ -260,14 +192,4 @@ public: extern Emulator Emu; -using lv2_lock_t = std::unique_lock; - -inline bool check_lv2_lock(lv2_lock_t& lv2_lock) -{ - return lv2_lock.owns_lock() && lv2_lock.mutex() == &Emu.GetCoreMutex(); -} - -#define LV2_LOCK lv2_lock_t lv2_lock(Emu.GetCoreMutex()) -#define LV2_DEFER_LOCK lv2_lock_t lv2_lock -#define CHECK_LV2_LOCK(x) if (!check_lv2_lock(x)) throw EXCEPTION("lv2_lock is invalid or not locked") #define CHECK_EMU_STATUS if (Emu.IsStopped()) throw EmulationStopped{} diff --git a/rpcs3/Emu/VFS.cpp b/rpcs3/Emu/VFS.cpp new file mode 100644 index 0000000000..a278da8e45 --- /dev/null +++ b/rpcs3/Emu/VFS.cpp @@ -0,0 +1,77 @@ +#include "stdafx.h" +#include "Utilities/Config.h" +#include "Emu/System.h" + +#include "VFS.h" + +cfg::string_entry g_cfg_vfs_emulator_dir(cfg::root.vfs, "$(EmulatorDir)"); // Default (empty): taken from fs::get_executable_dir() +cfg::string_entry g_cfg_vfs_dev_hdd0(cfg::root.vfs, "/dev_hdd0/", "$(EmulatorDir)dev_hdd0/"); +cfg::string_entry g_cfg_vfs_dev_hdd1(cfg::root.vfs, "/dev_hdd1/", "$(EmulatorDir)dev_hdd1/"); +cfg::string_entry g_cfg_vfs_dev_flash(cfg::root.vfs, "/dev_flash/", "$(EmulatorDir)dev_flash/"); +cfg::string_entry g_cfg_vfs_dev_usb000(cfg::root.vfs, "/dev_usb000/", "$(EmulatorDir)dev_usb000/"); +cfg::string_entry g_cfg_vfs_dev_bdvd(cfg::root.vfs, "/dev_bdvd/"); // Not mounted +cfg::string_entry g_cfg_vfs_app_home(cfg::root.vfs, "/app_home/"); // Not mounted + +cfg::bool_entry g_cfg_vfs_allow_host_root(cfg::root.vfs, "Enable /host_root/", true); + +void vfs::dump() +{ + LOG_NOTICE(LOADER, "Mount info:"); + LOG_NOTICE(LOADER, "/dev_hdd0/ -> %s", g_cfg_vfs_dev_hdd0.get()); + LOG_NOTICE(LOADER, "/dev_hdd1/ -> %s", g_cfg_vfs_dev_hdd1.get()); + LOG_NOTICE(LOADER, "/dev_flash/ -> %s", g_cfg_vfs_dev_flash.get()); + LOG_NOTICE(LOADER, "/dev_usb/ -> %s", g_cfg_vfs_dev_usb000.get()); + LOG_NOTICE(LOADER, "/dev_usb000/ -> %s", g_cfg_vfs_dev_usb000.get()); + if (g_cfg_vfs_dev_bdvd.size()) LOG_NOTICE(LOADER, "/dev_bdvd/ -> %s", g_cfg_vfs_dev_bdvd.get()); + if (g_cfg_vfs_app_home.size()) LOG_NOTICE(LOADER, "/app_home/ -> %s", g_cfg_vfs_app_home.get()); + if (g_cfg_vfs_allow_host_root) LOG_NOTICE(LOADER, "/host_root/ -> ."); + LOG_NOTICE(LOADER, ""); +} + +std::string vfs::get(const std::string& vpath) +{ + const cfg::string_entry* vdir = nullptr; + std::size_t f_pos = vpath.find_first_not_of('/'); + std::size_t start = 0; + + // Compare vpath with device name + auto detect = [&](const auto& vdev) -> bool + { + const std::size_t size = ::size32(vdev) - 1; // Char array size + + if (f_pos && f_pos != -1 && vpath.compare(f_pos - 1, size, vdev, size) == 0) + { + start = size; + return true; + } + + return false; + }; + + if (g_cfg_vfs_allow_host_root && detect("/host_root/")) + return vpath.substr(start); // Accessing host FS directly + else if (detect("/dev_hdd0/")) + vdir = &g_cfg_vfs_dev_hdd0; + else if (detect("/dev_hdd1/")) + vdir = &g_cfg_vfs_dev_hdd1; + else if (detect("/dev_flash/")) + vdir = &g_cfg_vfs_dev_flash; + else if (detect("/dev_usb000/")) + vdir = &g_cfg_vfs_dev_usb000; + else if (detect("/dev_usb/")) + vdir = &g_cfg_vfs_dev_usb000; + else if (detect("/dev_bdvd/")) + vdir = &g_cfg_vfs_dev_bdvd; + else if (detect("/app_home/")) + vdir = &g_cfg_vfs_app_home; + + // Return empty path if not mounted + if (!vdir || !start) + { + LOG_WARNING(GENERAL, "vfs::get() failed for %s", vpath); + return{}; + } + + // Replace $(EmulatorDir), concatenate + return fmt::replace_all(*vdir, "$(EmulatorDir)", g_cfg_vfs_emulator_dir.size() == 0 ? fs::get_executable_dir() : g_cfg_vfs_emulator_dir) + vpath.substr(start); +} diff --git a/rpcs3/Emu/VFS.h b/rpcs3/Emu/VFS.h new file mode 100644 index 0000000000..55c6ceeb57 --- /dev/null +++ b/rpcs3/Emu/VFS.h @@ -0,0 +1,10 @@ +#pragma once + +namespace vfs +{ + // Print mounted directories + void dump(); + + // Convert PS3/PSV path to fs-compatible path + std::string get(const std::string& vpath); +} diff --git a/rpcs3/Emu/events.cpp b/rpcs3/Emu/events.cpp deleted file mode 100644 index 333a065528..0000000000 --- a/rpcs3/Emu/events.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "stdafx.h" -#include "events.h" - -namespace rpcs3 -{ - event oninit; - event onstart; - event onstop; - event onpause; -} diff --git a/rpcs3/Emu/events.h b/rpcs3/Emu/events.h deleted file mode 100644 index e7c0167621..0000000000 --- a/rpcs3/Emu/events.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include - -namespace rpcs3 -{ - extern event oninit; - extern event onstart; - extern event onstop; - extern event onpause; -} diff --git a/rpcs3/Emu/state.cpp b/rpcs3/Emu/state.cpp deleted file mode 100644 index 8239ce699e..0000000000 --- a/rpcs3/Emu/state.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "stdafx.h" -#include "state.h" - -namespace rpcs3 -{ - state_t state; -} diff --git a/rpcs3/Emu/state.h b/rpcs3/Emu/state.h deleted file mode 100644 index fd7db03d03..0000000000 --- a/rpcs3/Emu/state.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include "config.h" - -namespace rpcs3 -{ - struct state_t - { - config_t config; - - std::string path_to_elf; - std::string virtual_path_to_elf; - }; - - extern state_t state; -} diff --git a/rpcs3/PPULLVMRecompiler.vcxproj b/rpcs3/PPULLVMRecompiler.vcxproj deleted file mode 100644 index 89ce2d8f9b..0000000000 --- a/rpcs3/PPULLVMRecompiler.vcxproj +++ /dev/null @@ -1,110 +0,0 @@ - - - - - Debug - LLVM - x64 - - - Debug - MemLeak - x64 - - - Debug - x64 - - - Release - LLVM - x64 - - - Release - x64 - - - - - true - ..\llvm\include;..\llvm_build\include;%(AdditionalIncludeDirectories) - - - - - true - ..\llvm\include;..\llvm_build\include;%(AdditionalIncludeDirectories) - - - - - true - ..\llvm\include;..\llvm_build\include;%(AdditionalIncludeDirectories) - - - - - true - ..\llvm\include;..\llvm_build\include;%(AdditionalIncludeDirectories) - - - - - true - ..\llvm\include;..\llvm_build\include;%(AdditionalIncludeDirectories) - - - - - - - - - - - - {c4a10229-4712-4bd2-b63e-50d93c67a038} - - - - {304A6E8B-A311-4EC5-8045-BFA8D08175CE} - Win32Proj - PPULLVMRecompiler - 8.1 - - - - StaticLibrary - v140 - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/rpcs3/PPULLVMRecompiler.vcxproj.filters b/rpcs3/PPULLVMRecompiler.vcxproj.filters deleted file mode 100644 index 3db3255af1..0000000000 --- a/rpcs3/PPULLVMRecompiler.vcxproj.filters +++ /dev/null @@ -1,22 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - - - Source Files - - - Source Files - - - - - Source Files - - - \ No newline at end of file diff --git a/rpcs3/PPULLVMRecompiler.vcxproj.user b/rpcs3/PPULLVMRecompiler.vcxproj.user deleted file mode 100644 index abe8dd8961..0000000000 --- a/rpcs3/PPULLVMRecompiler.vcxproj.user +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/rpcs3/config.cpp b/rpcs3/config.cpp deleted file mode 100644 index 270ecc8567..0000000000 --- a/rpcs3/config.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "stdafx.h" -#include "config.h" - -namespace rpcs3 -{ - config_t::config_t(const std::string &path_) - { - path(path_); - } - config_t::config_t(const config_t& rhs) - { - assign(rhs); - } - - config_t& config_t::operator =(const config_t& rhs) - { - assign(rhs); - path(rhs.path()); - return *this; - } - - void config_t::path(const std::string &new_path) - { - m_path = new_path; - } - - std::string config_t::path() const - { - return m_path; - } - - void config_t::load() - { - fs::file file(m_path, fom::create | fom::read); - - if (file) - from_string(file.to_string()); - } - - void config_t::save() const - { - fs::file(m_path, fom::rewrite).write(to_string()); - } - - config_t config{ fs::get_config_dir() + "rpcs3.new.ini" }; -} diff --git a/rpcs3/config.h b/rpcs3/config.h deleted file mode 100644 index 6d1ecd87f0..0000000000 --- a/rpcs3/config.h +++ /dev/null @@ -1,1010 +0,0 @@ -#pragma once -#include "Utilities/convert.h" -#include "Utilities/config_context.h" - -enum class audio_output_type -{ - Null, - OpenAL, - XAudio2 -}; - -namespace convert -{ - template<> - struct to_impl_t - { - static std::string func(audio_output_type value) - { - switch (value) - { - case audio_output_type::Null: return "Null"; - case audio_output_type::OpenAL: return "OpenAL"; - case audio_output_type::XAudio2: return "XAudio2"; - } - - return "Unknown"; - } - }; - - template<> - struct to_impl_t - { - static audio_output_type func(const std::string &value) - { - if (value == "Null") - return audio_output_type::Null; - - if (value == "OpenAL") - return audio_output_type::OpenAL; - - if (value == "XAudio2") - return audio_output_type::XAudio2; - - return audio_output_type::Null; - } - }; -} - -enum class rsx_renderer_type -{ - Null, - OpenGL, - Vulkan, - DX12 -}; - -enum class rsx_aspect_ratio -{ - _4x3 = 1, - _16x9 -}; - -enum class rsx_frame_limit -{ - Off, - _50, - _59_94, - _30, - _60, - Auto -}; - -enum class rsx_resolution -{ - _1920x1080 = 1, - _1280x720 = 2, - _720x480 = 4, - _720x576 = 5, - _1600x1080 = 10, - _1440x1080 = 11, - _1280x1080 = 12, - _960x1080 = 13 -}; - -namespace convert -{ - template<> - struct to_impl_t - { - static std::string func(rsx_renderer_type value) - { - switch (value) - { - case rsx_renderer_type::Null: return "Null"; - case rsx_renderer_type::OpenGL: return "OpenGL"; - case rsx_renderer_type::Vulkan: return "Vulkan"; - case rsx_renderer_type::DX12: return "DX12"; - } - - return "Unknown"; - } - }; - - template<> - struct to_impl_t - { - static rsx_renderer_type func(const std::string &value) - { - if (value == "Null") - return rsx_renderer_type::Null; - - if (value == "OpenGL") - return rsx_renderer_type::OpenGL; - - if (value == "Vulkan") - return rsx_renderer_type::Vulkan; - - if (value == "DX12") - return rsx_renderer_type::DX12; - - return rsx_renderer_type::Null; - } - }; - - template<> - struct to_impl_t - { - static std::string func(rsx_aspect_ratio value) - { - switch (value) - { - case rsx_aspect_ratio::_16x9: return "16x9"; - case rsx_aspect_ratio::_4x3: return "4x3"; - } - - return "Unknown"; - } - }; - - template<> - struct to_impl_t - { - static rsx_aspect_ratio func(const std::string &value) - { - if (value == "16x9") - return rsx_aspect_ratio::_16x9; - - if (value == "4x3") - return rsx_aspect_ratio::_4x3; - - return rsx_aspect_ratio::_16x9; - } - }; - - template<> - struct to_impl_t - { - static std::string func(rsx_frame_limit value) - { - switch (value) - { - case rsx_frame_limit::Off: return "Off"; - case rsx_frame_limit::_50: return "50"; - case rsx_frame_limit::_59_94: return "59.94"; - case rsx_frame_limit::_30: return "30"; - case rsx_frame_limit::_60: return "60"; - case rsx_frame_limit::Auto: return "Auto"; - } - - return "Unknown"; - } - }; - - template<> - struct to_impl_t - { - static rsx_frame_limit func(const std::string &value) - { - if (value == "Off") - return rsx_frame_limit::Off; - - if (value == "50") - return rsx_frame_limit::_50; - - if (value == "59.94") - return rsx_frame_limit::_59_94; - - if (value == "30") - return rsx_frame_limit::_30; - - if (value == "60") - return rsx_frame_limit::_60; - - if (value == "Auto") - return rsx_frame_limit::Auto; - - return rsx_frame_limit::Off; - } - }; - - template<> - struct to_impl_t - { - static std::string func(rsx_resolution value) - { - switch (value) - { - case rsx_resolution::_1920x1080: return "1920x1080"; - case rsx_resolution::_1280x720: return "1280x720"; - case rsx_resolution::_720x480: return "720x480"; - case rsx_resolution::_720x576: return "720x576"; - case rsx_resolution::_1600x1080: return "1600x1080"; - case rsx_resolution::_1440x1080: return "1440x1080"; - case rsx_resolution::_1280x1080: return "1280x1080"; - case rsx_resolution::_960x1080: return "960x1080"; - } - - return "Unknown"; - } - }; - - template<> - struct to_impl_t - { - static rsx_resolution func(const std::string &value) - { - if (value == "1920x1080") - return rsx_resolution::_1920x1080; - - if (value == "1280x720") - return rsx_resolution::_1280x720; - - if (value == "720x480") - return rsx_resolution::_720x480; - - if (value == "720x576") - return rsx_resolution::_720x576; - - if (value == "1600x1080") - return rsx_resolution::_1600x1080; - - if (value == "1440x1080") - return rsx_resolution::_1440x1080; - - if (value == "1280x1080") - return rsx_resolution::_1280x1080; - - if (value == "960x1080") - return rsx_resolution::_960x1080; - - return rsx_resolution::_720x480; - } - }; -} - -enum class ppu_decoder_type -{ - interpreter, - interpreter2, - recompiler_llvm -}; - -namespace convert -{ - template<> - struct to_impl_t - { - static std::string func(ppu_decoder_type value) - { - switch (value) - { - case ppu_decoder_type::interpreter: return "interpreter"; - case ppu_decoder_type::interpreter2: return "interpreter2"; - case ppu_decoder_type::recompiler_llvm: return "recompiler_llvm"; - } - - return "Unknown"; - } - }; - - template<> - struct to_impl_t - { - static ppu_decoder_type func(const std::string &value) - { - if (value == "interpreter") - return ppu_decoder_type::interpreter; - - if (value == "interpreter2") - return ppu_decoder_type::interpreter2; - - if (value == "recompiler_llvm") - return ppu_decoder_type::recompiler_llvm; - - return ppu_decoder_type::interpreter; - } - }; -} - -enum class spu_decoder_type -{ - interpreter_precise, - interpreter_fast, - recompiler_asmjit -}; - -namespace convert -{ - template<> - struct to_impl_t - { - static std::string func(spu_decoder_type value) - { - switch (value) - { - case spu_decoder_type::interpreter_precise: return "interpreter_precise"; - case spu_decoder_type::interpreter_fast: return "interpreter_fast"; - case spu_decoder_type::recompiler_asmjit: return "recompiler_asmjit"; - } - - return "Unknown"; - } - }; - - template<> - struct to_impl_t - { - static spu_decoder_type func(const std::string &value) - { - if (value == "interpreter_precise") - return spu_decoder_type::interpreter_precise; - - if (value == "interpreter_fast") - return spu_decoder_type::interpreter_fast; - - if (value == "recompiler_asmjit") - return spu_decoder_type::recompiler_asmjit; - - return spu_decoder_type::interpreter_precise; - } - }; -} - -enum class io_camera_state -{ - null, - connected -}; - -enum class io_camera_type -{ - unknown, - eye_toy, - play_station_eye, - usb_video_class_1_1 -}; - -enum class io_handler_mode -{ - null, - windows, - xinput -}; - -namespace convert -{ - template<> - struct to_impl_t - { - static std::string func(io_camera_state value) - { - switch (value) - { - case io_camera_state::null: return "null"; - case io_camera_state::connected: return "connected"; - } - - return "Unknown"; - } - }; - - template<> - struct to_impl_t - { - static io_camera_state func(const std::string &value) - { - if (value == "null") - return io_camera_state::null; - - if (value == "connected") - return io_camera_state::connected; - - return io_camera_state::null; - } - }; - - template<> - struct to_impl_t - { - static std::string func(io_camera_type value) - { - switch (value) - { - case io_camera_type::unknown: return "Unknown"; - case io_camera_type::eye_toy: return "EyeToy"; - case io_camera_type::play_station_eye: return "PlayStationEye"; - case io_camera_type::usb_video_class_1_1: return "UsbVideoClass1.1"; - } - return "Unknown"; - } - }; - - template<> - struct to_impl_t - { - static io_camera_type func(const std::string &value) - { - if (value == "Unknown") - return io_camera_type::unknown; - - if (value == "EyeToy") - return io_camera_type::eye_toy; - - if (value == "PlayStationEye") - return io_camera_type::play_station_eye; - - if (value == "UsbVideoClass1.1") - return io_camera_type::usb_video_class_1_1; - - return io_camera_type::unknown; - } - }; - - template<> - struct to_impl_t - { - static std::string func(io_handler_mode value) - { - switch (value) - { - case io_handler_mode::null: return "null"; - case io_handler_mode::windows: return "windows"; - case io_handler_mode::xinput: return "xinput"; - } - return "Unknown"; - } - }; - - template<> - struct to_impl_t - { - static io_handler_mode func(const std::string &value) - { - if (value == "null") - return io_handler_mode::null; - - if (value == "windows") - return io_handler_mode::windows; - - if (value == "xinput") - return io_handler_mode::xinput; - - return io_handler_mode::null; - } - }; -} - -enum class misc_net_status -{ - ip_obtained, - obtaining_ip, - connecting, - disconnected -}; - -namespace convert -{ - template<> - struct to_impl_t - { - static std::string func(_log::level value) - { - switch (value) - { - case _log::level::trace: return "All"; - case _log::level::warning: return "Warning"; - case _log::level::success: return "Success"; - case _log::level::error: return "Error"; - case _log::level::always: return "Nothing"; - case _log::level::fatal: return "Fatal"; - case _log::level::todo: return "TODO"; - case _log::level::notice: return "Notice"; - } - - return fmt::format("Unknown:0x%x", value); - } - }; - - template<> - struct to_impl_t<_log::level, std::string> - { - static _log::level func(const std::string &value) - { - if (value == "All") - return _log::level::trace; - - if (value == "Warning") - return _log::level::warning; - - if (value == "Success") - return _log::level::success; - - if (value == "Error") - return _log::level::error; - - if (value == "Nothing") - return _log::level::always; - - if (value == "Fatal") - return _log::level::fatal; - - if (value == "TODO") - return _log::level::todo; - - if (value == "Notice") - return _log::level::notice; - - return _log::level::success; - } - }; - - template<> - struct to_impl_t - { - static std::string func(misc_net_status value) - { - switch (value) - { - case misc_net_status::ip_obtained: return "IPObtained"; - case misc_net_status::obtaining_ip: return "ObtainingIP"; - case misc_net_status::connecting: return "Connecting"; - case misc_net_status::disconnected: return "Disconnected"; - } - - return "Unknown"; - } - }; - - template<> - struct to_impl_t - { - static misc_net_status func(const std::string &value) - { - if (value == "IPObtained") - return misc_net_status::ip_obtained; - - if (value == "ObtainingIP") - return misc_net_status::obtaining_ip; - - if (value == "Connecting") - return misc_net_status::connecting; - - if (value == "Disconnected") - return misc_net_status::disconnected; - - return misc_net_status::connecting; - } - }; -} - - -namespace rpcs3 -{ - class config_t : public config_context_t - { - std::string m_path; - - public: - struct gui_group : protected group - { - gui_group(config_context_t *cfg) : group{ cfg, "gui" } {} - - entry size{ this, "size",{ 900, 600 } }; - entry position{ this, "position",{ -1, -1 } }; - entry aui_mgr_perspective{ this, "main_frame_aui", "" }; - - } gui{ this }; - - struct core_group : protected group - { - core_group(config_context_t *cfg) : group{ cfg, "core" } {} - - struct llvm_group : protected group - { - llvm_group(group *grp) : group{ grp, "llvm" } {} - - entry exclusion_range { this, "Compiled blocks exclusion", false }; - entry min_id { this, "Excluded block range min", 200 }; - entry max_id { this, "Excluded block range max", 250 }; - entry threshold { this, "Compilation threshold", 1000 }; - -#define MACRO_PPU_INST_MAIN_EXPANDERS(MACRO) \ - /*MACRO(HACK)*/ \ - /*MACRO(TDI)*/ \ - MACRO(TWI) \ - MACRO(MULLI) \ - MACRO(SUBFIC) \ - MACRO(CMPLI) \ - MACRO(CMPI) \ - MACRO(ADDIC) \ - MACRO(ADDIC_) \ - MACRO(ADDI) \ - MACRO(ADDIS) \ - /*MACRO(BC)*/ \ - /*MACRO(SC)*/ \ - /*MACRO(B)*/ \ - MACRO(RLWIMI) \ - MACRO(RLWINM) \ - MACRO(RLWNM) \ - MACRO(ORI) \ - MACRO(ORIS) \ - MACRO(XORI) \ - MACRO(XORIS) \ - MACRO(ANDI_) \ - MACRO(ANDIS_) \ - MACRO(LWZ) \ - /*MACRO(LWZU)*/ \ - MACRO(LBZ) \ - /*MACRO(LBZU)*/ \ - MACRO(STW) \ - /*MACRO(STWU)*/ \ - /*MACRO(STB)*/ \ - /*MACRO(STBU)*/ \ - MACRO(LHZ) \ - /*MACRO(LHZU)*/ \ - /*MACRO(LHA)*/ \ - /*MACRO(LHAU)*/ \ - /*MACRO(STH)*/ \ - /*MACRO(STHU)*/ \ - /*MACRO(LMW)*/ \ - /*MACRO(STMW)*/ \ - MACRO(LFS) \ - /*MACRO(LFSU)*/ \ - /*MACRO(LFD)*/ \ - /*MACRO(LFDU)*/ \ - MACRO(STFS) \ - /*MACRO(STFSU)*/ \ - /*MACRO(STFD)*/ \ - /*MACRO(STFDU)*/ \ - /*MACRO(LFQ)*/ \ - /*MACRO(LFQU)*/ - -#define MACRO_PPU_INST_G_13_EXPANDERS(MACRO) \ - MACRO(MCRF) \ - /*MACRO(BCLR)*/ \ - MACRO(CRNOR) \ - MACRO(CRANDC) \ - /*MACRO(ISYNC)*/ \ - MACRO(CRXOR) \ - MACRO(CRNAND) \ - MACRO(CRAND) \ - MACRO(CREQV) \ - MACRO(CRORC) \ - MACRO(CROR) \ - /*MACRO(BCCTR)*/ - -#define MACRO_PPU_INST_G_1E_EXPANDERS(MACRO) \ - MACRO(RLDICL) \ - MACRO(RLDICR) \ - MACRO(RLDIC) \ - MACRO(RLDIMI) \ - MACRO(RLDC_LR) - -#define MACRO_PPU_INST_G_1F_EXPANDERS(MACRO) \ - MACRO(CMP) \ - /*MACRO(TW)*/ \ - /*MACRO(LVSL)*/ \ - /*MACRO(LVEBX)*/ \ - /*MACRO(SUBFC)*/ \ - /*MACRO(MULHDU)*/ \ - /*MACRO(ADDC)*/ \ - /*MACRO(MULHWU)*/ \ - MACRO(MFOCRF) \ - MACRO(LWARX) \ - /*MACRO(LDX)*/ \ - /*MACRO(LWZX)*/ \ - /*MACRO(CNTLZW)*/ \ - /*MACRO(SLD)*/ \ - MACRO(AND) \ - MACRO(CMPL) \ - /*MACRO(LVSR)*/ \ - /*MACRO(LVEHX)*/ \ - MACRO(SUBF) \ - /*MACRO(LDUX)*/ \ - /*MACRO(DCBST)*/ \ - /*MACRO(LWZUX)*/ \ - /*MACRO(CNTLZD)*/ \ - /*MACRO(ANDC)*/ \ - /*MACRO(TD)*/ \ - /*MACRO(LVEWX)*/ \ - /*MACRO(MULHD) \ - MACRO(MULHW) \ - MACRO(LDARX) \ - MACRO(DCBF) \ - MACRO(LBZX) \ - MACRO(LVX)*/ \ - MACRO(NEG) \ - /*MACRO(LBZUX) \ - MACRO(NOR) \ - MACRO(STVEBX) \ - MACRO(SUBFE) \ - MACRO(ADDE)*/ \ - MACRO(MTOCRF) \ - /*MACRO(STDX)*/ \ - MACRO(STWCX_) \ - /*MACRO(STWX) \ - MACRO(STVEHX) \ - MACRO(STDUX) \ - MACRO(STWUX) \ - MACRO(STVEWX) \ - MACRO(SUBFZE) \ - MACRO(ADDZE) \ - MACRO(STDCX_) \ - MACRO(STBX) \ - MACRO(STVX) \ - MACRO(SUBFME) \ - MACRO(MULLD) \ - MACRO(ADDME)*/ \ - MACRO(MULLW) \ - /*MACRO(DCBTST) \ - MACRO(STBUX) \ - MACRO(DOZ)*/ \ - MACRO(ADD) \ - /*MACRO(DCBT) \ - MACRO(LHZX) \ - MACRO(EQV) \ - MACRO(ECIWX) \ - MACRO(LHZUX) \ - MACRO(XOR)*/ \ - /*MACRO(MFSPR)*/ \ - /*MACRO(LWAX) \ - MACRO(DST) \ - MACRO(LHAX) \ - MACRO(LVXL) \ - MACRO(MFTB) \ - MACRO(LWAUX) \ - MACRO(DSTST) \ - MACRO(LHAUX) \ - MACRO(STHX) \ - MACRO(ORC) \ - MACRO(ECOWX) \ - MACRO(STHUX)*/ \ - MACRO(OR) \ - /*MACRO(DIVDU)*/ \ - MACRO(DIVWU) \ - /*MACRO(MTSPR)*/ \ - /*MACRO(DCBI) \ - MACRO(NAND) \ - MACRO(STVXL) \ - MACRO(DIVD)*/ \ - MACRO(DIVW) \ - /*MACRO(LVLX) \ - MACRO(SUBFCO) \ - MACRO(ADDCO) \ - MACRO(LDBRX) \ - MACRO(LSWX) \ - MACRO(SRW) \ - MACRO(SRD) \ - MACRO(LVRX) \ - MACRO(SUBFO) \ - MACRO(LFSUX) \ - MACRO(LSWI) \ - MACRO(SYNC) \ - MACRO(LFDX) \ - MACRO(NEGO) \ - MACRO(LFDUX) \ - MACRO(STVLX) \ - MACRO(SUBFEO) \ - MACRO(ADDEO) \ - MACRO(STDBRX) \ - MACRO(STSWX) \ - MACRO(STWBRX) \ - MACRO(STFSX) \ - MACRO(STVRX) \ - MACRO(STFSUX) \ - MACRO(SUBFZEO) \ - MACRO(ADDZEO) \ - MACRO(STSWI) \ - MACRO(STFDX) \ - MACRO(SUBFMEO) \ - MACRO(MULLDO) \ - MACRO(ADDMEO) \ - MACRO(MULLWO) \ - MACRO(STFDUX) \ - MACRO(LVLXL) \ - MACRO(ADDO) \ - MACRO(LHBRX) \ - MACRO(SRAW) \ - MACRO(SRAD) \ - MACRO(LVRXL) \ - MACRO(DSS)*/ \ - MACRO(SRAWI) \ - /*MACRO(SRADI1) \ - MACRO(SRADI2) \ - MACRO(EIEIO) \ - MACRO(STVLXL) \ - MACRO(STHBRX) \ - MACRO(EXTSH) \ - MACRO(STVRXL)*/ \ - MACRO(EXTSB) \ - /*MACRO(DIVDUO) \ - MACRO(DIVWUO) \ - MACRO(STFIWX)*/ \ - MACRO(EXTSW) \ - /*MACRO(ICBI) \ - MACRO(DIVDO) \ - MACRO(DIVWO) \ - MACRO(DCBZ)*/ - -#define MACRO_PPU_INST_G_3A_EXPANDERS(MACRO) \ - MACRO(LD) \ - /*MACRO(LDU)*/ \ - /*MACRO(LWA)*/ - -#define MACRO_PPU_INST_G_3E_EXPANDERS(MACRO) \ - MACRO(STD) \ - MACRO(STDU) - - - - -#define INSTRUCTION_ENTRY(inst) \ - entry enable_##inst { this, "Enable instruction " #inst, true}; - - MACRO_PPU_INST_MAIN_EXPANDERS(INSTRUCTION_ENTRY) - MACRO_PPU_INST_G_13_EXPANDERS(INSTRUCTION_ENTRY) - MACRO_PPU_INST_G_1E_EXPANDERS(INSTRUCTION_ENTRY) - MACRO_PPU_INST_G_1F_EXPANDERS(INSTRUCTION_ENTRY) - MACRO_PPU_INST_G_3A_EXPANDERS(INSTRUCTION_ENTRY) - MACRO_PPU_INST_G_3E_EXPANDERS(INSTRUCTION_ENTRY) - - } llvm{ this }; - - entry ppu_decoder { this, "PPU Decoder", ppu_decoder_type::interpreter }; - entry spu_decoder { this, "SPU Decoder", spu_decoder_type::interpreter_precise }; - entry hook_st_func { this, "Hook static functions", false }; - entry load_liblv2 { this, "Load liblv2.sprx", false }; - - } core{ this }; - - struct rsx_group : protected group - { - struct opengl_group : protected group - { - opengl_group(group *grp) : group{ grp, "opengl" } {} - - entry write_color_buffers { this, "Write Color Buffers", false }; - entry write_depth_buffer { this, "Write Depth Buffer", false }; - entry read_color_buffers { this, "Read Color Buffers", false }; - entry read_depth_buffer { this, "Read Depth Buffer", false }; - } opengl{ this }; - - struct d3d12_group : protected group - { - d3d12_group(group *grp) : group{ grp, "d3d12" } {} - - entry adaptater { this, "D3D Adaptater", 1 }; - entry debug_output { this, "Debug Output", false }; - entry overlay { this, "Debug overlay", false }; - } d3d12{ this }; - - rsx_group(config_context_t *cfg) : group{ cfg, "rsx" } {} - - entry renderer { this, "Renderer", rsx_renderer_type::OpenGL }; - entry resolution { this, "Resolution", rsx_resolution::_720x480 }; - entry aspect_ratio{ this, "Aspect ratio", rsx_aspect_ratio::_16x9 }; - entry frame_limit { this, "Frame limit", rsx_frame_limit::Off }; - entry log_programs { this, "Log shader programs", false }; - entry vsync { this, "VSync", false }; - entry _3dtv { this, "3D Monitor", false }; - - } rsx{ this }; - - struct audio_group : protected group - { - audio_group(config_context_t *cfg) : group{ cfg, "audio" } {} - - entry out{ this, "Audio Out", audio_output_type::OpenAL }; - entry dump_to_file { this, "Dump to file", false }; - entry convert_to_u16 { this, "Convert to 16 bit", false }; - } audio{ this }; - - struct io_group : protected group - { - io_group(config_context_t *cfg) : group{ cfg, "io" } {} - - entry camera { this, "Camera", io_camera_state::connected }; - entry camera_type { this, "Camera type", io_camera_type::play_station_eye }; - entry pad_handler_mode { this, "Pad Handler", io_handler_mode::windows }; - entry keyboard_handler_mode{ this, "Keyboard Handler", io_handler_mode::null }; - entry mouse_handler_mode { this, "Mouse Handler", io_handler_mode::null }; - - struct pad_group : protected group - { - pad_group(group *grp) : group{ grp, "pad" } {} - - entry left_stick_left { this, "Left Analog Stick Left", 314 }; - entry left_stick_down { this, "Left Analog Stick Down", 317 }; - entry left_stick_right { this, "Left Analog Stick Right", 316 }; - entry left_stick_up { this, "Left Analog Stick Up", 315 }; - entry right_stick_left { this, "Right Analog Stick Left", 313 }; - entry right_stick_down { this, "Right Analog Stick Down", 367 }; - entry right_stick_right{ this, "Right Analog Stick Right", 312 }; - entry right_stick_up { this, "Right Analog Stick Up", 366 }; - entry start { this, "Start", 13 }; - entry select { this, "Select", 32 }; - entry square { this, "Square", static_cast('J') }; - entry cross { this, "Cross", static_cast('K') }; - entry circle { this, "Circle", static_cast('L') }; - entry triangle { this, "Triangle", static_cast('I') }; - entry left { this, "Left", static_cast('A') }; - entry down { this, "Down", static_cast('S') }; - entry right { this, "Right", static_cast('D') }; - entry up { this, "Up", static_cast('W') }; - entry r1 { this, "R1", static_cast('3') }; - entry r2 { this, "R2", static_cast('E') }; - entry r3 { this, "R3", static_cast('C') }; - entry l1 { this, "L1", static_cast('1') }; - entry l2 { this, "L2", static_cast('Q') }; - entry l3 { this, "L3", static_cast('Z') }; - } pad{ this }; - - } io{ this }; - - struct misc_group : protected group - { - misc_group(config_context_t *cfg) : group{ cfg, "misc" } {} - - struct log_group : protected group - { - log_group(group *grp) : group{ grp, "log" } {} - - entry<_log::level> level { this, "Log Level", _log::level::success }; - entry rsx_logging { this, "RSX Logging", false }; - } log{ this }; - - struct net_group : protected group - { - net_group(group *grp) : group{ grp, "net" } {} - - entry status{ this, "Connection status", misc_net_status::ip_obtained }; - entry _interface { this, "Network adapter", 0 }; - } net{ this }; - - struct debug_group : protected group - { - debug_group(group *grp) : group{ grp, "debug" } {} - - entry auto_pause_syscall { this, "Auto Pause at System Call", false }; - entry auto_pause_func_call { this, "Auto Pause at Function Call", false }; - } debug{ this }; - - entry exit_on_stop { this, "Exit RPCS3 when process finishes", false }; - entry always_start { this, "Always start after boot", true }; - entry use_default_ini { this, "Use default configuration", true }; - } misc{ this }; - - struct system_group : protected group - { - system_group(config_context_t *cfg) : group{ cfg, "system" } {} - - entry language { this, "Language", 1 }; - entry emulation_dir_path{ this, "Emulation dir path", "" }; - entry emulation_dir_path_enable{ this, "Use path below as EmulationDir", false }; - } system{ this }; - - struct vfs_group : public group - { - vfs_group(config_context_t *cfg) : group{ cfg, "vfs" } {} - entry count{ this, "count", 0 }; - entry hdd_count{ this, "hdd_count", 0 }; - } vfs{ this }; - - struct lle_group : public group - { - lle_group(config_context_t *cfg) : group{ cfg, "lle" } {} - } lle{ this }; - - struct gw_group : public group - { - gw_group(config_context_t *cfg) : group{ cfg, "game_viewer" } {} - } game_viewer{ this }; - - config_t() = default; - config_t(const std::string &path); - config_t(const config_t& rhs); - config_t(config_t&& rhs) = delete; - - config_t& operator =(const config_t& rhs); - config_t& operator =(config_t&& rhs) = delete; - - void path(const std::string &new_path); - std::string path() const; - - void load(); - void save() const; - }; - - extern config_t config; -} diff --git a/rpcs3/rpcs3.cpp b/rpcs3/rpcs3.cpp index 4ced904402..9342ae6163 100644 --- a/rpcs3/rpcs3.cpp +++ b/rpcs3/rpcs3.cpp @@ -1,25 +1,24 @@ #include "stdafx.h" #include "stdafx_gui.h" +#include "rpcs3.h" + +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/state.h" -#include "rpcs3.h" + #include "Gui/ConLogFrame.h" #include "Emu/GameInfo.h" -#include "Emu/Io/Keyboard.h" #include "Emu/Io/Null/NullKeyboardHandler.h" -#include "Emu/Io/Windows/WindowsKeyboardHandler.h" +#include "BasicKeyboardHandler.h" -#include "Emu/Io/Mouse.h" #include "Emu/Io/Null/NullMouseHandler.h" -#include "Emu/Io/Windows/WindowsMouseHandler.h" +#include "BasicMouseHandler.h" -#include "Emu/Io/Pad.h" #include "Emu/Io/Null/NullPadHandler.h" -#include "Emu/Io/Windows/WindowsPadHandler.h" +#include "KeyboardPadHandler.h" #ifdef _MSC_VER -#include "Emu/Io/XInput/XInputPadHandler.h" +#include "XInputPadHandler.h" #endif #include "Emu/RSX/Null/NullGSRender.h" @@ -48,11 +47,72 @@ #include #endif +// GUI config +YAML::Node g_gui_cfg; + +// GUI config file +static fs::file s_gui_cfg; + +void save_gui_cfg() +{ + YAML::Emitter out; + out.SetSeqFormat(YAML::Flow); + out << g_gui_cfg; + + // Save to file + s_gui_cfg.seek(0); + s_gui_cfg.trunc(0); + s_gui_cfg.write(out.c_str(), out.size()); +} + wxDEFINE_EVENT(wxEVT_DBG_COMMAND, wxCommandEvent); IMPLEMENT_APP(Rpcs3App) Rpcs3App* TheApp; +cfg::map_entry()>> g_cfg_kb_handler(cfg::root.io, "Keyboard", +{ + { "Null", PURE_EXPR(std::make_shared()) }, + { "Basic", PURE_EXPR(std::make_shared()) }, +}); + +cfg::map_entry()>> g_cfg_mouse_handler(cfg::root.io, "Mouse", +{ + { "Null", PURE_EXPR(std::make_shared()) }, + { "Basic", PURE_EXPR(std::make_shared()) }, +}); + +cfg::map_entry()>> g_cfg_pad_handler(cfg::root.io, "Pad", "Keyboard", +{ + { "Null", PURE_EXPR(std::make_shared()) }, + { "Keyboard", PURE_EXPR(std::make_shared()) }, +#ifdef _MSC_VER + { "XInput", PURE_EXPR(std::make_shared()) }, +#endif +}); + +cfg::map_entry()>> g_cfg_gs_render(cfg::root.video, "Renderer", "OpenGL", +{ + { "Null", PURE_EXPR(std::make_shared()) }, + { "OpenGL", PURE_EXPR(std::make_shared()) }, +#ifdef _MSC_VER + { "DX12", PURE_EXPR(std::make_shared()) }, + { "Vulkan", PURE_EXPR(std::make_shared()) }, +#endif +}); + +cfg::map_entry()>> g_cfg_audio_render(cfg::root.audio, "Renderer", "OpenAL", +{ + { "Null", PURE_EXPR(std::make_shared()) }, + { "OpenAL", PURE_EXPR(std::make_shared()) }, +#ifdef _MSC_VER + { "XAudio2", PURE_EXPR(std::make_shared()) }, +#endif +}); + +extern cfg::bool_entry g_cfg_autostart; +extern cfg::bool_entry g_cfg_autoexit; + bool Rpcs3App::OnInit() { static const wxCmdLineEntryDesc desc[] @@ -72,6 +132,9 @@ bool Rpcs3App::OnInit() this->Exit(); } + s_gui_cfg.open(fs::get_config_dir() + "/config_gui.yml", fs::read + fs::write + fs::create); + g_gui_cfg = YAML::Load(s_gui_cfg.to_string()); + EmuCallbacks callbacks; callbacks.call_after = [](std::function func) @@ -85,83 +148,38 @@ bool Rpcs3App::OnInit() wxGetApp().ProcessPendingEvents(); }; - callbacks.send_dbg_command = [](DbgCommand id, CPUThread* t) + callbacks.exit = [this]() + { + wxGetApp().Exit(); + }; + + callbacks.send_dbg_command = [](DbgCommand id, cpu_thread* t) { wxGetApp().SendDbgCommand(id, t); }; - callbacks.get_kb_handler = []() -> std::unique_ptr - { - switch (auto mode = rpcs3::config.io.keyboard_handler_mode.value()) - { - case io_handler_mode::null: return std::make_unique(); - case io_handler_mode::windows: return std::make_unique(); - default: throw EXCEPTION("Invalid Keyboard Handler Mode %d", +(u32)mode); - } - }; + callbacks.get_kb_handler = PURE_EXPR(g_cfg_kb_handler.get()()); - callbacks.get_mouse_handler = []() -> std::unique_ptr - { - switch (auto mode = rpcs3::config.io.mouse_handler_mode.value()) - { - case io_handler_mode::null: return std::make_unique(); - case io_handler_mode::windows: return std::make_unique(); - default: throw EXCEPTION("Invalid Mouse Handler Mode %d", +(u32)mode); - } - }; + callbacks.get_mouse_handler = PURE_EXPR(g_cfg_mouse_handler.get()()); - callbacks.get_pad_handler = []() -> std::unique_ptr - { - switch (auto mode = rpcs3::config.io.pad_handler_mode.value()) - { - case io_handler_mode::null: return std::make_unique(); - case io_handler_mode::windows: return std::make_unique(); -#ifdef _MSC_VER - case io_handler_mode::xinput: return std::make_unique(); -#endif - default: throw EXCEPTION("Invalid Pad Handler Mode %d", (int)mode); - } - }; + callbacks.get_pad_handler = PURE_EXPR(g_cfg_pad_handler.get()()); - callbacks.get_gs_frame = [](frame_type type) -> std::unique_ptr + callbacks.get_gs_frame = [](frame_type type, size2i size) -> std::unique_ptr { switch (type) { - case frame_type::OpenGL: return std::make_unique(); - case frame_type::DX12: return std::make_unique("DirectX 12"); - case frame_type::Null: return std::make_unique("Null"); - case frame_type::Vulkan: return std::make_unique("Vulkan"); + case frame_type::OpenGL: return std::make_unique(size); + case frame_type::DX12: return std::make_unique("DirectX 12", size); + case frame_type::Null: return std::make_unique("Null", size); + case frame_type::Vulkan: return std::make_unique("Vulkan", size); } - throw EXCEPTION("Invalid Frame Type"); + throw EXCEPTION("Invalid Frame Type (0x%x)", type); }; - callbacks.get_gs_render = []() -> std::shared_ptr - { - switch (auto mode = rpcs3::state.config.rsx.renderer.value()) - { - case rsx_renderer_type::Null: return std::make_shared(); - case rsx_renderer_type::OpenGL: return std::make_shared(); -#ifdef _MSC_VER - case rsx_renderer_type::DX12: return std::make_shared(); - case rsx_renderer_type::Vulkan: return std::make_shared(); -#endif - default: throw EXCEPTION("Invalid GS Renderer %d", (int)mode); - } - }; + callbacks.get_gs_render = PURE_EXPR(g_cfg_gs_render.get()()); - callbacks.get_audio = []() -> std::shared_ptr - { - switch (rpcs3::state.config.audio.out.value()) - { - default: - case audio_output_type::Null: return std::make_shared(); - case audio_output_type::OpenAL: return std::make_shared(); -#ifdef _MSC_VER - case audio_output_type::XAudio2: return std::make_shared(); -#endif - } - }; + callbacks.get_audio = PURE_EXPR(g_cfg_audio_render.get()()); callbacks.get_msg_dialog = []() -> std::shared_ptr { @@ -199,13 +217,15 @@ void Rpcs3App::OnArguments(const wxCmdLineParser& parser) if (parser.FoundSwitch("t")) { - HLEExitOnStop = rpcs3::config.misc.exit_on_stop.value(); - rpcs3::config.misc.exit_on_stop = true; if (parser.GetParamCount() != 1) { - wxLogDebug(wxT("A (S)ELF file needs to be given in test mode, exiting.")); + wxLogDebug("A (S)ELF file needs to be given in test mode, exiting."); this->Exit(); } + + // TODO: clean implementation + g_cfg_autostart = true; + g_cfg_autoexit = true; } if (parser.GetParamCount() > 0) @@ -218,16 +238,11 @@ void Rpcs3App::OnArguments(const wxCmdLineParser& parser) void Rpcs3App::Exit() { - if (parser.FoundSwitch("t")) - { - rpcs3::config.misc.exit_on_stop = HLEExitOnStop; - } - Emu.Stop(); wxApp::Exit(); } -void Rpcs3App::SendDbgCommand(DbgCommand id, CPUThread* thr) +void Rpcs3App::SendDbgCommand(DbgCommand id, cpu_thread* thr) { wxCommandEvent event(wxEVT_DBG_COMMAND, id); event.SetClientData(thr); diff --git a/rpcs3/rpcs3.h b/rpcs3/rpcs3.h index bf745cdfe1..5561d8539c 100644 --- a/rpcs3/rpcs3.h +++ b/rpcs3/rpcs3.h @@ -1,21 +1,17 @@ #pragma once + #include "Gui/MainFrame.h" #include "Emu/DbgCommand.h" -#include "Utilities/Thread.h" #include #include -class CPUThread; - wxDECLARE_EVENT(wxEVT_DBG_COMMAND, wxCommandEvent); - class Rpcs3App : public wxApp { private: wxCmdLineParser parser; - // Used to restore the configuration state after a test run - bool HLEExitOnStop; + public: MainFrame* m_MainFrame; @@ -25,12 +21,9 @@ public: Rpcs3App(); - void SendDbgCommand(DbgCommand id, CPUThread* thr=nullptr); + void SendDbgCommand(DbgCommand id, class cpu_thread* thr = nullptr); }; DECLARE_APP(Rpcs3App) -//extern CPUThread& GetCPU(const u8 core); - extern Rpcs3App* TheApp; -static const u64 PS3_CLK = 3200000000;