#pragma once class PPUThread; struct ARMv7Context; namespace vm { // helper SFINAE type for vm::_ptr_base comparison operators (enables comparison between equal types and between any type and void*) template using if_comparable_t = std::enable_if_t< std::is_void::value || std::is_void::value || std::is_same, std::remove_cv_t>::value, RT>; // helper SFINAE type for vm::_ptr_base pointer arithmetic operators and indirection (disabled for void and function pointers) template using if_arithmetical_ptr_t = std::enable_if_t< !std::is_void::value && !std::is_function::value, RT>; template struct _ptr_base { AT m_addr; // don't access directly using type = T; static_assert(!std::is_pointer::value, "vm::_ptr_base<> error: invalid type (pointer)"); static_assert(!std::is_reference::value, "vm::_ptr_base<> error: invalid type (reference)"); AT addr() const { return m_addr; } // get vm pointer to member template> _ptr_base of(MT T2::*const member) const { const u32 offset = static_cast(reinterpret_cast(&(reinterpret_cast(0ull)->*member))); return{ vm::cast(m_addr + offset) }; } // get vm pointer to array member with array subscribtion template> _ptr_base> of(MT T2::*const member, u32 index) const { const u32 offset = static_cast(reinterpret_cast(&(reinterpret_cast(0ull)->*member))); return{ vm::cast(m_addr + offset + sizeof32(T) * index) }; } template std::enable_if_t::value> set(const CT& value) { m_addr = value; } template static std::enable_if_t::value, _ptr_base> make(const AT2& addr) { return{ addr }; } T* get_ptr() const { return vm::get_ptr(vm::cast(m_addr)); } T* priv_ptr() const { return vm::priv_ptr(vm::cast(m_addr)); } T* operator ->() const { return get_ptr(); } std::add_lvalue_reference_t operator [](u32 index) const { static_assert(!std::is_void::value, "vm::_ptr_base<> error: operator[] is not available for void pointers"); return vm::get_ref(vm::cast(m_addr + sizeof32(T) * index)); } // enable only the conversions which are originally possible between pointer types template::value>> operator _ptr_base() const { return{ vm::cast(m_addr) }; } template::value>> explicit operator T2*() const { return get_ptr(); } explicit operator bool() const { return m_addr != 0; } // test address alignment using alignof(T) bool aligned() const { return m_addr % alignof32(T) == 0; } // test address for arbitrary alignment or something force_inline explicit_bool_t operator %(to_ne_t right) const { return m_addr % right; } _ptr_base& operator =(const _ptr_base&) = default; }; template struct _ptr_base { AT m_addr; using type = func_def; AT addr() const { return m_addr; } template std::enable_if_t::value> set(const CT& value) { m_addr = value; } template static std::enable_if_t::value, _ptr_base> make(const AT2& addr) { return{ addr }; } // defined in CB_FUNC.h, passing context is mandatory RT operator()(PPUThread& CPU, T... args) const; // defined in ARMv7Callback.h, passing context is mandatory RT operator()(ARMv7Context& context, T... args) const; // conversion to another function pointer template operator _ptr_base() const { return{ vm::cast(m_addr) }; } explicit operator bool() const { return m_addr != 0; } _ptr_base& operator =(const _ptr_base&) = default; }; template struct _ptr_base { AT m_addr; static_assert(!sizeof(AT), "vm::_ptr_base<> error: use RT(T...) format for functions instead of RT(*)(T...)"); }; // Native endianness pointer to LE data template using ptrl = _ptr_base, AT>; // Native endianness pointer to BE data template using ptrb = _ptr_base, AT>; // BE pointer to LE data template using bptrl = _ptr_base, to_be_t>; // BE pointer to BE data template using bptrb = _ptr_base, to_be_t>; // LE pointer to LE data template using lptrl = _ptr_base, to_le_t>; // LE pointer to BE data template using lptrb = _ptr_base, to_le_t>; namespace ps3 { // default pointer for PS3 HLE functions (Native endianness pointer to BE data) template using ptr = ptrb; // default pointer to pointer for PS3 HLE functions (Native endianness pointer to BE pointer to BE data) template using pptr = ptr, AT>; // default pointer for PS3 HLE structures (BE pointer to BE data) template using bptr = bptrb; // default pointer to pointer for PS3 HLE structures (BE pointer to BE pointer to BE data) template using bpptr = bptr, AT>; // native endianness pointer to const BE data template using cptr = ptr; // BE pointer to const BE data template using bcptr = bptr; template using cpptr = pptr; template using bcpptr = bpptr; } namespace psv { // default pointer for PSV HLE functions (Native endianness pointer to LE data) template using ptr = ptrl; // default pointer to pointer for PSV HLE functions (Native endianness pointer to LE pointer to LE data) template using pptr = ptr>; // default pointer for PSV HLE structures (LE pointer to LE data) template using lptr = lptrl; // default pointer to pointer for PSV HLE structures (LE pointer to LE pointer to LE data) template using lpptr = lptr>; // native endianness pointer to const LE data template using cptr = ptr; // LE pointer to const LE data template using lcptr = lptr; template using cpptr = pptr; template using lcpptr = lpptr; } struct null_t { template operator _ptr_base() const { return{}; } }; // vm::null is convertible to any vm::ptr type as null pointer in virtual memory static null_t null; // perform static_cast (for example, vm::ptr to vm::ptr) template(std::declval()))> inline _ptr_base static_ptr_cast(const _ptr_base& other) { return{ other.m_addr }; } // perform const_cast (for example, vm::cptr to vm::ptr) template(std::declval()))> inline _ptr_base const_ptr_cast(const _ptr_base& other) { return{ other.m_addr }; } // perform reinterpret_cast (for example, vm::ptr to vm::ptr) template(std::declval()))> inline _ptr_base reinterpret_ptr_cast(const _ptr_base& other) { return{ other.m_addr }; } } // unary plus operator for vm::_ptr_base (always available) template inline vm::_ptr_base operator +(const vm::_ptr_base& ptr) { return ptr; } // indirection operator for vm::_ptr_base template inline vm::if_arithmetical_ptr_t operator *(const vm::_ptr_base& ptr) { return vm::get_ref(vm::cast(ptr.m_addr)); } // postfix increment operator for vm::_ptr_base template inline vm::if_arithmetical_ptr_t> operator ++(vm::_ptr_base& ptr, int) { const AT result = ptr.m_addr; ptr.m_addr += sizeof32(T); return{ result }; } // prefix increment operator for vm::_ptr_base template inline vm::if_arithmetical_ptr_t&> operator ++(vm::_ptr_base& ptr) { ptr.m_addr += sizeof32(T); return ptr; } // postfix decrement operator for vm::_ptr_base template inline vm::if_arithmetical_ptr_t> operator --(vm::_ptr_base& ptr, int) { const AT result = ptr.m_addr; ptr.m_addr -= sizeof32(T); return{ result }; } // prefix decrement operator for vm::_ptr_base template inline vm::if_arithmetical_ptr_t&> operator --(vm::_ptr_base& ptr) { ptr.m_addr -= sizeof32(T); return ptr; } // addition assignment operator for vm::_ptr_base (pointer += integer) template inline vm::if_arithmetical_ptr_t&> operator +=(vm::_ptr_base& ptr, to_ne_t count) { ptr.m_addr += count * sizeof32(T); return ptr; } // subtraction assignment operator for vm::_ptr_base (pointer -= integer) template inline vm::if_arithmetical_ptr_t&> operator -=(vm::_ptr_base& ptr, to_ne_t count) { ptr.m_addr -= count * sizeof32(T); return ptr; } // addition operator for vm::_ptr_base (pointer + integer) template inline vm::if_arithmetical_ptr_t> operator +(const vm::_ptr_base& ptr, to_ne_t count) { return{ ptr.m_addr + count * sizeof32(T) }; } // addition operator for vm::_ptr_base (integer + pointer) template inline vm::if_arithmetical_ptr_t> operator +(to_ne_t count, const vm::_ptr_base& ptr) { return{ ptr.m_addr + count * sizeof32(T) }; } // subtraction operator for vm::_ptr_base (pointer - integer) template inline vm::if_arithmetical_ptr_t> operator -(const vm::_ptr_base& ptr, to_ne_t count) { return{ ptr.m_addr - count * sizeof32(T) }; } // pointer difference operator for vm::_ptr_base template inline std::enable_if_t< !std::is_void::value && !std::is_void::value && !std::is_function::value && !std::is_function::value && std::is_same, std::remove_cv_t>::value, s32> operator -(const vm::_ptr_base& left, const vm::_ptr_base& right) { return static_cast(left.m_addr - right.m_addr) / sizeof32(T1); } // comparison operator for vm::_ptr_base (pointer1 == pointer2) template vm::if_comparable_t operator ==(const vm::_ptr_base& left, const vm::_ptr_base& right) { return left.m_addr == right.m_addr; } template bool operator ==(const vm::null_t&, const vm::_ptr_base& ptr) { return ptr.m_addr == 0; } template bool operator ==(const vm::_ptr_base& ptr, const vm::null_t&) { return ptr.m_addr == 0; } // comparison operator for vm::_ptr_base (pointer1 != pointer2) template vm::if_comparable_t operator !=(const vm::_ptr_base& left, const vm::_ptr_base& right) { return left.m_addr != right.m_addr; } template bool operator !=(const vm::null_t&, const vm::_ptr_base& ptr) { return ptr.m_addr != 0; } template bool operator !=(const vm::_ptr_base& ptr, const vm::null_t&) { return ptr.m_addr != 0; } // comparison operator for vm::_ptr_base (pointer1 < pointer2) template vm::if_comparable_t operator <(const vm::_ptr_base& left, const vm::_ptr_base& right) { return left.m_addr < right.m_addr; } template bool operator <(const vm::null_t&, const vm::_ptr_base& ptr) { return ptr.m_addr != 0; } template bool operator <(const vm::_ptr_base&, const vm::null_t&) { return false; } // comparison operator for vm::_ptr_base (pointer1 <= pointer2) template vm::if_comparable_t operator <=(const vm::_ptr_base& left, const vm::_ptr_base& right) { return left.m_addr <= right.m_addr; } template bool operator <=(const vm::null_t&, const vm::_ptr_base&) { return true; } template bool operator <=(const vm::_ptr_base& ptr, const vm::null_t&) { return ptr.m_addr == 0; } // comparison operator for vm::_ptr_base (pointer1 > pointer2) template vm::if_comparable_t operator >(const vm::_ptr_base& left, const vm::_ptr_base& right) { return left.m_addr > right.m_addr; } template bool operator >(const vm::null_t&, const vm::_ptr_base&) { return false; } template bool operator >(const vm::_ptr_base& ptr, const vm::null_t&) { return ptr.m_addr != 0; } // comparison operator for vm::_ptr_base (pointer1 >= pointer2) template vm::if_comparable_t operator >=(const vm::_ptr_base& left, const vm::_ptr_base& right) { return left.m_addr >= right.m_addr; } template bool operator >=(const vm::null_t&, const vm::_ptr_base& ptr) { return ptr.m_addr == 0; } template bool operator >=(const vm::_ptr_base&, const vm::null_t&) { return true; } // external specialization for is_be_t<> (true if AT is be_t<>) template struct is_be_t> : public std::integral_constant::value> { }; // external specialization for is_le_t<> (true if AT is le_t<>) template struct is_le_t> : public std::integral_constant::value> { }; // external specialization for to_ne_t<> (change AT endianness to native) template struct to_ne> { using type = vm::_ptr_base>; }; // external specialization for to_be_t<> (change AT endianness to BE) template struct to_be> { using type = vm::_ptr_base>; }; // external specialization for to_le_t<> (change AT endianness to LE) template struct to_le> { using type = vm::_ptr_base>; }; namespace fmt { // external specialization for fmt::format function template struct unveil, false> { using result_type = typename unveil::result_type; force_inline static result_type get_value(const vm::_ptr_base& arg) { return unveil::get_value(arg.addr()); } }; } // external specializations for PPU GPR (SC_FUNC.h, CB_FUNC.h) template struct cast_ppu_gpr; template struct cast_ppu_gpr, false> { force_inline static u64 to_gpr(const vm::_ptr_base& value) { return cast_ppu_gpr::value>::to_gpr(value.addr()); } force_inline static vm::_ptr_base from_gpr(const u64 reg) { return vm::_ptr_base::make(cast_ppu_gpr::value>::from_gpr(reg)); } }; // external specializations for ARMv7 GPR template struct cast_armv7_gpr; template struct cast_armv7_gpr, false> { force_inline static u32 to_gpr(const vm::_ptr_base& value) { return cast_armv7_gpr::value>::to_gpr(value.addr()); } force_inline static vm::_ptr_base from_gpr(const u32 reg) { return vm::_ptr_base::make(cast_armv7_gpr::value>::from_gpr(reg)); } };