diff --git a/Utilities/Atomic.h b/Utilities/Atomic.h new file mode 100644 index 0000000000..e0656b674b --- /dev/null +++ b/Utilities/Atomic.h @@ -0,0 +1,717 @@ +#pragma once + +#if defined(__GNUG__) + +template inline std::enable_if_t sync_val_compare_and_swap(volatile T* dest, T2 comp, T2 exch) +{ + return __sync_val_compare_and_swap(dest, comp, exch); +} + +template inline std::enable_if_t sync_bool_compare_and_swap(volatile T* dest, T2 comp, T2 exch) +{ + return __sync_bool_compare_and_swap(dest, comp, exch); +} + +template inline std::enable_if_t sync_lock_test_and_set(volatile T* dest, T2 value) +{ + return __sync_lock_test_and_set(dest, value); +} + +template inline std::enable_if_t sync_fetch_and_add(volatile T* dest, T2 value) +{ + return __sync_fetch_and_add(dest, value); +} + +template inline std::enable_if_t sync_fetch_and_sub(volatile T* dest, T2 value) +{ + return __sync_fetch_and_sub(dest, value); +} + +template inline std::enable_if_t sync_fetch_and_or(volatile T* dest, T2 value) +{ + return __sync_fetch_and_or(dest, value); +} + +template inline std::enable_if_t sync_fetch_and_and(volatile T* dest, T2 value) +{ + return __sync_fetch_and_and(dest, value); +} + +template inline std::enable_if_t sync_fetch_and_xor(volatile T* dest, T2 value) +{ + return __sync_fetch_and_xor(dest, value); +} + +#elif defined(_MSC_VER) + +// atomic compare and swap functions + +inline u8 sync_val_compare_and_swap(volatile u8* dest, u8 comp, u8 exch) +{ + return _InterlockedCompareExchange8((volatile char*)dest, exch, comp); +} + +inline u16 sync_val_compare_and_swap(volatile u16* dest, u16 comp, u16 exch) +{ + return _InterlockedCompareExchange16((volatile short*)dest, exch, comp); +} + +inline u32 sync_val_compare_and_swap(volatile u32* dest, u32 comp, u32 exch) +{ + return _InterlockedCompareExchange((volatile long*)dest, exch, comp); +} + +inline u64 sync_val_compare_and_swap(volatile u64* dest, u64 comp, u64 exch) +{ + return _InterlockedCompareExchange64((volatile long long*)dest, exch, comp); +} + +inline u128 sync_val_compare_and_swap(volatile u128* dest, u128 comp, u128 exch) +{ + _InterlockedCompareExchange128((volatile long long*)dest, exch.hi, exch.lo, (long long*)&comp); + return comp; +} + +inline bool sync_bool_compare_and_swap(volatile u8* dest, u8 comp, u8 exch) +{ + return (u8)_InterlockedCompareExchange8((volatile char*)dest, exch, comp) == comp; +} + +inline bool sync_bool_compare_and_swap(volatile u16* dest, u16 comp, u16 exch) +{ + return (u16)_InterlockedCompareExchange16((volatile short*)dest, exch, comp) == comp; +} + +inline bool sync_bool_compare_and_swap(volatile u32* dest, u32 comp, u32 exch) +{ + return (u32)_InterlockedCompareExchange((volatile long*)dest, exch, comp) == comp; +} + +inline bool sync_bool_compare_and_swap(volatile u64* dest, u64 comp, u64 exch) +{ + return (u64)_InterlockedCompareExchange64((volatile long long*)dest, exch, comp) == comp; +} + +inline bool sync_bool_compare_and_swap(volatile u128* dest, u128 comp, u128 exch) +{ + return _InterlockedCompareExchange128((volatile long long*)dest, exch.hi, exch.lo, (long long*)&comp) != 0; +} + +// atomic exchange functions + +inline u8 sync_lock_test_and_set(volatile u8* dest, u8 value) +{ + return _InterlockedExchange8((volatile char*)dest, value); +} + +inline u16 sync_lock_test_and_set(volatile u16* dest, u16 value) +{ + return _InterlockedExchange16((volatile short*)dest, value); +} + +inline u32 sync_lock_test_and_set(volatile u32* dest, u32 value) +{ + return _InterlockedExchange((volatile long*)dest, value); +} + +inline u64 sync_lock_test_and_set(volatile u64* dest, u64 value) +{ + return _InterlockedExchange64((volatile long long*)dest, value); +} + +inline u128 sync_lock_test_and_set(volatile u128* dest, u128 value) +{ + while (true) + { + u128 old; + old.lo = dest->lo; + old.hi = dest->hi; + + if (sync_bool_compare_and_swap(dest, old, value)) return old; + } +} + +// atomic add functions + +inline u8 sync_fetch_and_add(volatile u8* dest, u8 value) +{ + return _InterlockedExchangeAdd8((volatile char*)dest, value); +} + +inline u16 sync_fetch_and_add(volatile u16* dest, u16 value) +{ + return _InterlockedExchangeAdd16((volatile short*)dest, value); +} + +inline u32 sync_fetch_and_add(volatile u32* dest, u32 value) +{ + return _InterlockedExchangeAdd((volatile long*)dest, value); +} + +inline u64 sync_fetch_and_add(volatile u64* dest, u64 value) +{ + return _InterlockedExchangeAdd64((volatile long long*)dest, value); +} + +inline u128 sync_fetch_and_add(volatile u128* dest, u128 value) +{ + while (true) + { + u128 old; + old.lo = dest->lo; + old.hi = dest->hi; + + u128 _new; + _new.lo = old.lo + value.lo; + _new.hi = old.hi + value.hi + (_new.lo < value.lo); + + if (sync_bool_compare_and_swap(dest, old, _new)) return old; + } +} + +// atomic sub functions + +inline u8 sync_fetch_and_sub(volatile u8* dest, u8 value) +{ + return _InterlockedExchangeAdd8((volatile char*)dest, -(char)value); +} + +inline u16 sync_fetch_and_sub(volatile u16* dest, u16 value) +{ + return _InterlockedExchangeAdd16((volatile short*)dest, -(short)value); +} + +inline u32 sync_fetch_and_sub(volatile u32* dest, u32 value) +{ + return _InterlockedExchangeAdd((volatile long*)dest, -(long)value); +} + +inline u64 sync_fetch_and_sub(volatile u64* dest, u64 value) +{ + return _InterlockedExchangeAdd64((volatile long long*)dest, -(long long)value); +} + +inline u128 sync_fetch_and_sub(volatile u128* dest, u128 value) +{ + while (true) + { + u128 old; + old.lo = dest->lo; + old.hi = dest->hi; + + u128 _new; + _new.lo = old.lo - value.lo; + _new.hi = old.hi - value.hi - (old.lo < value.lo); + + if (sync_bool_compare_and_swap(dest, old, _new)) return old; + } +} + +// atomic `bitwise or` functions + +inline u8 sync_fetch_and_or(volatile u8* dest, u8 value) +{ + return _InterlockedOr8((volatile char*)dest, value); +} + +inline u16 sync_fetch_and_or(volatile u16* dest, u16 value) +{ + return _InterlockedOr16((volatile short*)dest, value); +} + +inline u32 sync_fetch_and_or(volatile u32* dest, u32 value) +{ + return _InterlockedOr((volatile long*)dest, value); +} + +inline u64 sync_fetch_and_or(volatile u64* dest, u64 value) +{ + return _InterlockedOr64((volatile long long*)dest, value); +} + +inline u128 sync_fetch_and_or(volatile u128* dest, u128 value) +{ + while (true) + { + u128 old; + old.lo = dest->lo; + old.hi = dest->hi; + + u128 _new; + _new.lo = old.lo | value.lo; + _new.hi = old.hi | value.hi; + + if (sync_bool_compare_and_swap(dest, old, _new)) return old; + } +} + +// atomic `bitwise and` functions + +inline u8 sync_fetch_and_and(volatile u8* dest, u8 value) +{ + return _InterlockedAnd8((volatile char*)dest, value); +} + +inline u16 sync_fetch_and_and(volatile u16* dest, u16 value) +{ + return _InterlockedAnd16((volatile short*)dest, value); +} + +inline u32 sync_fetch_and_and(volatile u32* dest, u32 value) +{ + return _InterlockedAnd((volatile long*)dest, value); +} + +inline u64 sync_fetch_and_and(volatile u64* dest, u64 value) +{ + return _InterlockedAnd64((volatile long long*)dest, value); +} + +inline u128 sync_fetch_and_and(volatile u128* dest, u128 value) +{ + while (true) + { + u128 old; + old.lo = dest->lo; + old.hi = dest->hi; + + u128 _new; + _new.lo = old.lo & value.lo; + _new.hi = old.hi & value.hi; + + if (sync_bool_compare_and_swap(dest, old, _new)) return old; + } +} + +// atomic `bitwise xor` functions + +inline u8 sync_fetch_and_xor(volatile u8* dest, u8 value) +{ + return _InterlockedXor8((volatile char*)dest, value); +} + +inline u16 sync_fetch_and_xor(volatile u16* dest, u16 value) +{ + return _InterlockedXor16((volatile short*)dest, value); +} + +inline u32 sync_fetch_and_xor(volatile u32* dest, u32 value) +{ + return _InterlockedXor((volatile long*)dest, value); +} + +inline u64 sync_fetch_and_xor(volatile u64* dest, u64 value) +{ + return _InterlockedXor64((volatile long long*)dest, value); +} + +inline u128 sync_fetch_and_xor(volatile u128* dest, u128 value) +{ + while (true) + { + u128 old; + old.lo = dest->lo; + old.hi = dest->hi; + + u128 _new; + _new.lo = old.lo ^ value.lo; + _new.hi = old.hi ^ value.hi; + + if (sync_bool_compare_and_swap(dest, old, _new)) return old; + } +} + +#endif /* _MSC_VER */ + +template struct atomic_storage +{ + static_assert(!Size, "Invalid atomic type"); +}; + +template struct atomic_storage +{ + using type = u8; +}; + +template struct atomic_storage +{ + using type = u16; +}; + +template struct atomic_storage +{ + using type = u32; +}; + +template struct atomic_storage +{ + using type = u64; +}; + +template struct atomic_storage +{ + using type = u128; +}; + +template using atomic_storage_t = typename atomic_storage::type; + +// result wrapper to deal with void result type +template struct atomic_op_result_t +{ + RT result; + + template inline atomic_op_result_t(T func, VT& var, Args&&... args) + : result(std::move(func(var, std::forward(args)...))) + { + } + + inline RT move() + { + return std::move(result); + } +}; + +// void specialization: result is the initial value of the first arg +template struct atomic_op_result_t +{ + VT result; + + template inline atomic_op_result_t(T func, VT& var, Args&&... args) + : result(var) + { + func(var, std::forward(args)...); + } + + inline VT move() + { + return std::move(result); + } +}; + +// member function specialization +template struct atomic_op_result_t +{ + RT result; + + template inline atomic_op_result_t(RT(CT::*func)(FArgs...), VT& var, Args&&... args) + : result(std::move((var.*func)(std::forward(args)...))) + { + } + + inline RT move() + { + return std::move(result); + } +}; + +// member function void specialization +template struct atomic_op_result_t +{ + VT result; + + template inline atomic_op_result_t(void(CT::*func)(FArgs...), VT& var, Args&&... args) + : result(var) + { + (var.*func)(std::forward(args)...); + } + + inline VT move() + { + return std::move(result); + } +}; + +template class atomic_t +{ + using type = std::remove_cv_t; + using stype = atomic_storage_t; + using storage = atomic_storage; + + static_assert(alignof(type) <= alignof(stype), "atomic_t<> error: unexpected alignment"); + + stype m_data; + + template static inline void write_relaxed(volatile T2& data, const T2& value) + { + data = value; + } + + static inline void write_relaxed(volatile u128& data, const u128& value) + { + sync_lock_test_and_set(&data, value); + } + + template static inline T2 read_relaxed(const volatile T2& data) + { + return data; + } + + static inline u128 read_relaxed(const volatile u128& value) + { + return sync_val_compare_and_swap(const_cast(&value), u128{0}, u128{0}); + } + +public: + static inline const stype to_subtype(const type& value) + { + return reinterpret_cast(value); + } + + static inline const type from_subtype(const stype value) + { + return reinterpret_cast(value); + } + + atomic_t() = default; + + atomic_t(const atomic_t&) = delete; + + atomic_t(atomic_t&&) = delete; + + inline atomic_t(type value) + : m_data(to_subtype(value)) + { + } + + atomic_t& operator =(const atomic_t&) = delete; + + atomic_t& operator =(atomic_t&&) = delete; + + inline atomic_t& operator =(type value) + { + return write_relaxed(m_data, to_subtype(value)), *this; + } + + operator type() const volatile + { + return from_subtype(read_relaxed(m_data)); + } + + // Unsafe direct access + stype* raw_data() + { + return reinterpret_cast(&m_data); + } + + // Unsafe direct access + type& raw() + { + return reinterpret_cast(m_data); + } + + // Atomically compare data with cmp, replace with exch if equal, return previous data value anyway + inline const type compare_and_swap(const type& cmp, const type& exch) volatile + { + return from_subtype(sync_val_compare_and_swap(&m_data, to_subtype(cmp), to_subtype(exch))); + } + + // Atomically compare data with cmp, replace with exch if equal, return true if data was replaced + inline bool compare_and_swap_test(const type& cmp, const type& exch) volatile + { + return sync_bool_compare_and_swap(&m_data, to_subtype(cmp), to_subtype(exch)); + } + + // Atomically replace data with exch, return previous data value + inline const type exchange(const type& exch) volatile + { + return from_subtype(sync_lock_test_and_set(&m_data, to_subtype(exch))); + } + + // Atomically read data, possibly without memory barrier (not for 128 bit) + inline const type load() const volatile + { + return from_subtype(read_relaxed(m_data)); + } + + // Atomically write data, possibly without memory barrier (not for 128 bit) + inline void store(const type& value) volatile + { + write_relaxed(m_data, to_subtype(value)); + } + + // Perform an atomic operation on data (func is either pointer to member function or callable object with a T& first arg); + // Returns the result of the callable object call or previous (old) value of the atomic variable if the return type is void + template> auto atomic_op(F func, Args&&... args) volatile -> decltype(atomic_op_result_t::result) + { + while (true) + { + // Read the old value from memory + const stype old = read_relaxed(m_data); + + // Copy the old value + stype _new = old; + + // Call atomic op for the local copy of the old value and save the return value of the function + atomic_op_result_t result(func, reinterpret_cast(_new), args...); + + // Atomically compare value with `old`, replace with `_new` and return on success + if (sync_bool_compare_and_swap(&m_data, old, _new)) return result.move(); + } + } + + // Atomic bitwise OR, returns previous data + inline const type _or(const type& right) volatile + { + return from_subtype(sync_fetch_and_or(&m_data, to_subtype(right))); + } + + // Atomic bitwise AND, returns previous data + inline const type _and(const type& right) volatile + { + return from_subtype(sync_fetch_and_and(&m_data, to_subtype(right))); + } + + // Atomic bitwise AND NOT (inverts right argument), returns previous data + inline const type _and_not(const type& right) volatile + { + return from_subtype(sync_fetch_and_and(&m_data, ~to_subtype(right))); + } + + // Atomic bitwise XOR, returns previous data + inline const type _xor(const type& right) volatile + { + return from_subtype(sync_fetch_and_xor(&m_data, to_subtype(right))); + } + + inline const type operator |=(const type& right) volatile + { + return from_subtype(sync_fetch_and_or(&m_data, to_subtype(right)) | to_subtype(right)); + } + + inline const type operator &=(const type& right) volatile + { + return from_subtype(sync_fetch_and_and(&m_data, to_subtype(right)) & to_subtype(right)); + } + + inline const type operator ^=(const type& right) volatile + { + return from_subtype(sync_fetch_and_xor(&m_data, to_subtype(right)) ^ to_subtype(right)); + } +}; + +template inline std::enable_if_t operator ++(atomic_t& left) +{ + return left.from_subtype(sync_fetch_and_add(left.raw_data(), 1) + 1); +} + +template inline std::enable_if_t operator --(atomic_t& left) +{ + return left.from_subtype(sync_fetch_and_sub(left.raw_data(), 1) - 1); +} + +template inline std::enable_if_t operator ++(atomic_t& left, int) +{ + return left.from_subtype(sync_fetch_and_add(left.raw_data(), 1)); +} + +template inline std::enable_if_t operator --(atomic_t& left, int) +{ + return left.from_subtype(sync_fetch_and_sub(left.raw_data(), 1)); +} + +template inline std::enable_if_t::value, T> operator +=(atomic_t& left, const T2& right) +{ + return left.from_subtype(sync_fetch_and_add(left.raw_data(), right) + right); +} + +template inline std::enable_if_t::value, T> operator -=(atomic_t& left, const T2& right) +{ + return left.from_subtype(sync_fetch_and_sub(left.raw_data(), right) - right); +} + +template inline std::enable_if_t> operator ++(atomic_t>& left) +{ + return left.from_subtype(sync_fetch_and_add(left.raw_data(), 1) + 1); +} + +template inline std::enable_if_t> operator --(atomic_t>& left) +{ + return left.from_subtype(sync_fetch_and_sub(left.raw_data(), 1) - 1); +} + +template inline std::enable_if_t> operator ++(atomic_t>& left, int) +{ + return left.from_subtype(sync_fetch_and_add(left.raw_data(), 1)); +} + +template inline std::enable_if_t> operator --(atomic_t>& left, int) +{ + return left.from_subtype(sync_fetch_and_sub(left.raw_data(), 1)); +} + +template inline std::enable_if_t::value, nse_t> operator +=(atomic_t>& left, const T2& right) +{ + return left.from_subtype(sync_fetch_and_add(left.raw_data(), right) + right); +} + +template inline std::enable_if_t::value, nse_t> operator -=(atomic_t>& left, const T2& right) +{ + return left.from_subtype(sync_fetch_and_sub(left.raw_data(), right) - right); +} + +template inline std::enable_if_t> operator ++(atomic_t>& left) +{ + return left.atomic_op([](se_t& value) -> se_t + { + return ++value; + }); +} + +template inline std::enable_if_t> operator --(atomic_t>& left) +{ + return left.atomic_op([](se_t& value) -> se_t + { + return --value; + }); +} + +template inline std::enable_if_t> operator ++(atomic_t>& left, int) +{ + return left.atomic_op([](se_t& value) -> se_t + { + return value++; + }); +} + +template inline std::enable_if_t> operator --(atomic_t>& left, int) +{ + return left.atomic_op([](se_t& value) -> se_t + { + return value--; + }); +} + +template inline std::enable_if_t::value, se_t> operator +=(atomic_t>& left, const T2& right) +{ + return left.atomic_op([&](se_t& value) -> se_t + { + return value += right; + }); +} + +template inline std::enable_if_t::value, se_t> operator -=(atomic_t>& left, const T2& right) +{ + return left.atomic_op([&](se_t& value) -> se_t + { + return value -= right; + }); +} + +template using atomic_be_t = atomic_t>; // Atomic BE Type (for PS3 virtual memory) + +template using atomic_le_t = atomic_t>; // Atomic LE Type (for PSV virtual memory) + +// Algorithm for std::atomic; similar to atomic_t::atomic_op() +template> auto atomic_op(std::atomic& var, F func, Args&&... args) -> decltype(atomic_op_result_t::result) +{ + auto old = var.load(); + + while (true) + { + auto _new = old; + + atomic_op_result_t result(func, _new, args...); + + if (var.compare_exchange_strong(old, _new)) return result.move(); + } +} diff --git a/Utilities/BEType.h b/Utilities/BEType.h index 4b34c7015e..916b52eb64 100644 --- a/Utilities/BEType.h +++ b/Utilities/BEType.h @@ -8,97 +8,74 @@ #define IS_LE_MACHINE // only draft +template class masked_array_t // array type accessed as (index ^ M) +{ + T m_data[N]; + +public: + T& operator [](std::size_t index) + { + return m_data[index ^ M]; + } + + const T& operator [](std::size_t index) const + { + return m_data[index ^ M]; + } + + T& at(std::size_t index) + { + return (index ^ M) < N ? m_data[index ^ M] : throw std::out_of_range("Masked array"); + } + + const T& at(std::size_t index) const + { + return (index ^ M) < N ? m_data[index ^ M] : throw std::out_of_range("Masked array"); + } +}; + union v128 { - u64 _u64[2]; - s64 _s64[2]; +#ifdef IS_LE_MACHINE + template using normal_array_t = masked_array_t; + template using reversed_array_t = masked_array_t; +#else + template using normal_array_t = masked_array_t; + template using reversed_array_t = masked_array_t; +#endif - class u64_reversed_array_2 - { - u64 data[2]; + normal_array_t _u64; + normal_array_t _s64; + reversed_array_t u64r; + reversed_array_t s64r; - public: - u64& operator [] (s32 index) - { - return data[1 - index]; - } + normal_array_t _u32; + normal_array_t _s32; + reversed_array_t u32r; + reversed_array_t s32r; - const u64& operator [] (s32 index) const - { - return data[1 - index]; - } + normal_array_t _u16; + normal_array_t _s16; + reversed_array_t u16r; + reversed_array_t s16r; - } u64r; + normal_array_t _u8; + normal_array_t _s8; + reversed_array_t u8r; + reversed_array_t s8r; - u32 _u32[4]; - s32 _s32[4]; + normal_array_t _f; + normal_array_t _d; + reversed_array_t fr; + reversed_array_t dr; - class u32_reversed_array_4 - { - u32 data[4]; - - public: - u32& operator [] (s32 index) - { - return data[3 - index]; - } - - const u32& operator [] (s32 index) const - { - return data[3 - index]; - } - - } u32r; - - u16 _u16[8]; - s16 _s16[8]; - - class u16_reversed_array_8 - { - u16 data[8]; - - public: - u16& operator [] (s32 index) - { - return data[7 - index]; - } - - const u16& operator [] (s32 index) const - { - return data[7 - index]; - } - - } u16r; - - u8 _u8[16]; - s8 _s8[16]; - - class u8_reversed_array_16 - { - u8 data[16]; - - public: - u8& operator [] (s32 index) - { - return data[15 - index]; - } - - const u8& operator [] (s32 index) const - { - return data[15 - index]; - } - - } u8r; - - float _f[4]; - double _d[2]; __m128 vf; __m128i vi; __m128d vd; class bit_array_128 { - u64 data[2]; + u64 m_data[2]; public: class bit_element @@ -113,12 +90,12 @@ union v128 { } - force_inline operator bool() const + inline operator bool() const { return (data & mask) != 0; } - force_inline bit_element& operator = (const bool right) + inline bit_element& operator =(const bool right) { if (right) { @@ -131,7 +108,7 @@ union v128 return *this; } - force_inline bit_element& operator = (const bit_element& right) + inline bit_element& operator =(const bit_element& right) { if (right) { @@ -146,30 +123,40 @@ union v128 }; // Index 0 returns the MSB and index 127 returns the LSB - bit_element operator [] (u32 index) + bit_element operator [](u32 index) { - assert(index < 128); - #ifdef IS_LE_MACHINE - return bit_element(data[1 - (index >> 6)], 0x8000000000000000ull >> (index & 0x3F)); + return bit_element(m_data[1 - (index >> 6)], 0x8000000000000000ull >> (index & 0x3F)); #else - return bit_element(data[index >> 6], 0x8000000000000000ull >> (index & 0x3F)); + return bit_element(m_data[index >> 6], 0x8000000000000000ull >> (index & 0x3F)); #endif } // Index 0 returns the MSB and index 127 returns the LSB - const bool operator [] (u32 index) const + bool operator [](u32 index) const { - assert(index < 128); - #ifdef IS_LE_MACHINE - return (data[1 - (index >> 6)] & (0x8000000000000000ull >> (index & 0x3F))) != 0; + return (m_data[1 - (index >> 6)] & (0x8000000000000000ull >> (index & 0x3F))) != 0; #else - return (data[index >> 6] & (0x8000000000000000ull >> (index & 0x3F))) != 0; + return (m_data[index >> 6] & (0x8000000000000000ull >> (index & 0x3F))) != 0; #endif } - } _bit; + bit_element at(u32 index) + { + if (index >= 128) throw std::out_of_range("Bit element"); + + return operator[](index); + } + + bool at(u32 index) const + { + if (index >= 128) throw std::out_of_range("Bit element"); + + return operator[](index); + } + } + _bit; static v128 from64(u64 _0, u64 _1 = 0) { @@ -248,117 +235,118 @@ union v128 return ret; } - static force_inline v128 add8(const v128& left, const v128& right) + static inline v128 add8(const v128& left, const v128& right) { return fromV(_mm_add_epi8(left.vi, right.vi)); } - static force_inline v128 add16(const v128& left, const v128& right) + static inline v128 add16(const v128& left, const v128& right) { return fromV(_mm_add_epi16(left.vi, right.vi)); } - static force_inline v128 add32(const v128& left, const v128& right) + static inline v128 add32(const v128& left, const v128& right) { return fromV(_mm_add_epi32(left.vi, right.vi)); } - static force_inline v128 addfs(const v128& left, const v128& right) + static inline v128 addfs(const v128& left, const v128& right) { return fromF(_mm_add_ps(left.vf, right.vf)); } - static force_inline v128 addfd(const v128& left, const v128& right) + static inline v128 addfd(const v128& left, const v128& right) { return fromD(_mm_add_pd(left.vd, right.vd)); } - static force_inline v128 sub8(const v128& left, const v128& right) + static inline v128 sub8(const v128& left, const v128& right) { return fromV(_mm_sub_epi8(left.vi, right.vi)); } - static force_inline v128 sub16(const v128& left, const v128& right) + static inline v128 sub16(const v128& left, const v128& right) { return fromV(_mm_sub_epi16(left.vi, right.vi)); } - static force_inline v128 sub32(const v128& left, const v128& right) + static inline v128 sub32(const v128& left, const v128& right) { return fromV(_mm_sub_epi32(left.vi, right.vi)); } - static force_inline v128 subfs(const v128& left, const v128& right) + static inline v128 subfs(const v128& left, const v128& right) { return fromF(_mm_sub_ps(left.vf, right.vf)); } - static force_inline v128 subfd(const v128& left, const v128& right) + static inline v128 subfd(const v128& left, const v128& right) { return fromD(_mm_sub_pd(left.vd, right.vd)); } - static force_inline v128 maxu8(const v128& left, const v128& right) + static inline v128 maxu8(const v128& left, const v128& right) { return fromV(_mm_max_epu8(left.vi, right.vi)); } - static force_inline v128 minu8(const v128& left, const v128& right) + static inline v128 minu8(const v128& left, const v128& right) { return fromV(_mm_min_epu8(left.vi, right.vi)); } - static force_inline v128 eq8(const v128& left, const v128& right) + static inline v128 eq8(const v128& left, const v128& right) { return fromV(_mm_cmpeq_epi8(left.vi, right.vi)); } - static force_inline v128 eq16(const v128& left, const v128& right) + static inline v128 eq16(const v128& left, const v128& right) { return fromV(_mm_cmpeq_epi16(left.vi, right.vi)); } - static force_inline v128 eq32(const v128& left, const v128& right) + static inline v128 eq32(const v128& left, const v128& right) { return fromV(_mm_cmpeq_epi32(left.vi, right.vi)); } - bool operator == (const v128& right) const + bool operator ==(const v128& right) const { - return (_u64[0] == right._u64[0]) && (_u64[1] == right._u64[1]); + return _u64[0] == right._u64[0] && _u64[1] == right._u64[1]; } - bool operator != (const v128& right) const + bool operator !=(const v128& right) const { - return (_u64[0] != right._u64[0]) || (_u64[1] != right._u64[1]); + return _u64[0] != right._u64[0] || _u64[1] != right._u64[1]; } - force_inline bool is_any_1() const // check if any bit is 1 + inline bool is_any_1() const // check if any bit is 1 { return _u64[0] || _u64[1]; } - force_inline bool is_any_0() const // check if any bit is 0 + inline bool is_any_0() const // check if any bit is 0 { return ~_u64[0] || ~_u64[1]; } // result = (~left) & (right) - static force_inline v128 andnot(const v128& left, const v128& right) + static inline v128 andnot(const v128& left, const v128& right) { return fromV(_mm_andnot_si128(left.vi, right.vi)); } void clear() { - _u64[1] = _u64[0] = 0; + _u64[0] = 0; + _u64[1] = 0; } std::string to_hex() const; std::string to_xyzw() const; - static force_inline v128 byteswap(const v128 val) + static inline v128 byteswap(const v128 val) { return fromV(_mm_shuffle_epi8(val.vi, _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15))); } @@ -386,293 +374,469 @@ inline v128 operator ~(const v128& other) return v128::from64(~other._u64[0], ~other._u64[1]); } -template struct se_t; - -template struct se_t +template struct se_storage { - static force_inline u16 to(const T& src) - { - return _byteswap_ushort((u16&)src); - } - - static force_inline T from(const u16 src) - { - const u16 res = _byteswap_ushort(src); - return (T&)res; - } + static_assert(!Size, "Bad se_storage<> type"); }; -template struct se_t -{ - static force_inline u32 to(const T& src) - { - return _byteswap_ulong((u32&)src); - } - - static force_inline T from(const u32 src) - { - const u32 res = _byteswap_ulong(src); - return (T&)res; - } -}; - -template struct se_t -{ - static force_inline u64 to(const T& src) - { - return _byteswap_uint64((u64&)src); - } - - static force_inline T from(const u64 src) - { - const u64 res = _byteswap_uint64(src); - return (T&)res; - } -}; - -template struct se_t -{ - static force_inline v128 to(const T& src) - { - return v128::byteswap((v128&)src); - } - - static force_inline T from(const v128& src) - { - const v128 res = v128::byteswap(src); - return (T&)res; - } -}; - -template struct const_se_t; - -template struct const_se_t -{ - static const u16 value = - ((_value >> 8) & 0x00ff) | - ((_value << 8) & 0xff00); -}; - -template struct const_se_t -{ - static const u32 value = - ((_value >> 24) & 0x000000ff) | - ((_value >> 8) & 0x0000ff00) | - ((_value << 8) & 0x00ff0000) | - ((_value << 24) & 0xff000000); -}; - -template struct const_se_t -{ - static const u64 value = - ((_value >> 56) & 0x00000000000000ff) | - ((_value >> 40) & 0x000000000000ff00) | - ((_value >> 24) & 0x0000000000ff0000) | - ((_value >> 8) & 0x00000000ff000000) | - ((_value << 8) & 0x000000ff00000000) | - ((_value << 24) & 0x0000ff0000000000) | - ((_value << 40) & 0x00ff000000000000) | - ((_value << 56) & 0xff00000000000000); -}; - -template struct be_storage -{ - static_assert(!size, "Bad be_storage_t<> type"); -}; - -template struct be_storage +template struct se_storage { using type = u16; + + [[deprecated]] static constexpr u16 swap(u16 src) // for reference + { + return (src >> 8) | (src << 8); + } + + static inline u16 to(const T& src) + { + return _byteswap_ushort(reinterpret_cast(src)); + } + + static inline T from(u16 src) + { + const u16 result = _byteswap_ushort(src); + return reinterpret_cast(result); + } }; -template struct be_storage +template struct se_storage { using type = u32; + + [[deprecated]] static constexpr u32 swap(u32 src) // for reference + { + return (src >> 24) | (src << 24) | ((src >> 8) & 0x0000ff00) | ((src << 8) & 0x00ff0000); + } + + static inline u32 to(const T& src) + { + return _byteswap_ulong(reinterpret_cast(src)); + } + + static inline T from(u32 src) + { + const u32 result = _byteswap_ulong(src); + return reinterpret_cast(result); + } }; -template struct be_storage +template struct se_storage { using type = u64; + + [[deprecated]] static constexpr u64 swap(u64 src) // for reference + { + return (src >> 56) | (src << 56) | + ((src >> 40) & 0x000000000000ff00) | + ((src >> 24) & 0x0000000000ff0000) | + ((src >> 8) & 0x00000000ff000000) | + ((src << 8) & 0x000000ff00000000) | + ((src << 24) & 0x0000ff0000000000) | + ((src << 40) & 0x00ff000000000000); + } + + static inline u64 to(const T& src) + { + return _byteswap_uint64(reinterpret_cast(src)); + } + + static inline T from(u64 src) + { + const u64 result = _byteswap_uint64(src); + return reinterpret_cast(result); + } }; -template struct be_storage +template struct se_storage { using type = v128; + + static inline v128 to(const T& src) + { + return v128::byteswap(reinterpret_cast(src)); + } + + static inline T from(const v128& src) + { + const v128 result = v128::byteswap(src); + return reinterpret_cast(result); + } }; -template using be_storage_t = typename be_storage::type; +template using se_storage_t = typename se_storage::type; -template class be_t +template struct se_convert { - // TODO (complicated cases like int-float conversions are not handled correctly) - template - struct _convert + using type_from = std::remove_cv_t; + using type_to = std::remove_cv_t; + using stype_from = se_storage_t>; + using stype_to = se_storage_t>; + using storage_from = se_storage>; + using storage_to = se_storage>; + + static inline std::enable_if_t::value, stype_to> convert(const stype_from& data) { - static force_inline be_t& func(Tfrom& be_value) + return data; + } + + static inline stype_to convert(const stype_from& data, ...) + { + return storage_to::to(storage_from::from(data)); + } +}; + +static struct se_raw_tag_t {} const se_raw{}; + +template class se_t; + +// se_t with switched endianness +template class se_t +{ + using type = std::remove_cv_t; + using stype = se_storage_t; + using storage = se_storage; + + stype m_data; + + static_assert(!std::is_union::value && !std::is_class::value || std::is_same::value || std::is_same::value, "se_t<> error: invalid type (struct or union)"); + static_assert(!std::is_pointer::value, "se_t<> error: invalid type (pointer)"); + static_assert(!std::is_reference::value, "se_t<> error: invalid type (reference)"); + static_assert(!std::is_array::value, "se_t<> error: invalid type (array)"); + static_assert(!std::is_enum::value, "se_t<> error: invalid type (enumeration), use integral type instead"); + static_assert(alignof(type) == alignof(stype), "se_t<> error: unexpected alignment"); + + template::value> struct bool_converter + { + static inline bool to_bool(const se_t& value) { - Tto res = be_value; - return (be_t&)res; + return static_cast(value.value()); } }; - template - struct _convert + template struct bool_converter { - static force_inline be_t& func(Tfrom& be_value) + static inline bool to_bool(const se_t& value) { - Tto res = se_t::func(se_t::func(be_value)); - return (be_t&)res; - } - }; - - template - struct _convert - { - static force_inline be_t& func(Tfrom& be_value) - { - Tto res = be_value >> ((sizeof(Tfrom) - sizeof(Tto)) * 8); - return (be_t&)res; + return value.m_data != 0; } }; public: - using type = std::remove_cv_t; - using stype = be_storage_t>; + se_t() = default; -#ifdef IS_LE_MACHINE - stype m_data; // don't access directly -#else - type m_data; // don't access directly -#endif + se_t(const se_t& right) = default; - static_assert(!std::is_class::value, "be_t<> error: invalid type (class or structure)"); - static_assert(!std::is_union::value || std::is_same::value, "be_t<> error: invalid type (union)"); - static_assert(!std::is_pointer::value, "be_t<> error: invalid type (pointer)"); - static_assert(!std::is_reference::value, "be_t<> error: invalid type (reference)"); - static_assert(!std::is_array::value, "be_t<> error: invalid type (array)"); - static_assert(!std::is_enum::value, "be_t<> error: invalid type (enumeration), use integral type instead"); - static_assert(__alignof(type) == __alignof(stype), "be_t<> error: unexpected alignment"); - - be_t() = default; - - be_t(const be_t&) = default; - - force_inline be_t(const type& value) -#ifdef IS_LE_MACHINE - : m_data(se_t::to(value)) -#else - : m_data(value) -#endif + inline se_t(type value) + : m_data(storage::to(value)) { } - - // get value in current machine byte ordering - force_inline type value() const - { -#ifdef IS_LE_MACHINE - return se_t::from(m_data); -#else - return m_data; -#endif - } - - // get underlying data without any byte order manipulation - const stype& data() const - { -#ifdef IS_LE_MACHINE - return m_data; -#else - return reinterpret_cast(m_data); -#endif - } - be_t& operator =(const be_t&) = default; - - template std::enable_if_t::value, be_t&> operator =(const CT& value) + // construct directly from raw data (don't use) + inline se_t(const stype& raw_value, const se_raw_tag_t&) + : m_data(raw_value) { -#ifdef IS_LE_MACHINE - m_data = se_t::to(value); -#else - m_data = value; -#endif - - return *this; } - //template::value>> operator CT() const - //{ - // return value(); - //} - - operator type() const + inline type value() const { - return value(); + return storage::from(m_data); } - // conversion to another be_t type - //template operator be_t() const - //{ - // return value(); - // //return _convert sizeof(T)) ? 1 : (sizeof(T1) < sizeof(T) ? 2 : 0))>::func(m_data); - //} + // access underlying raw data (don't use) + inline const stype& raw_data() const noexcept + { + return m_data; + } + + se_t& operator =(const se_t&) = default; - template be_t& operator +=(const T1& right) { return *this = value() + right; } - template be_t& operator -=(const T1& right) { return *this = value() - right; } - template be_t& operator *=(const T1& right) { return *this = value() * right; } - template be_t& operator /=(const T1& right) { return *this = value() / right; } - template be_t& operator %=(const T1& right) { return *this = value() % right; } + inline se_t& operator =(type value) + { + return m_data = storage::to(value), *this; + } - template be_t& operator <<=(const T1& right) { return *this = value() << right; } - template be_t& operator >>=(const T1& right) { return *this = value() >> right; } + inline operator type() const + { + return storage::from(m_data); + } - template be_t& operator &=(const T1& right) { return m_data &= be_t(right).data(), *this; } - template be_t& operator |=(const T1& right) { return m_data |= be_t(right).data(), *this; } - template be_t& operator ^=(const T1& right) { return m_data ^= be_t(right).data(), *this; } + // optimization + explicit inline operator bool() const + { + return bool_converter::to_bool(*this); + } - be_t operator ++(int) { be_t res = *this; *this += 1; return res; } - be_t operator --(int) { be_t res = *this; *this -= 1; return res; } - be_t& operator ++() { *this += 1; return *this; } - be_t& operator --() { *this -= 1; return *this; } + // optimization + template inline std::enable_if_t operator &=(const se_t& right) + { + return m_data &= right.raw_data(), *this; + } + + // optimization + template inline std::enable_if_t::value, se_t&> operator &=(CT right) + { + return m_data &= storage::to(right), *this; + } + + // optimization + template inline std::enable_if_t operator |=(const se_t& right) + { + return m_data |= right.raw_data(), *this; + } + + // optimization + template inline std::enable_if_t::value, se_t&> operator |=(CT right) + { + return m_data |= storage::to(right), *this; + } + + // optimization + template inline std::enable_if_t operator ^=(const se_t& right) + { + return m_data ^= right.raw_data(), *this; + } + + // optimization + template inline std::enable_if_t::value, se_t&> operator ^=(CT right) + { + return m_data ^= storage::to(right), *this; + } }; -template inline std::enable_if_t::value && std::is_integral::value, bool> operator ==(const be_t& left, const be_t& right) +// se_t with native endianness +template class se_t { - return left.data() == right.data(); + using type = std::remove_cv_t; + + type m_data; + + static_assert(!std::is_union::value && !std::is_class::value || std::is_same::value || std::is_same::value, "se_t<> error: invalid type (struct or union)"); + static_assert(!std::is_pointer::value, "se_t<> error: invalid type (pointer)"); + static_assert(!std::is_reference::value, "se_t<> error: invalid type (reference)"); + static_assert(!std::is_array::value, "se_t<> error: invalid type (array)"); + static_assert(!std::is_enum::value, "se_t<> error: invalid type (enumeration), use integral type instead"); + +public: + se_t() = default; + + se_t(const se_t&) = default; + + inline se_t(type value) + : m_data(value) + { + } + + inline type value() const + { + return m_data; + } + + se_t& operator =(const se_t& value) = default; + + inline se_t& operator =(type value) + { + return m_data = value, *this; + } + + inline operator type() const + { + return m_data; + } + + template inline std::enable_if_t::value, se_t&> operator &=(const CT& right) + { + return m_data &= right, *this; + } + + template inline std::enable_if_t::value, se_t&> operator |=(const CT& right) + { + return m_data |= right, *this; + } + + template inline std::enable_if_t::value, se_t&> operator ^=(const CT& right) + { + return m_data ^= right, *this; + } +}; + +// se_t with native endianness (alias) +template using nse_t = se_t; + +template inline se_t& operator +=(se_t& left, const T1& right) +{ + auto value = left.value(); + return left = (value += right); } -template inline std::enable_if_t::value && std::is_integral::value, bool> operator !=(const be_t& left, const be_t& right) +template inline se_t& operator -=(se_t& left, const T1& right) { - return left.data() != right.data(); + auto value = left.value(); + return left = (value -= right); } -template inline std::enable_if_t::value && std::is_integral::value, be_t> operator &(const be_t& left, const be_t& right) +template inline se_t& operator *=(se_t& left, const T1& right) { - be_t result; - result.m_data = left.data() & right.data(); + auto value = left.value(); + return left = (value *= right); +} + +template inline se_t& operator /=(se_t& left, const T1& right) +{ + auto value = left.value(); + return left = (value /= right); +} + +template inline se_t& operator %=(se_t& left, const T1& right) +{ + auto value = left.value(); + return left = (value %= right); +} + +template inline se_t& operator <<=(se_t& left, const T1& right) +{ + auto value = left.value(); + return left = (value <<= right); +} + +template inline se_t& operator >>=(se_t& left, const T1& right) +{ + auto value = left.value(); + return left = (value >>= right); +} + +template inline se_t operator ++(se_t& left, int) +{ + auto value = left.value(); + auto result = value++; + left = value; return result; } -template inline std::enable_if_t::value && std::is_integral::value, be_t> operator |(const be_t& left, const be_t& right) +template inline se_t operator --(se_t& left, int) { - be_t result; - result.m_data = left.data() | right.data(); + auto value = left.value(); + auto result = value--; + left = value; return result; } -template inline std::enable_if_t::value && std::is_integral::value, be_t> operator ^(const be_t& left, const be_t& right) +template inline se_t& operator ++(se_t& right) { - be_t result; - result.m_data = left.data() ^ right.data(); - return result; + auto value = right.value(); + return right = ++value; } -template inline std::enable_if_t::value, be_t> operator ~(const be_t& arg) +template inline se_t& operator --(se_t& right) { - be_t result; - result.m_data = ~arg.data(); - return result; + auto value = right.value(); + return right = --value; } +// optimization +template inline std::enable_if_t operator ==(const se_t& left, const se_t& right) +{ + return left.raw_data() == right.raw_data(); +} + +// optimization +template inline std::enable_if_t= sizeof(T2), bool> operator ==(const se_t& left, T2 right) +{ + return left.raw_data() == se_storage::to(right); +} + +// optimization +template inline std::enable_if_t operator ==(T1 left, const se_t& right) +{ + return se_storage::to(left) == right.raw_data(); +} + +// optimization +template inline std::enable_if_t operator !=(const se_t& left, const se_t& right) +{ + return left.raw_data() != right.raw_data(); +} + +// optimization +template inline std::enable_if_t= sizeof(T2), bool> operator !=(const se_t& left, T2 right) +{ + return left.raw_data() != se_storage::to(right); +} + +// optimization +template inline std::enable_if_t operator !=(T1 left, const se_t& right) +{ + return se_storage::to(left) != right.raw_data(); +} + +// optimization +template inline std::enable_if_t= 4, se_t> operator &(const se_t& left, const se_t& right) +{ + return{ left.raw_data() & right.raw_data(), se_raw }; +} + +// optimization +template inline std::enable_if_t= sizeof(T2) && sizeof(T1) >= 4, se_t> operator &(const se_t& left, T2 right) +{ + return{ left.raw_data() & se_storage::to(right), se_raw }; +} + +// optimization +template inline std::enable_if_t= 4, se_t> operator &(T1 left, const se_t& right) +{ + return{ se_storage::to(left) & right.raw_data(), se_raw }; +} + +// optimization +template inline std::enable_if_t= 4, se_t> operator |(const se_t& left, const se_t& right) +{ + return{ left.raw_data() | right.raw_data(), se_raw }; +} + +// optimization +template inline std::enable_if_t= sizeof(T2) && sizeof(T1) >= 4, se_t> operator |(const se_t& left, T2 right) +{ + return{ left.raw_data() | se_storage::to(right), se_raw }; +} + +// optimization +template inline std::enable_if_t= 4, se_t> operator |(T1 left, const se_t& right) +{ + return{ se_storage::to(left) | right.raw_data(), se_raw }; +} + +// optimization +template inline std::enable_if_t= 4, se_t> operator ^(const se_t& left, const se_t& right) +{ + return{ left.raw_data() ^ right.raw_data(), se_raw }; +} + +// optimization +template inline std::enable_if_t= sizeof(T2) && sizeof(T1) >= 4, se_t> operator ^(const se_t& left, T2 right) +{ + return{ left.raw_data() ^ se_storage::to(right), se_raw }; +} + +// optimization +template inline std::enable_if_t= 4, se_t> operator ^(T1 left, const se_t& right) +{ + return{ se_storage::to(left) ^ right.raw_data(), se_raw }; +} + +// optimization +template inline std::enable_if_t= 4, se_t> operator ~(const se_t& right) +{ + return{ ~right.raw_data(), se_raw }; +} + +#ifdef IS_LE_MACHINE +template using be_t = se_t; +template using le_t = se_t; +#else +template using be_t = se_t; +template using le_t = se_t; +#endif + template struct is_be_t : public std::integral_constant { }; @@ -692,21 +856,19 @@ template struct is_be_t : public std::integral_constant< // to_be_t helper struct template struct to_be { - using type = std::conditional_t::value || std::is_enum::value || std::is_same::value, be_t, T>; + using type = std::conditional_t::value || std::is_enum::value || std::is_same::value || std::is_same::value, be_t, T>; }; // be_t if possible, T otherwise template using to_be_t = typename to_be::type; -template struct to_be +template struct to_be // move const qualifier { - // move const qualifier using type = const to_be_t; }; -template struct to_be +template struct to_be // move volatile qualifier { - // move volatile qualifier using type = volatile to_be_t; }; @@ -716,79 +878,6 @@ template<> struct to_be { using type = char; }; template<> struct to_be { using type = u8; }; template<> struct to_be { using type = s8; }; -template class le_t -{ -public: - using type = std::remove_cv_t; - using stype = be_storage_t>; - - type m_data; // don't access directly - - static_assert(!std::is_class::value, "le_t<> error: invalid type (class or structure)"); - static_assert(!std::is_union::value || std::is_same::value, "le_t<> error: invalid type (union)"); - static_assert(!std::is_pointer::value, "le_t<> error: invalid type (pointer)"); - static_assert(!std::is_reference::value, "le_t<> error: invalid type (reference)"); - static_assert(!std::is_array::value, "le_t<> error: invalid type (array)"); - static_assert(!std::is_enum::value, "le_t<> error: invalid type (enumeration), use integral type instead"); - static_assert(__alignof(type) == __alignof(stype), "le_t<> error: unexpected alignment"); - - le_t() = default; - - le_t(const le_t&) = default; - - le_t(const type& value) - : m_data(value) - { - } - - type value() const - { - return m_data; - } - - const stype& data() const - { - return reinterpret_cast(m_data); - } - - le_t& operator =(const le_t& value) = default; - - template std::enable_if_t::value, le_t&> operator =(const CT& value) - { - m_data = value; - return *this; - } - - operator type() const - { - return value(); - } - - // conversion to another le_t type - //template operator le_t() const - //{ - // return value(); - //} - - template le_t& operator +=(const T1& right) { return *this = value() + right; } - template le_t& operator -=(const T1& right) { return *this = value() - right; } - template le_t& operator *=(const T1& right) { return *this = value() * right; } - template le_t& operator /=(const T1& right) { return *this = value() / right; } - template le_t& operator %=(const T1& right) { return *this = value() % right; } - - template le_t& operator <<=(const T1& right) { return *this = value() << right; } - template le_t& operator >>=(const T1& right) { return *this = value() >> right; } - - template le_t& operator &=(const T1& right) { return m_data &= le_t(right).data(), *this; } - template le_t& operator |=(const T1& right) { return m_data |= le_t(right).data(), *this; } - template le_t& operator ^=(const T1& right) { return m_data ^= le_t(right).data(), *this; } - - le_t operator ++(int) { le_t res = *this; *this += 1; return res; } - le_t operator --(int) { le_t res = *this; *this -= 1; return res; } - le_t& operator ++() { *this += 1; return *this; } - le_t& operator --() { *this -= 1; return *this; } -}; - template struct is_le_t : public std::integral_constant { }; @@ -807,21 +896,19 @@ template struct is_le_t : public std::integral_constant< template struct to_le { - using type = std::conditional_t::value || std::is_enum::value || std::is_same::value, le_t, T>; + using type = std::conditional_t::value || std::is_enum::value || std::is_same::value || std::is_same::value, le_t, T>; }; // le_t if possible, T otherwise template using to_le_t = typename to_le::type; -template struct to_le +template struct to_le // move const qualifier { - // move const qualifier using type = const to_le_t; }; -template struct to_le +template struct to_le // move volatile qualifier { - // move volatile qualifier using type = volatile to_le_t; }; @@ -837,12 +924,7 @@ template struct to_ne using type = T; }; -template struct to_ne> -{ - using type = T; -}; - -template struct to_ne> +template struct to_ne> { using type = T; }; @@ -850,14 +932,12 @@ template struct to_ne> // restore native endianness for T: returns T for be_t or le_t, T otherwise template using to_ne_t = typename to_ne::type; -template struct to_ne +template struct to_ne // move const qualifier { - // move const qualifier using type = const to_ne_t; }; -template struct to_ne +template struct to_ne // move volatile qualifier { - // move volatile qualifier using type = volatile to_ne_t; }; diff --git a/Utilities/GNU.h b/Utilities/GNU.h index d6e21fdf20..c8d5c74cb4 100644 --- a/Utilities/GNU.h +++ b/Utilities/GNU.h @@ -86,364 +86,152 @@ struct alignas(16) uint128_t { uint64_t lo, hi; - uint128_t& operator ++() + uint128_t() = default; + + uint128_t(uint64_t l) + : lo(l) + , hi(0) + { + } + + [[deprecated("Not implemented")]] inline uint128_t operator +(const uint128_t& r) const + { + return{}; + } + + inline uint128_t operator +(uint64_t r) const + { + uint128_t value; + value.lo = lo + r; + value.hi = value.lo < r ? hi + 1 : hi; + return value; + } + + [[deprecated("Not implemented")]] inline uint128_t operator -(const uint128_t& r) const + { + return{}; + } + + inline uint128_t operator -(uint64_t r) const + { + uint128_t value; + value.lo = lo - r; + value.hi = lo < r ? hi - 1 : hi; + return value; + } + + inline uint128_t operator +() const + { + return *this; + } + + inline uint128_t operator -() const + { + uint128_t value; + value.lo = ~lo + 1; + value.hi = lo ? ~hi : ~hi + 1; + return value; + } + + inline uint128_t& operator ++() { if (!++lo) ++hi; return *this; } - uint128_t& operator --() - { - if (!lo--) hi--; - return *this; - } - - uint128_t operator ++(int) + inline uint128_t operator ++(int) { uint128_t value = *this; if (!++lo) ++hi; return value; } - uint128_t operator --(int) + inline uint128_t& operator --() + { + if (!lo--) hi--; + return *this; + } + + inline uint128_t operator --(int) { uint128_t value = *this; if (!lo--) hi--; return value; } + + inline uint128_t operator ~() const + { + uint128_t value; + value.lo = ~lo; + value.hi = ~hi; + return value; + } + + inline uint128_t operator &(const uint128_t& r) const + { + uint128_t value; + value.lo = lo & r.lo; + value.hi = hi & r.hi; + return value; + } + + inline uint128_t operator |(const uint128_t& r) const + { + uint128_t value; + value.lo = lo | r.lo; + value.hi = hi | r.hi; + return value; + } + + inline uint128_t operator ^(const uint128_t& r) const + { + uint128_t value; + value.lo = lo ^ r.lo; + value.hi = hi ^ r.hi; + return value; + } + + [[deprecated("Not implemented")]] inline uint128_t& operator +=(const uint128_t& r) + { + return *this; + } + + inline uint128_t& operator +=(uint64_t r) + { + hi = (lo += r) < r ? hi + 1 : hi; + return *this; + } + + [[deprecated("Not implemented")]] inline uint128_t& operator -=(const uint128_t& r) + { + return *this; + } + + inline uint128_t& operator &=(const uint128_t& r) + { + lo &= r.lo; + hi &= r.hi; + return *this; + } + + inline uint128_t& operator |=(const uint128_t& r) + { + lo |= r.lo; + hi |= r.hi; + return *this; + } + + inline uint128_t& operator ^=(const uint128_t& r) + { + lo ^= r.lo; + hi ^= r.hi; + return *this; + } }; using __uint128_t = uint128_t; #endif -// SFINAE Helper type -template using if_integral_t = std::enable_if_t::value || std::is_same, __uint128_t>::value, TT>; - -#if defined(__GNUG__) - -template inline if_integral_t sync_val_compare_and_swap(volatile T* dest, T2 comp, T2 exch) -{ - return __sync_val_compare_and_swap(dest, comp, exch); -} - -template inline if_integral_t sync_bool_compare_and_swap(volatile T* dest, T2 comp, T2 exch) -{ - return __sync_bool_compare_and_swap(dest, comp, exch); -} - -template inline if_integral_t sync_lock_test_and_set(volatile T* dest, T2 value) -{ - return __sync_lock_test_and_set(dest, value); -} - -template inline if_integral_t sync_fetch_and_add(volatile T* dest, T2 value) -{ - return __sync_fetch_and_add(dest, value); -} - -template inline if_integral_t sync_fetch_and_sub(volatile T* dest, T2 value) -{ - return __sync_fetch_and_sub(dest, value); -} - -template inline if_integral_t sync_fetch_and_or(volatile T* dest, T2 value) -{ - return __sync_fetch_and_or(dest, value); -} - -template inline if_integral_t sync_fetch_and_and(volatile T* dest, T2 value) -{ - return __sync_fetch_and_and(dest, value); -} - -template inline if_integral_t sync_fetch_and_xor(volatile T* dest, T2 value) -{ - return __sync_fetch_and_xor(dest, value); -} - -#endif /* __GNUG__ */ - -#if defined(_MSC_VER) - -// atomic compare and swap functions - -inline uint8_t sync_val_compare_and_swap(volatile uint8_t* dest, uint8_t comp, uint8_t exch) -{ - return _InterlockedCompareExchange8((volatile char*)dest, exch, comp); -} - -inline uint16_t sync_val_compare_and_swap(volatile uint16_t* dest, uint16_t comp, uint16_t exch) -{ - return _InterlockedCompareExchange16((volatile short*)dest, exch, comp); -} - -inline uint32_t sync_val_compare_and_swap(volatile uint32_t* dest, uint32_t comp, uint32_t exch) -{ - return _InterlockedCompareExchange((volatile long*)dest, exch, comp); -} - -inline uint64_t sync_val_compare_and_swap(volatile uint64_t* dest, uint64_t comp, uint64_t exch) -{ - return _InterlockedCompareExchange64((volatile long long*)dest, exch, comp); -} - -inline uint128_t sync_val_compare_and_swap(volatile uint128_t* dest, uint128_t comp, uint128_t exch) -{ - _InterlockedCompareExchange128((volatile long long*)dest, exch.hi, exch.lo, (long long*)&comp); - return comp; -} - -inline bool sync_bool_compare_and_swap(volatile uint8_t* dest, uint8_t comp, uint8_t exch) -{ - return (uint8_t)_InterlockedCompareExchange8((volatile char*)dest, exch, comp) == comp; -} - -inline bool sync_bool_compare_and_swap(volatile uint16_t* dest, uint16_t comp, uint16_t exch) -{ - return (uint16_t)_InterlockedCompareExchange16((volatile short*)dest, exch, comp) == comp; -} - -inline bool sync_bool_compare_and_swap(volatile uint32_t* dest, uint32_t comp, uint32_t exch) -{ - return (uint32_t)_InterlockedCompareExchange((volatile long*)dest, exch, comp) == comp; -} - -inline bool sync_bool_compare_and_swap(volatile uint64_t* dest, uint64_t comp, uint64_t exch) -{ - return (uint64_t)_InterlockedCompareExchange64((volatile long long*)dest, exch, comp) == comp; -} - -inline bool sync_bool_compare_and_swap(volatile uint128_t* dest, uint128_t comp, uint128_t exch) -{ - return _InterlockedCompareExchange128((volatile long long*)dest, exch.hi, exch.lo, (long long*)&comp) != 0; -} - -// atomic exchange functions - -inline uint8_t sync_lock_test_and_set(volatile uint8_t* dest, uint8_t value) -{ - return _InterlockedExchange8((volatile char*)dest, value); -} - -inline uint16_t sync_lock_test_and_set(volatile uint16_t* dest, uint16_t value) -{ - return _InterlockedExchange16((volatile short*)dest, value); -} - -inline uint32_t sync_lock_test_and_set(volatile uint32_t* dest, uint32_t value) -{ - return _InterlockedExchange((volatile long*)dest, value); -} - -inline uint64_t sync_lock_test_and_set(volatile uint64_t* dest, uint64_t value) -{ - return _InterlockedExchange64((volatile long long*)dest, value); -} - -inline uint128_t sync_lock_test_and_set(volatile uint128_t* dest, uint128_t value) -{ - while (true) - { - uint128_t old; - old.lo = dest->lo; - old.hi = dest->hi; - - if (sync_bool_compare_and_swap(dest, old, value)) return old; - } -} - -// atomic add functions - -inline uint8_t sync_fetch_and_add(volatile uint8_t* dest, uint8_t value) -{ - return _InterlockedExchangeAdd8((volatile char*)dest, value); -} - -inline uint16_t sync_fetch_and_add(volatile uint16_t* dest, uint16_t value) -{ - return _InterlockedExchangeAdd16((volatile short*)dest, value); -} - -inline uint32_t sync_fetch_and_add(volatile uint32_t* dest, uint32_t value) -{ - return _InterlockedExchangeAdd((volatile long*)dest, value); -} - -inline uint64_t sync_fetch_and_add(volatile uint64_t* dest, uint64_t value) -{ - return _InterlockedExchangeAdd64((volatile long long*)dest, value); -} - -inline uint128_t sync_fetch_and_add(volatile uint128_t* dest, uint128_t value) -{ - while (true) - { - uint128_t old; - old.lo = dest->lo; - old.hi = dest->hi; - - uint128_t _new; - _new.lo = old.lo + value.lo; - _new.hi = old.hi + value.hi + (_new.lo < value.lo); - - if (sync_bool_compare_and_swap(dest, old, _new)) return old; - } -} - -// atomic sub functions - -inline uint8_t sync_fetch_and_sub(volatile uint8_t* dest, uint8_t value) -{ - return _InterlockedExchangeAdd8((volatile char*)dest, -(char)value); -} - -inline uint16_t sync_fetch_and_sub(volatile uint16_t* dest, uint16_t value) -{ - return _InterlockedExchangeAdd16((volatile short*)dest, -(short)value); -} - -inline uint32_t sync_fetch_and_sub(volatile uint32_t* dest, uint32_t value) -{ - return _InterlockedExchangeAdd((volatile long*)dest, -(long)value); -} - -inline uint64_t sync_fetch_and_sub(volatile uint64_t* dest, uint64_t value) -{ - return _InterlockedExchangeAdd64((volatile long long*)dest, -(long long)value); -} - -inline uint128_t sync_fetch_and_sub(volatile uint128_t* dest, uint128_t value) -{ - while (true) - { - uint128_t old; - old.lo = dest->lo; - old.hi = dest->hi; - - uint128_t _new; - _new.lo = old.lo - value.lo; - _new.hi = old.hi - value.hi - (old.lo < value.lo); - - if (sync_bool_compare_and_swap(dest, old, _new)) return old; - } -} - -// atomic `bitwise or` functions - -inline uint8_t sync_fetch_and_or(volatile uint8_t* dest, uint8_t value) -{ - return _InterlockedOr8((volatile char*)dest, value); -} - -inline uint16_t sync_fetch_and_or(volatile uint16_t* dest, uint16_t value) -{ - return _InterlockedOr16((volatile short*)dest, value); -} - -inline uint32_t sync_fetch_and_or(volatile uint32_t* dest, uint32_t value) -{ - return _InterlockedOr((volatile long*)dest, value); -} - -inline uint64_t sync_fetch_and_or(volatile uint64_t* dest, uint64_t value) -{ - return _InterlockedOr64((volatile long long*)dest, value); -} - -inline uint128_t sync_fetch_and_or(volatile uint128_t* dest, uint128_t value) -{ - while (true) - { - uint128_t old; - old.lo = dest->lo; - old.hi = dest->hi; - - uint128_t _new; - _new.lo = old.lo | value.lo; - _new.hi = old.hi | value.hi; - - if (sync_bool_compare_and_swap(dest, old, _new)) return old; - } -} - -// atomic `bitwise and` functions - -inline uint8_t sync_fetch_and_and(volatile uint8_t* dest, uint8_t value) -{ - return _InterlockedAnd8((volatile char*)dest, value); -} - -inline uint16_t sync_fetch_and_and(volatile uint16_t* dest, uint16_t value) -{ - return _InterlockedAnd16((volatile short*)dest, value); -} - -inline uint32_t sync_fetch_and_and(volatile uint32_t* dest, uint32_t value) -{ - return _InterlockedAnd((volatile long*)dest, value); -} - -inline uint64_t sync_fetch_and_and(volatile uint64_t* dest, uint64_t value) -{ - return _InterlockedAnd64((volatile long long*)dest, value); -} - -inline uint128_t sync_fetch_and_and(volatile uint128_t* dest, uint128_t value) -{ - while (true) - { - uint128_t old; - old.lo = dest->lo; - old.hi = dest->hi; - - uint128_t _new; - _new.lo = old.lo & value.lo; - _new.hi = old.hi & value.hi; - - if (sync_bool_compare_and_swap(dest, old, _new)) return old; - } -} - -// atomic `bitwise xor` functions - -inline uint8_t sync_fetch_and_xor(volatile uint8_t* dest, uint8_t value) -{ - return _InterlockedXor8((volatile char*)dest, value); -} - -inline uint16_t sync_fetch_and_xor(volatile uint16_t* dest, uint16_t value) -{ - return _InterlockedXor16((volatile short*)dest, value); -} - -inline uint32_t sync_fetch_and_xor(volatile uint32_t* dest, uint32_t value) -{ - return _InterlockedXor((volatile long*)dest, value); -} - -inline uint64_t sync_fetch_and_xor(volatile uint64_t* dest, uint64_t value) -{ - return _InterlockedXor64((volatile long long*)dest, value); -} - -inline uint128_t sync_fetch_and_xor(volatile uint128_t* dest, uint128_t value) -{ - while (true) - { - uint128_t old; - old.lo = dest->lo; - old.hi = dest->hi; - - uint128_t _new; - _new.lo = old.lo ^ value.lo; - _new.hi = old.hi ^ value.hi; - - if (sync_bool_compare_and_swap(dest, old, _new)) return old; - } -} - -#endif /* _MSC_VER */ - inline uint32_t cntlz32(uint32_t arg) { #if defined(_MSC_VER) diff --git a/Utilities/Interval.h b/Utilities/Interval.h index bc8009c743..120edcb073 100644 --- a/Utilities/Interval.h +++ b/Utilities/Interval.h @@ -1,42 +1,32 @@ #pragma once -template -struct BaseInterval +template struct range_t { - static const uint64_t zero = 0ull; - static const uint64_t notz = 0xffffffffffffffffull; + T1 _min; // first value + T2 _max; // second value +}; - T m_min, m_max; +template constexpr range_t, std::decay_t> make_range(T1&& _min, T2&& _max) +{ + return{ std::forward(_min), std::forward(_max) }; +} - static BaseInterval make(T min_value, T max_value) - { - BaseInterval res = { min_value, max_value }; - return res; - } +template constexpr bool operator <(const range_t& range, const T& value) +{ + return range._min < value && range._max < value; +} - static BaseInterval make() - { - return make((T&)zero, (T&)notz); - } +template constexpr bool operator <(const T& value, const range_t& range) +{ + return value < range._min && value < range._max; +} - bool getconst(T& result) - { - if (m_min == m_max) - { - result = m_min; - return true; - } - else - { - return false; - } - } +template constexpr bool operator ==(const range_t& range, const T& value) +{ + return !(value < range._min) && !(range._max < value); +} - bool isindef() - { - if (T == float) - { - - } - } -}; \ No newline at end of file +template constexpr bool operator ==(const T& value, const range_t& range) +{ + return !(value < range._min) && !(range._max < value); +} diff --git a/Utilities/Semaphore.h b/Utilities/Semaphore.h index 03d3a77168..8ed96f4275 100644 --- a/Utilities/Semaphore.h +++ b/Utilities/Semaphore.h @@ -22,7 +22,7 @@ public: const u32 max_value; semaphore_t(u32 max_value = 1, u32 value = 0) - : m_var({ value, 0 }) + : m_var(sync_var_t{ value, 0 }) , max_value(max_value) { } diff --git a/Utilities/SharedMutex.cpp b/Utilities/SharedMutex.cpp new file mode 100644 index 0000000000..9394fde020 --- /dev/null +++ b/Utilities/SharedMutex.cpp @@ -0,0 +1,152 @@ +#include "stdafx.h" +#include "SharedMutex.h" + +static const u32 MAX_READERS = 0x7fffffff; // 2^31-1 + +inline bool shared_mutex_t::try_lock_shared() +{ + return m_info.atomic_op([](ownership_info_t& info) -> bool + { + if (info.readers < MAX_READERS && !info.writers && !info.waiting_readers && !info.waiting_writers) + { + info.readers++; + return true; + } + + return false; + }); +} + +void shared_mutex_t::lock_shared() +{ + if (!try_lock_shared()) + { + std::unique_lock lock(m_mutex); + + m_wrcv.wait(lock, WRAP_EXPR(m_info.atomic_op([](ownership_info_t& info) -> bool + { + if (info.waiting_readers < UINT16_MAX) + { + info.waiting_readers++; + return true; + } + + return false; + }))); + + m_rcv.wait(lock, WRAP_EXPR(m_info.atomic_op([](ownership_info_t& info) -> bool + { + if (!info.writers && !info.waiting_writers && info.readers < MAX_READERS) + { + info.readers++; + return true; + } + + return false; + }))); + + const auto info = m_info.atomic_op([](ownership_info_t& info) + { + if (!info.waiting_readers--) + { + throw EXCEPTION("Invalid value"); + } + }); + + if (info.waiting_readers == UINT16_MAX) + { + m_wrcv.notify_one(); + } + } +} + +void shared_mutex_t::unlock_shared() +{ + const auto info = m_info.atomic_op([](ownership_info_t& info) + { + if (!info.readers--) + { + throw EXCEPTION("Not locked"); + } + }); + + const bool notify_writers = info.readers == 1 && info.writers; + const bool notify_readers = info.readers == UINT32_MAX && info.waiting_readers; + + if (notify_writers || notify_readers) + { + std::lock_guard lock(m_mutex); + + if (notify_writers) m_wcv.notify_one(); + if (notify_readers) m_rcv.notify_one(); + } +} + +inline bool shared_mutex_t::try_lock() +{ + return m_info.compare_and_swap_test({ 0, 0, 0, 0 }, { 0, 1, 0, 0 }); +} + +void shared_mutex_t::lock() +{ + if (!try_lock()) + { + std::unique_lock lock(m_mutex); + + m_wwcv.wait(lock, WRAP_EXPR(m_info.atomic_op([](ownership_info_t& info) -> bool + { + if (info.waiting_writers < UINT16_MAX) + { + info.waiting_writers++; + return true; + } + + return false; + }))); + + m_wcv.wait(lock, WRAP_EXPR(m_info.atomic_op([](ownership_info_t& info) -> bool + { + if (!info.writers) + { + info.writers++; + return true; + } + + return false; + }))); + + m_wcv.wait(lock, WRAP_EXPR(m_info.load().readers == 0)); + + const auto info = m_info.atomic_op([](ownership_info_t& info) + { + if (!info.waiting_writers--) + { + throw EXCEPTION("Invalid value"); + } + }); + + if (info.waiting_writers == UINT16_MAX) + { + m_wwcv.notify_one(); + } + } +} + +void shared_mutex_t::unlock() +{ + const auto info = m_info.atomic_op([](ownership_info_t& info) + { + if (!info.writers--) + { + throw EXCEPTION("Not locked"); + } + }); + + if (info.waiting_writers || info.waiting_readers) + { + std::lock_guard lock(m_mutex); + + if (info.waiting_writers) m_wcv.notify_one(); + else if (info.waiting_readers) m_rcv.notify_all(); + } +} diff --git a/Utilities/SharedMutex.h b/Utilities/SharedMutex.h new file mode 100644 index 0000000000..82d38c1ee7 --- /dev/null +++ b/Utilities/SharedMutex.h @@ -0,0 +1,46 @@ +#pragma once + +#include + +// An attempt to create lock-free (in optimistic case) implementation similar to std::shared_mutex; +// MSVC implementation of std::shared_timed_mutex is not lock-free and thus may be slow, and std::shared_mutex is not available. +class shared_mutex_t +{ + struct ownership_info_t + { + u32 readers : 31; + u32 writers : 1; + u16 waiting_readers; + u16 waiting_writers; + }; + + atomic_t m_info{}; + + std::mutex m_mutex; + + std::condition_variable m_rcv; + std::condition_variable m_wcv; + std::condition_variable m_wrcv; + std::condition_variable m_wwcv; + +public: + shared_mutex_t() = default; + + // Lock in shared mode + void lock_shared(); + + // Try to lock in shared mode + bool try_lock_shared(); + + // Unlock in shared mode + void unlock_shared(); + + // Lock exclusively + void lock(); + + // Try to lock exclusively + bool try_lock(); + + // Unlock exclusively + void unlock(); +}; diff --git a/Utilities/StrFmt.h b/Utilities/StrFmt.h index 8465ad0612..02111b9db2 100644 --- a/Utilities/StrFmt.h +++ b/Utilities/StrFmt.h @@ -145,8 +145,7 @@ namespace fmt std::string to_udec(u64 value); std::string to_sdec(s64 value); - template::value> - struct unveil + template::value> struct unveil { using result_type = T; @@ -156,8 +155,7 @@ namespace fmt } }; - template<> - struct unveil + template<> struct unveil { using result_type = const char*; @@ -167,8 +165,7 @@ namespace fmt } }; - template - struct unveil + template struct unveil { using result_type = const char*; @@ -178,8 +175,7 @@ namespace fmt } }; - template<> - struct unveil + template<> struct unveil { using result_type = const char*; @@ -189,8 +185,7 @@ namespace fmt } }; - template - struct unveil + template struct unveil { using result_type = std::underlying_type_t; @@ -200,25 +195,13 @@ namespace fmt } }; - template - struct unveil, false> + template struct unveil, false> { using result_type = typename unveil::result_type; - force_inline static result_type get_value(const be_t& arg) + force_inline static result_type get_value(const se_t& arg) { - return unveil::get_value(arg.value()); - } - }; - - template - struct unveil, false> - { - using result_type = typename unveil::result_type; - - force_inline static result_type get_value(const le_t& arg) - { - return unveil::get_value(arg.value()); + return unveil::get_value(arg); } }; @@ -270,11 +253,11 @@ namespace fmt } } - struct exception + struct exception : public std::exception { std::unique_ptr message; - template never_inline safe_buffers exception(const char* file, int line, const char* func, const char* text, Args... args) + template never_inline safe_buffers exception(const char* file, int line, const char* func, const char* text, Args... args) noexcept { const std::string data = format(text, args...) + format("\n(in file %s:%d, in function %s)", file, line, func); @@ -283,16 +266,16 @@ namespace fmt std::memcpy(message.get(), data.c_str(), data.size() + 1); } - exception(const exception& other) + exception(const exception& other) noexcept { - const std::size_t size = std::strlen(other); + const std::size_t size = std::strlen(other.message.get()); message.reset(new char[size + 1]); - std::memcpy(message.get(), other, size + 1); + std::memcpy(message.get(), other.message.get(), size + 1); } - operator const char*() const + virtual const char* what() const noexcept override { return message.get(); } diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index bdc740374a..100bf3d7e4 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -1121,6 +1121,8 @@ void _se_translator(unsigned int u, EXCEPTION_POINTERS* pExp) { throw EXCEPTION("Access violation %s location 0x%llx", is_writing ? "writing" : "reading", addr64); } + + //__int2c(); // if it crashed there, check the callstack for the actual source of the crash } const PVOID exception_handler = (atexit([]{ RemoveVectoredExceptionHandler(exception_handler); }), AddVectoredExceptionHandler(1, [](PEXCEPTION_POINTERS pExp) -> LONG @@ -1281,14 +1283,9 @@ void named_thread_t::start(std::function name, std::function& test_exit) diff --git a/rpcs3/Crypto/unpkg.cpp b/rpcs3/Crypto/unpkg.cpp index fe2ce08277..5a0dcd62aa 100644 --- a/rpcs3/Crypto/unpkg.cpp +++ b/rpcs3/Crypto/unpkg.cpp @@ -6,13 +6,6 @@ #include "sha1.h" #include "key_vault.h" #include "unpkg.h" -#include "restore_new.h" -#pragma warning(push) -#pragma message("TODO: remove wx dependency: ") -#pragma warning(disable : 4996) -#include -#pragma warning(pop) -#include "define_new_memleakdetect.h" static bool CheckHeader(const fs::file& pkg_f, PKGHeader& header) { @@ -66,7 +59,7 @@ static bool CheckHeader(const fs::file& pkg_f, PKGHeader& header) } // PKG Decryption -bool Unpack(const fs::file& pkg_f, std::string dir) +bool UnpackPKG(const fs::file& pkg_f, const std::string& dir, volatile f64& progress) { // Save current file offset (probably zero) const u64 start_offset = pkg_f.seek(0, fsm::cur); @@ -85,75 +78,78 @@ bool Unpack(const fs::file& pkg_f, std::string dir) return false; } - aes_context c; - - u8 iv[HASH_LEN]; - be_t& hi = (be_t&)iv[0]; - be_t& lo = (be_t&)iv[8]; - - // Allocate buffers with BUF_SIZE size or more if required - const u64 buffer_size = std::max(BUF_SIZE, sizeof(PKGEntry) * header.file_count); - - const std::unique_ptr buf(new u8[buffer_size]), ctr(new u8[buffer_size]); - - // Debug key - u8 key[0x40] = {}; - memcpy(key + 0x00, &header.qa_digest[0], 8); // &data[0x60] - memcpy(key + 0x08, &header.qa_digest[0], 8); // &data[0x60] - memcpy(key + 0x10, &header.qa_digest[8], 8); // &data[0x68] - memcpy(key + 0x18, &header.qa_digest[8], 8); // &data[0x68] + // Allocate buffer with BUF_SIZE size or more if required + const std::unique_ptr buf(new u128[std::max(BUF_SIZE, sizeof(PKGEntry) * header.file_count) / sizeof(u128)]); // Define decryption subfunction (`psp` arg selects the key for specific block) - auto decrypt = [&](u64 offset, u64 size, bool psp) + auto decrypt = [&](u64 offset, u64 size, bool psp) -> u64 { - // Initialize buffer - std::memset(buf.get(), 0, size); - - // Read the data pkg_f.seek(start_offset + header.data_offset + offset); - size = pkg_f.read(buf.get(), size); - const u64 bits = (size + HASH_LEN - 1) / HASH_LEN; + + // Read the data and set available size + const u64 read = pkg_f.read(buf.get(), size); + + // Get block count + const u64 blocks = (read + 15) / 16; if (header.pkg_type == PKG_RELEASE_TYPE_DEBUG) { - for (u64 j = 0; j < bits; j++) + // Debug key + be_t input[8] = { - u8 hash[0x14]; - sha1(key, 0x40, hash); - *(u64*)&buf[j * HASH_LEN + 0] ^= *(u64*)&hash[0]; - *(u64*)&buf[j * HASH_LEN + 8] ^= *(u64*)&hash[8]; - *(be_t*)&key[0x38] += 1; + header.qa_digest[0], + header.qa_digest[0], + header.qa_digest[1], + header.qa_digest[1], + }; + + for (u64 i = 0; i < blocks; i++) + { + // Initialize "debug key" for current position + input[7] = offset / 16 + i; + + union + { + u8 _key[0x14]; + u128 key; + }; + + sha1(reinterpret_cast(input), sizeof(input), _key); + + buf[i] ^= key; } } if (header.pkg_type == PKG_RELEASE_TYPE_RELEASE) { + aes_context ctx; + // Set decryption key - aes_setkey_enc(&c, psp ? PKG_AES_KEY2 : PKG_AES_KEY, 128); + aes_setkey_enc(&ctx, psp ? PKG_AES_KEY2 : PKG_AES_KEY, 128); - // Initialize `iv` for the specific position - memcpy(iv, header.klicensee, sizeof(iv)); - if (lo + offset / HASH_LEN < lo) hi++; - lo += offset / HASH_LEN; + // Initialize "release key" for start position + be_t input = header.klicensee.value() + offset / 16; - for (u64 j = 0; j < bits; j++) + // Increment "release key" for every block + for (u64 i = 0; i < blocks; i++, input++) { - aes_crypt_ecb(&c, AES_ENCRYPT, iv, ctr.get() + j * HASH_LEN); - - if (!++lo) + union { - hi++; - } - } + u8 _key[16]; + u128 key; + }; - for (u64 j = 0; j < size; j++) - { - buf[j] ^= ctr[j]; + aes_crypt_ecb(&ctx, AES_ENCRYPT, reinterpret_cast(&input), _key); + + buf[i] ^= key; } } + + // Return the amount of data written in buf + return read; }; - wxProgressDialog pdlg("PKG Decrypter / Installer", "Please wait, decrypting...", header.file_count, 0, wxPD_AUTO_HIDE | wxPD_APP_MODAL); + LOG_SUCCESS(LOADER, "PKG: Installing in %s (%d entries)...", dir, header.file_count); decrypt(0, header.file_count * sizeof(PKGEntry), header.pkg_platform == PKG_PLATFORM_TYPE_PSP); @@ -161,12 +157,16 @@ bool Unpack(const fs::file& pkg_f, std::string dir) std::memcpy(entries.data(), buf.get(), entries.size() * sizeof(PKGEntry)); - for (s32 i = 0; i < entries.size(); i++) + for (const auto& entry : entries) { - const PKGEntry& entry = entries[i]; - const bool is_psp = (entry.type & PKG_FILE_ENTRY_PSP) != 0; + if (entry.name_size > 256) + { + LOG_ERROR(LOADER, "PKG: Name size is too big (0x%x)", entry.name_size); + continue; + } + decrypt(entry.name_offset, entry.name_size, is_psp); const std::string name(reinterpret_cast(buf.get()), entry.name_size); @@ -181,10 +181,7 @@ bool Unpack(const fs::file& pkg_f, std::string dir) { const std::string path = dir + name; - if (fs::is_file(path)) - { - LOG_WARNING(LOADER, "PKG Loader: '%s' is overwritten", path); - } + const bool did_overwrite = fs::is_file(path); if (fs::file out{ path, fom::write | fom::create | fom::trunc }) { @@ -192,15 +189,33 @@ bool Unpack(const fs::file& pkg_f, std::string dir) { const u64 block_size = std::min(BUF_SIZE, entry.file_size - pos); - decrypt(entry.file_offset + pos, block_size, is_psp); + if (decrypt(entry.file_offset + pos, block_size, is_psp) != block_size) + { + LOG_ERROR(LOADER, "PKG: Failed to extract file %s", path); + break; + } - out.write(buf.get(), block_size); + if (out.write(buf.get(), block_size) != block_size) + { + LOG_ERROR(LOADER, "PKG: Failed to write file %s", path); + break; + } + + progress += (block_size + 0.0) / header.data_size; + } + + if (did_overwrite) + { + LOG_SUCCESS(LOADER, "PKG: %s file overwritten", name); + } + else + { + LOG_SUCCESS(LOADER, "PKG: %s file created", name); } } else { - LOG_ERROR(LOADER, "PKG Loader: Could not create file '%s'", path); - return false; + LOG_ERROR(LOADER, "PKG: Could not create file %s", path); } break; @@ -210,10 +225,17 @@ bool Unpack(const fs::file& pkg_f, std::string dir) { const std::string path = dir + name; - if (!fs::is_dir(path) && !fs::create_dir(path)) + if (fs::create_dir(path)) { - LOG_ERROR(LOADER, "PKG Loader: Could not create directory: %s", path); - return false; + LOG_SUCCESS(LOADER, "PKG: %s directory created", name); + } + else if (fs::is_dir(path)) + { + LOG_SUCCESS(LOADER, "PKG: %s directory already exists", name); + } + else + { + LOG_ERROR(LOADER, "PKG: Could not create directory %s", path); } break; @@ -221,12 +243,9 @@ bool Unpack(const fs::file& pkg_f, std::string dir) default: { - LOG_ERROR(LOADER, "PKG Loader: unknown PKG file entry: 0x%x", entry.type); - return false; + LOG_ERROR(LOADER, "PKG: Unknown PKG entry type (0x%x) %s", entry.type, name); } } - - pdlg.Update(i + 1); } return true; diff --git a/rpcs3/Crypto/unpkg.h b/rpcs3/Crypto/unpkg.h index e973e892ef..4983525ebf 100644 --- a/rpcs3/Crypto/unpkg.h +++ b/rpcs3/Crypto/unpkg.h @@ -3,8 +3,7 @@ // Constants enum { - HASH_LEN = 16, - BUF_SIZE = 8192 * 1024, + BUF_SIZE = 8192 * 1024, // 8 MB PKG_HEADER_SIZE = 0xC0, //sizeof(pkg_header) + sizeof(pkg_unk_checksum) PKG_HEADER_SIZE2 = 0x280, }; @@ -45,8 +44,8 @@ struct PKGHeader be_t data_offset; // Encrypted data offset be_t data_size; // Encrypted data size in bytes char title_id[48]; // Title ID - u8 qa_digest[16]; // This should be the hash of "files + attribs" - u8 klicensee[16]; // Nonce + be_t qa_digest[2]; // This should be the hash of "files + attribs" + be_t klicensee; // Nonce }; struct PKGEntry @@ -59,6 +58,4 @@ struct PKGEntry be_t pad; // Padding (zeros) }; -namespace fs { struct file; } - -bool Unpack(const fs::file& pkg_f, std::string dir); +bool UnpackPKG(const struct fs::file& pkg_f, const std::string& dir, volatile f64& progress); diff --git a/rpcs3/Emu/ARMv7/ARMv7Thread.cpp b/rpcs3/Emu/ARMv7/ARMv7Thread.cpp index 3f72c08dcd..fd9c4ba632 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Thread.cpp +++ b/rpcs3/Emu/ARMv7/ARMv7Thread.cpp @@ -28,7 +28,7 @@ void armv7_init_tls() for (auto& v : g_armv7_tls_owners) { - v.store(0, std::memory_order_relaxed); + v = 0; } } @@ -53,8 +53,8 @@ u32 armv7_get_tls(u32 thread) if (g_armv7_tls_owners[i].compare_exchange_strong(old, thread)) { const u32 addr = g_armv7_tls_start + i * Emu.GetTLSMemsz(); // get TLS address - memcpy(vm::get_ptr(addr), vm::get_ptr(Emu.GetTLSAddr()), Emu.GetTLSFilesz()); // initialize from TLS image - memset(vm::get_ptr(addr + Emu.GetTLSFilesz()), 0, Emu.GetTLSMemsz() - Emu.GetTLSFilesz()); // fill the rest with zeros + std::memcpy(vm::get_ptr(addr), vm::get_ptr(Emu.GetTLSAddr()), Emu.GetTLSFilesz()); // initialize from TLS image + std::memset(vm::get_ptr(addr + Emu.GetTLSFilesz()), 0, Emu.GetTLSMemsz() - Emu.GetTLSFilesz()); // fill the rest with zeros return addr; } } @@ -195,15 +195,13 @@ void ARMv7Thread::task() { if (custom_task) { - if (m_state.load() && check_status()) return; + if (check_status()) return; return custom_task(*this); } - while (true) + while (!m_state || !check_status()) { - if (m_state.load() && check_status()) break; - // decode instruction using specified decoder PC += m_dec->DecodeMemory(PC); } diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp index d97165b960..eb403ddf9f 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp @@ -116,12 +116,7 @@ s32 sceKernelExitDeleteThread(ARMv7Thread& context, s32 exitStatus) context.stop(); // current thread should be deleted - const u32 id = context.get_id(); - - CallAfter([id]() - { - idm::remove(id); - }); + idm::remove(context.get_id()); return SCE_OK; } @@ -494,7 +489,7 @@ s32 sceKernelWaitEventFlag(ARMv7Thread& context, s32 evfId, u32 bitPattern, u32 if (passed >= timeout) { context.GPR[0] = SCE_KERNEL_ERROR_WAIT_TIMEOUT; - context.GPR[1] = evf->pattern.load(); + context.GPR[1] = evf->pattern; break; } @@ -629,7 +624,7 @@ s32 sceKernelCancelEventFlag(s32 evfId, u32 setPattern, vm::ptr pNumWaitThr *pNumWaitThreads = static_cast(evf->sq.size()); - evf->pattern.store(setPattern); + evf->pattern = setPattern; evf->sq.clear(); return SCE_OK; @@ -655,7 +650,7 @@ s32 sceKernelGetEventFlagInfo(s32 evfId, vm::ptr pInfo) pInfo->attr = evf->attr; pInfo->initPattern = evf->init; - pInfo->currentPattern = evf->pattern.load(); + pInfo->currentPattern = evf->pattern; pInfo->numWaitThreads = static_cast(evf->sq.size()); return SCE_OK; diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibKernel.h b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.h index 05e7968852..1ba6f3a4ca 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibKernel.h +++ b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.h @@ -464,8 +464,8 @@ struct psv_event_flag_t : name(name) , attr(attr) , init(pattern) + , pattern(pattern) { - this->pattern.store(pattern); } // Wakeup all waiters to return SCE_KERNEL_ERROR_WAIT_DELETE @@ -473,7 +473,7 @@ struct psv_event_flag_t { std::lock_guard lock(mutex); - const u32 pattern = this->pattern.load(); + const u32 pattern = this->pattern; for (auto& thread : sq) { @@ -550,8 +550,8 @@ struct psv_semaphore_t : name(name) , attr(attr) , max(max) + , count(count) { - this->count.store(count); } }; @@ -588,8 +588,8 @@ struct psv_mutex_t psv_mutex_t(const char* name, u32 attr, s32 count) : name(name) , attr(attr) + , count(count) { - this->count.store(count); } }; diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp b/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp index 274824bba4..bac1572107 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp @@ -188,7 +188,7 @@ namespace sce_libc_func sceLibc.Success("Process finished"); - CallAfter([]() + Emu.CallAfter([]() { Emu.Stop(); }); diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index 035c911382..7cc5ba39e5 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -4,20 +4,18 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/DbgCommand.h" #include "CPUDecoder.h" #include "CPUThread.h" CPUThread::CPUThread(CPUThreadType type, const std::string& name, std::function thread_name) - : m_state({ CPU_STATE_STOPPED }) - , m_id(idm::get_last_id()) + : m_id(idm::get_last_id()) , m_type(type) , m_name(name) { start(std::move(thread_name), [this] { - SendDbgCommand(DID_CREATE_THREAD, this); + Emu.SendDbgCommand(DID_CREATE_THREAD, this); std::unique_lock lock(mutex); @@ -71,12 +69,12 @@ CPUThread::CPUThread(CPUThreadType type, const std::string& name, std::function< CPUThread::~CPUThread() { - SendDbgCommand(DID_REMOVE_THREAD, this); + Emu.SendDbgCommand(DID_REMOVE_THREAD, this); } bool CPUThread::is_paused() const { - return (m_state.load() & CPU_STATE_PAUSED) != 0 || Emu.IsPaused(); + return (m_state & CPU_STATE_PAUSED) != 0 || Emu.IsPaused(); } void CPUThread::dump_info() const @@ -89,27 +87,27 @@ void CPUThread::dump_info() const void CPUThread::run() { - SendDbgCommand(DID_START_THREAD, this); + Emu.SendDbgCommand(DID_START_THREAD, this); init_stack(); init_regs(); do_run(); - SendDbgCommand(DID_STARTED_THREAD, this); + Emu.SendDbgCommand(DID_STARTED_THREAD, this); } void CPUThread::pause() { - SendDbgCommand(DID_PAUSE_THREAD, this); + Emu.SendDbgCommand(DID_PAUSE_THREAD, this); m_state |= CPU_STATE_PAUSED; - SendDbgCommand(DID_PAUSED_THREAD, this); + Emu.SendDbgCommand(DID_PAUSED_THREAD, this); } void CPUThread::resume() { - SendDbgCommand(DID_RESUME_THREAD, this); + Emu.SendDbgCommand(DID_RESUME_THREAD, this); { // lock for reliable notification @@ -120,12 +118,12 @@ void CPUThread::resume() cv.notify_one(); } - SendDbgCommand(DID_RESUMED_THREAD, this); + Emu.SendDbgCommand(DID_RESUMED_THREAD, this); } void CPUThread::stop() { - SendDbgCommand(DID_STOP_THREAD, this); + Emu.SendDbgCommand(DID_STOP_THREAD, this); if (is_current()) { @@ -141,12 +139,12 @@ void CPUThread::stop() cv.notify_one(); } - SendDbgCommand(DID_STOPED_THREAD, this); + Emu.SendDbgCommand(DID_STOPED_THREAD, this); } void CPUThread::exec() { - SendDbgCommand(DID_EXEC_THREAD, this); + Emu.SendDbgCommand(DID_EXEC_THREAD, this); { // lock for reliable notification @@ -258,7 +256,7 @@ bool CPUThread::check_status() { CHECK_EMU_STATUS; // check at least once - if (!is_paused() && (m_state.load() & CPU_STATE_INTR) == 0) + if (!is_paused() && (m_state & CPU_STATE_INTR) == 0) { break; } @@ -269,7 +267,7 @@ bool CPUThread::check_status() continue; } - if (!is_paused() && (m_state.load() & CPU_STATE_INTR) != 0 && handle_interrupt()) + if (!is_paused() && (m_state & CPU_STATE_INTR) != 0 && handle_interrupt()) { continue; } @@ -277,12 +275,12 @@ bool CPUThread::check_status() cv.wait(lock); } - if (m_state.load() & CPU_STATE_RETURN || is_stopped()) + if (m_state & CPU_STATE_RETURN || is_stopped()) { return true; } - if (m_state.load() & CPU_STATE_STEP) + if (m_state & CPU_STATE_STEP) { // set PAUSE, but allow to execute once m_state |= CPU_STATE_PAUSED; diff --git a/rpcs3/Emu/CPU/CPUThread.h b/rpcs3/Emu/CPU/CPUThread.h index 57d821e01a..079da43f16 100644 --- a/rpcs3/Emu/CPU/CPUThread.h +++ b/rpcs3/Emu/CPU/CPUThread.h @@ -45,7 +45,7 @@ protected: using named_thread_t::join; using named_thread_t::joinable; - atomic_t m_state; // thread state flags + atomic_t m_state{ CPU_STATE_STOPPED }; // thread state flags std::unique_ptr m_dec; @@ -62,8 +62,8 @@ public: CPUThreadType get_type() const { return m_type; } std::string get_name() const { return m_name; } - bool is_alive() const { return (m_state.load() & CPU_STATE_DEAD) == 0; } - bool is_stopped() const { return (m_state.load() & CPU_STATE_STOPPED) != 0; } + 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; virtual void dump_info() const; diff --git a/rpcs3/Emu/CPU/CPUThreadManager.cpp b/rpcs3/Emu/CPU/CPUThreadManager.cpp index efad193d15..e02f653c0e 100644 --- a/rpcs3/Emu/CPU/CPUThreadManager.cpp +++ b/rpcs3/Emu/CPU/CPUThreadManager.cpp @@ -1,7 +1,6 @@ #include "stdafx.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/DbgCommand.h" #include "Emu/IdManager.h" #include "Emu/Cell/PPUThread.h" @@ -82,7 +81,7 @@ std::shared_ptr CPUThreadManager::NewRawSPUThread() break; } } - + return result; } diff --git a/rpcs3/Emu/Cell/PPUInterpreter.cpp b/rpcs3/Emu/Cell/PPUInterpreter.cpp index d2e2d15524..5d94b04a3c 100644 --- a/rpcs3/Emu/Cell/PPUInterpreter.cpp +++ b/rpcs3/Emu/Cell/PPUInterpreter.cpp @@ -970,8 +970,8 @@ void ppu_interpreter::VSLB(PPUThread& CPU, ppu_opcode_t op) void ppu_interpreter::VSLDOI(PPUThread& CPU, ppu_opcode_t op) { u8 tmpSRC[32]; - memcpy(tmpSRC, CPU.VPR[op.vb]._u8, 16); - memcpy(tmpSRC + 16, CPU.VPR[op.va]._u8, 16); + std::memcpy(tmpSRC, CPU.VPR + op.vb, 16); + std::memcpy(tmpSRC + 16, CPU.VPR + op.va, 16); for (uint b = 0; b<16; b++) { @@ -1475,7 +1475,7 @@ void ppu_interpreter::SC(PPUThread& CPU, ppu_opcode_t op) { switch (op.lev) { - case 0x0: SysCalls::DoSyscall(CPU, CPU.GPR[11]); break; + case 0x0: execute_syscall_by_index(CPU, CPU.GPR[11]); break; case 0x3: CPU.fast_stop(); break; default: throw EXCEPTION(""); } diff --git a/rpcs3/Emu/Cell/PPUInterpreter.h b/rpcs3/Emu/Cell/PPUInterpreter.h index 7e9ebc0419..1692fb76e9 100644 --- a/rpcs3/Emu/Cell/PPUInterpreter.h +++ b/rpcs3/Emu/Cell/PPUInterpreter.h @@ -1,9 +1,6 @@ #pragma once #include "Emu/Cell/PPUOpcodes.h" -#include "Emu/SysCalls/SysCalls.h" -#include "rpcs3/Ini.h" -#include "Emu/SysCalls/Modules.h" #include "Emu/Memory/Memory.h" #include @@ -16,7 +13,7 @@ #include -extern u64 rotate_mask[64][64]; // defined in PPUThread.cpp, static didn't work correctly in GCC 4.9 for some reason +extern u64 rotate_mask[64][64]; // defined in PPUThread.cpp extern u64 get_timebased_time(); inline void InitRotateMask() @@ -1327,8 +1324,8 @@ private: void VPERM(u32 vd, u32 va, u32 vb, u32 vc) { u8 tmpSRC[32]; - memcpy(tmpSRC, CPU.VPR[vb]._u8, 16); - memcpy(tmpSRC + 16, CPU.VPR[va]._u8, 16); + std::memcpy(tmpSRC, CPU.VPR + vb, 16); + std::memcpy(tmpSRC + 16, CPU.VPR + va, 16); for (uint b = 0; b < 16; b++) { @@ -1703,8 +1700,8 @@ private: void VSLDOI(u32 vd, u32 va, u32 vb, u32 sh) { u8 tmpSRC[32]; - memcpy(tmpSRC, CPU.VPR[vb]._u8, 16); - memcpy(tmpSRC + 16, CPU.VPR[va]._u8, 16); + std::memcpy(tmpSRC, CPU.VPR + vb, 16); + std::memcpy(tmpSRC + 16, CPU.VPR + va, 16); for(uint b=0; b<16; b++) { @@ -2232,13 +2229,17 @@ private: } void HACK(u32 index) { + extern void execute_ppu_func_by_index(PPUThread& ppu, u32 index); + execute_ppu_func_by_index(CPU, index); } void SC(u32 lev) { + extern void execute_syscall_by_index(PPUThread& ppu, u64 code); + switch (lev) { - case 0x0: SysCalls::DoSyscall(CPU, CPU.GPR[11]); break; + case 0x0: execute_syscall_by_index(CPU, CPU.GPR[11]); break; case 0x1: throw EXCEPTION("HyperCall LV1"); case 0x3: CPU.fast_stop(); break; default: throw EXCEPTION("Unknown level (0x%x)", lev); @@ -2487,12 +2488,12 @@ private: void LDX(u32 rd, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = vm::read64(VM_CAST(addr)); + CPU.GPR[rd] = vm::ps3::read64(VM_CAST(addr)); } void LWZX(u32 rd, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = vm::read32(VM_CAST(addr)); + CPU.GPR[rd] = vm::ps3::read32(VM_CAST(addr)); } void SLW(u32 ra, u32 rs, u32 rb, u32 rc) { @@ -2564,7 +2565,7 @@ private: void LVEHX(u32 vd, u32 ra, u32 rb) { const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~1ULL; - CPU.VPR[vd]._u16[7 - ((addr >> 1) & 0x7)] = vm::read16(VM_CAST(addr)); + CPU.VPR[vd]._u16[7 - ((addr >> 1) & 0x7)] = vm::ps3::read16(VM_CAST(addr)); // check LVEWX comments } void SUBF(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) @@ -2578,7 +2579,7 @@ private: void LDUX(u32 rd, u32 ra, u32 rb) { const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - CPU.GPR[rd] = vm::read64(VM_CAST(addr)); + CPU.GPR[rd] = vm::ps3::read64(VM_CAST(addr)); CPU.GPR[ra] = addr; } void DCBST(u32 ra, u32 rb) @@ -2587,7 +2588,7 @@ private: void LWZUX(u32 rd, u32 ra, u32 rb) { const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - CPU.GPR[rd] = vm::read32(VM_CAST(addr)); + CPU.GPR[rd] = vm::ps3::read32(VM_CAST(addr)); CPU.GPR[ra] = addr; } void CNTLZD(u32 ra, u32 rs, u32 rc) @@ -2613,7 +2614,7 @@ private: void LVEWX(u32 vd, u32 ra, u32 rb) { const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~3ULL; - CPU.VPR[vd]._u32[3 - ((addr >> 2) & 0x3)] = vm::read32(VM_CAST(addr)); + CPU.VPR[vd]._u32[3 - ((addr >> 2) & 0x3)] = vm::ps3::read32(VM_CAST(addr)); // It's not very good idea to implement it using read128(), // because it can theoretically read RawSPU 32-bit MMIO register (read128() will fail) //CPU.VPR[vd] = vm::read128((ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~0xfULL); @@ -2650,7 +2651,7 @@ private: void LVX(u32 vd, u32 ra, u32 rb) { const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~0xfull; - CPU.VPR[vd] = vm::read128(VM_CAST(addr)); + CPU.VPR[vd] = vm::ps3::read128(VM_CAST(addr)); } void NEG(u32 rd, u32 ra, u32 oe, u32 rc) { @@ -2746,7 +2747,7 @@ private: void STDX(u32 rs, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - vm::write64(VM_CAST(addr), CPU.GPR[rs]); + vm::ps3::write64(VM_CAST(addr), CPU.GPR[rs]); } void STWCX_(u32 rs, u32 ra, u32 rb) { @@ -2758,31 +2759,31 @@ private: void STWX(u32 rs, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - vm::write32(VM_CAST(addr), (u32)CPU.GPR[rs]); + vm::ps3::write32(VM_CAST(addr), (u32)CPU.GPR[rs]); } void STVEHX(u32 vs, u32 ra, u32 rb) { const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~1ULL; const u8 eb = (addr & 0xf) >> 1; - vm::write16(VM_CAST(addr), CPU.VPR[vs]._u16[7 - eb]); + vm::ps3::write16(VM_CAST(addr), CPU.VPR[vs]._u16[7 - eb]); } void STDUX(u32 rs, u32 ra, u32 rb) { const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - vm::write64(VM_CAST(addr), CPU.GPR[rs]); + vm::ps3::write64(VM_CAST(addr), CPU.GPR[rs]); CPU.GPR[ra] = addr; } void STWUX(u32 rs, u32 ra, u32 rb) { const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - vm::write32(VM_CAST(addr), (u32)CPU.GPR[rs]); + vm::ps3::write32(VM_CAST(addr), (u32)CPU.GPR[rs]); CPU.GPR[ra] = addr; } void STVEWX(u32 vs, u32 ra, u32 rb) { const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~3ULL; const u8 eb = (addr & 0xf) >> 2; - vm::write32(VM_CAST(addr), CPU.VPR[vs]._u32[3 - eb]); + vm::ps3::write32(VM_CAST(addr), CPU.VPR[vs]._u32[3 - eb]); } void SUBFZE(u32 rd, u32 ra, u32 oe, u32 rc) { @@ -2815,7 +2816,7 @@ private: void STVX(u32 vs, u32 ra, u32 rb) { const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~0xfull; - vm::write128(VM_CAST(addr), CPU.VPR[vs]); + vm::ps3::write128(VM_CAST(addr), CPU.VPR[vs]); } void MULLD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { @@ -2875,7 +2876,7 @@ private: void LHZX(u32 rd, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = vm::read16(VM_CAST(addr)); + CPU.GPR[rd] = vm::ps3::read16(VM_CAST(addr)); } void EQV(u32 ra, u32 rs, u32 rb, u32 rc) { @@ -2889,7 +2890,7 @@ private: void LHZUX(u32 rd, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = vm::read16(VM_CAST(addr)); + CPU.GPR[rd] = vm::ps3::read16(VM_CAST(addr)); CPU.GPR[ra] = addr; } void XOR(u32 ra, u32 rs, u32 rb, u32 rc) @@ -2904,7 +2905,7 @@ private: void LWAX(u32 rd, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = (s64)(s32)vm::read32(VM_CAST(addr)); + CPU.GPR[rd] = (s64)(s32)vm::ps3::read32(VM_CAST(addr)); } void DST(u32 ra, u32 rb, u32 strm, u32 t) { @@ -2912,12 +2913,12 @@ private: void LHAX(u32 rd, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = (s64)(s16)vm::read16(VM_CAST(addr)); + CPU.GPR[rd] = (s64)(s16)vm::ps3::read16(VM_CAST(addr)); } void LVXL(u32 vd, u32 ra, u32 rb) { const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~0xfull; - CPU.VPR[vd] = vm::read128(VM_CAST(addr)); + CPU.VPR[vd] = vm::ps3::read128(VM_CAST(addr)); } void MFTB(u32 rd, u32 spr) { @@ -2934,7 +2935,7 @@ private: void LWAUX(u32 rd, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = (s64)(s32)vm::read32(VM_CAST(addr)); + CPU.GPR[rd] = (s64)(s32)vm::ps3::read32(VM_CAST(addr)); CPU.GPR[ra] = addr; } void DSTST(u32 ra, u32 rb, u32 strm, u32 t) @@ -2943,13 +2944,13 @@ private: void LHAUX(u32 rd, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = (s64)(s16)vm::read16(VM_CAST(addr)); + CPU.GPR[rd] = (s64)(s16)vm::ps3::read16(VM_CAST(addr)); CPU.GPR[ra] = addr; } void STHX(u32 rs, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - vm::write16(VM_CAST(addr), (u16)CPU.GPR[rs]); + vm::ps3::write16(VM_CAST(addr), (u16)CPU.GPR[rs]); } void ORC(u32 ra, u32 rs, u32 rb, u32 rc) { @@ -2963,7 +2964,7 @@ private: void STHUX(u32 rs, u32 ra, u32 rb) { const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - vm::write16(VM_CAST(addr), (u16)CPU.GPR[rs]); + vm::ps3::write16(VM_CAST(addr), (u16)CPU.GPR[rs]); CPU.GPR[ra] = addr; } void OR(u32 ra, u32 rs, u32 rb, u32 rc) @@ -3023,7 +3024,7 @@ private: void STVXL(u32 vs, u32 ra, u32 rb) { const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~0xfull; - vm::write128(VM_CAST(addr), CPU.VPR[vs]); + vm::ps3::write128(VM_CAST(addr), CPU.VPR[vs]); } void DIVD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { @@ -3148,7 +3149,7 @@ private: { if (N > 3) { - CPU.GPR[reg] = vm::read32(VM_CAST(addr)); + CPU.GPR[reg] = vm::ps3::read32(VM_CAST(addr)); addr += 4; N -= 4; } @@ -3216,7 +3217,7 @@ private: u32 count = CPU.XER.XER & 0x7F; for (; count >= 4; count -= 4, addr += 4, rs = (rs+1) & 31) { - vm::write32(VM_CAST(addr), (u32)CPU.GPR[rs]); + vm::ps3::write32(VM_CAST(addr), (u32)CPU.GPR[rs]); } if (count) { @@ -3281,7 +3282,7 @@ private: { if (N > 3) { - vm::write32(VM_CAST(addr), (u32)CPU.GPR[reg]); + vm::ps3::write32(VM_CAST(addr), (u32)CPU.GPR[reg]); addr += 4; N -= 4; } @@ -3424,7 +3425,7 @@ private: void STFIWX(u32 frs, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - vm::write32(VM_CAST(addr), (u32&)CPU.FPR[frs]); + vm::ps3::write32(VM_CAST(addr), (u32&)CPU.FPR[frs]); } void EXTSW(u32 ra, u32 rs, u32 rc) { @@ -3444,12 +3445,12 @@ private: void LWZ(u32 rd, u32 ra, s32 d) { const u64 addr = ra ? CPU.GPR[ra] + d : d; - CPU.GPR[rd] = vm::read32(VM_CAST(addr)); + CPU.GPR[rd] = vm::ps3::read32(VM_CAST(addr)); } void LWZU(u32 rd, u32 ra, s32 d) { const u64 addr = CPU.GPR[ra] + d; - CPU.GPR[rd] = vm::read32(VM_CAST(addr)); + CPU.GPR[rd] = vm::ps3::read32(VM_CAST(addr)); CPU.GPR[ra] = addr; } void LBZ(u32 rd, u32 ra, s32 d) @@ -3466,12 +3467,12 @@ private: void STW(u32 rs, u32 ra, s32 d) { const u64 addr = ra ? CPU.GPR[ra] + d : d; - vm::write32(VM_CAST(addr), (u32)CPU.GPR[rs]); + vm::ps3::write32(VM_CAST(addr), (u32)CPU.GPR[rs]); } void STWU(u32 rs, u32 ra, s32 d) { const u64 addr = CPU.GPR[ra] + d; - vm::write32(VM_CAST(addr), (u32)CPU.GPR[rs]); + vm::ps3::write32(VM_CAST(addr), (u32)CPU.GPR[rs]); CPU.GPR[ra] = addr; } void STB(u32 rs, u32 ra, s32 d) @@ -3488,34 +3489,34 @@ private: void LHZ(u32 rd, u32 ra, s32 d) { const u64 addr = ra ? CPU.GPR[ra] + d : d; - CPU.GPR[rd] = vm::read16(VM_CAST(addr)); + CPU.GPR[rd] = vm::ps3::read16(VM_CAST(addr)); } void LHZU(u32 rd, u32 ra, s32 d) { const u64 addr = CPU.GPR[ra] + d; - CPU.GPR[rd] = vm::read16(VM_CAST(addr)); + CPU.GPR[rd] = vm::ps3::read16(VM_CAST(addr)); CPU.GPR[ra] = addr; } void LHA(u32 rd, u32 ra, s32 d) { const u64 addr = ra ? CPU.GPR[ra] + d : d; - CPU.GPR[rd] = (s64)(s16)vm::read16(VM_CAST(addr)); + CPU.GPR[rd] = (s64)(s16)vm::ps3::read16(VM_CAST(addr)); } void LHAU(u32 rd, u32 ra, s32 d) { const u64 addr = CPU.GPR[ra] + d; - CPU.GPR[rd] = (s64)(s16)vm::read16(VM_CAST(addr)); + CPU.GPR[rd] = (s64)(s16)vm::ps3::read16(VM_CAST(addr)); CPU.GPR[ra] = addr; } void STH(u32 rs, u32 ra, s32 d) { const u64 addr = ra ? CPU.GPR[ra] + d : d; - vm::write16(VM_CAST(addr), (u16)CPU.GPR[rs]); + vm::ps3::write16(VM_CAST(addr), (u16)CPU.GPR[rs]); } void STHU(u32 rs, u32 ra, s32 d) { const u64 addr = CPU.GPR[ra] + d; - vm::write16(VM_CAST(addr), (u16)CPU.GPR[rs]); + vm::ps3::write16(VM_CAST(addr), (u16)CPU.GPR[rs]); CPU.GPR[ra] = addr; } void LMW(u32 rd, u32 ra, s32 d) @@ -3523,7 +3524,7 @@ private: u64 addr = ra ? CPU.GPR[ra] + d : d; for(u32 i=rd; i<32; ++i, addr += 4) { - CPU.GPR[i] = vm::read32(VM_CAST(addr)); + CPU.GPR[i] = vm::ps3::read32(VM_CAST(addr)); } } void STMW(u32 rs, u32 ra, s32 d) @@ -3531,7 +3532,7 @@ private: u64 addr = ra ? CPU.GPR[ra] + d : d; for(u32 i=rs; i<32; ++i, addr += 4) { - vm::write32(VM_CAST(addr), (u32)CPU.GPR[i]); + vm::ps3::write32(VM_CAST(addr), (u32)CPU.GPR[i]); } } void LFS(u32 frd, u32 ra, s32 d) @@ -3619,18 +3620,18 @@ private: void LD(u32 rd, u32 ra, s32 ds) { const u64 addr = ra ? CPU.GPR[ra] + ds : ds; - CPU.GPR[rd] = vm::read64(VM_CAST(addr)); + CPU.GPR[rd] = vm::ps3::read64(VM_CAST(addr)); } void LDU(u32 rd, u32 ra, s32 ds) { const u64 addr = CPU.GPR[ra] + ds; - CPU.GPR[rd] = vm::read64(VM_CAST(addr)); + CPU.GPR[rd] = vm::ps3::read64(VM_CAST(addr)); CPU.GPR[ra] = addr; } void LWA(u32 rd, u32 ra, s32 ds) { const u64 addr = ra ? CPU.GPR[ra] + ds : ds; - CPU.GPR[rd] = (s64)(s32)vm::read32(VM_CAST(addr)); + CPU.GPR[rd] = (s64)(s32)vm::ps3::read32(VM_CAST(addr)); } void FDIVS(u32 frd, u32 fra, u32 frb, u32 rc) {FDIV(frd, fra, frb, rc, true);} void FSUBS(u32 frd, u32 fra, u32 frb, u32 rc) {FSUB(frd, fra, frb, rc, true);} @@ -3684,12 +3685,12 @@ private: void STD(u32 rs, u32 ra, s32 d) { const u64 addr = ra ? CPU.GPR[ra] + d : d; - vm::write64(VM_CAST(addr), CPU.GPR[rs]); + vm::ps3::write64(VM_CAST(addr), CPU.GPR[rs]); } void STDU(u32 rs, u32 ra, s32 ds) { const u64 addr = CPU.GPR[ra] + ds; - vm::write64(VM_CAST(addr), CPU.GPR[rs]); + vm::ps3::write64(VM_CAST(addr), CPU.GPR[rs]); CPU.GPR[ra] = addr; } void MTFSB1(u32 crbd, u32 rc) diff --git a/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp b/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp index 306b1a3ba2..f0cf394d40 100644 --- a/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp +++ b/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #ifdef LLVM_AVAILABLE +#include "rpcs3/Ini.h" #include "Utilities/Log.h" #include "Emu/System.h" #include "Emu/Cell/PPUDisAsm.h" diff --git a/rpcs3/Emu/Cell/PPULLVMRecompilerCore.cpp b/rpcs3/Emu/Cell/PPULLVMRecompilerCore.cpp index d3af52b2e9..17c2c22313 100644 --- a/rpcs3/Emu/Cell/PPULLVMRecompilerCore.cpp +++ b/rpcs3/Emu/Cell/PPULLVMRecompilerCore.cpp @@ -29,6 +29,9 @@ #pragma warning(pop) #endif +extern void execute_ppu_func_by_index(PPUThread& ppu, u32 id); +extern void execute_syscall_by_index(PPUThread& ppu, u64 code); + using namespace llvm; using namespace ppu_recompiler_llvm; @@ -1787,7 +1790,7 @@ void Compiler::HACK(u32 index) { static u32 wrappedDoSyscall(PPUThread &CPU, u64 code) noexcept { try { - SysCalls::DoSyscall(CPU, code); + execute_syscall_by_index(CPU, code); return ExecutionStatus::ExecutionStatusBlockEnded; } catch (...) @@ -1812,7 +1815,7 @@ void Compiler::SC(u32 lev) { } break; case 3: - Call("PPUThread.FastStop", &PPUThread::fast_stop, m_state.args[CompileTaskState::Args::State]); + Call("PPUThread.fast_stop", &PPUThread::fast_stop, m_state.args[CompileTaskState::Args::State]); break; default: CompilationError(fmt::format("SC %u", lev)); @@ -2160,7 +2163,7 @@ void Compiler::TW(u32 to, u32 ra, u32 rb) { } void Compiler::LVSL(u32 vd, u32 ra, u32 rb) { - static const v128 s_lvsl_values[] = { + static const u64 s_lvsl_values[0x10][2] = { { 0x08090A0B0C0D0E0F, 0x0001020304050607 }, { 0x090A0B0C0D0E0F10, 0x0102030405060708 }, { 0x0A0B0C0D0E0F1011, 0x0203040506070809 }, @@ -2389,7 +2392,7 @@ void Compiler::CMPL(u32 crfd, u32 l, u32 ra, u32 rb) { } void Compiler::LVSR(u32 vd, u32 ra, u32 rb) { - static const v128 s_lvsr_values[] = { + static const u64 s_lvsr_values[0x10][2] = { { 0x18191A1B1C1D1E1F, 0x1011121314151617 }, { 0x1718191A1B1C1D1E, 0x0F10111213141516 }, { 0x161718191A1B1C1D, 0x0E0F101112131415 }, diff --git a/rpcs3/Emu/Cell/PPULLVMRecompilerTests.cpp b/rpcs3/Emu/Cell/PPULLVMRecompilerTests.cpp index c295698328..a55e332406 100644 --- a/rpcs3/Emu/Cell/PPULLVMRecompilerTests.cpp +++ b/rpcs3/Emu/Cell/PPULLVMRecompilerTests.cpp @@ -99,7 +99,7 @@ struct ppu_recompiler_llvm::PPUState { address = addr; for (int i = 0; i < (sizeof(mem_block) / 8); i++) { - mem_block[i] = vm::read64(address + (i * 8)); + mem_block[i] = vm::ps3::read64(address + (i * 8)); } } @@ -123,7 +123,7 @@ struct ppu_recompiler_llvm::PPUState { ppu.TB = TB; for (int i = 0; i < (sizeof(mem_block) / 8); i++) { - vm::write64(address + (i * 8), mem_block[i]); + vm::ps3::write64(address + (i * 8), mem_block[i]); } } diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index e9a5fa6660..106f0bf923 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -5,8 +5,6 @@ #include "Emu/System.h" #include "Emu/IdManager.h" #include "Emu/Cell/PPUThread.h" -#include "Emu/SysCalls/SysCalls.h" -#include "Emu/SysCalls/Modules.h" #include "Emu/Cell/PPUDecoder.h" #include "Emu/Cell/PPUInterpreter.h" #include "Emu/Cell/PPUInterpreter2.h" @@ -51,7 +49,7 @@ void ppu_decoder_cache_t::initialize(u32 addr, u32 size) inter->func = ppu_interpreter::NULL_OP; // decode PPU opcode - dec.Decode(vm::read32(pos)); + dec.Decode(vm::ps3::read32(pos)); // store function address pointer[pos / 4] = inter->func; @@ -81,13 +79,15 @@ PPUThread::~PPUThread() void PPUThread::dump_info() const { + extern std::string get_ps3_function_name(u64 fid); + if (~hle_code < 1024) { - LOG_SUCCESS(HLE, "Last syscall: %lld (%s)", ~hle_code, SysCalls::GetFuncName(hle_code)); + LOG_SUCCESS(HLE, "Last syscall: %lld (%s)", ~hle_code, get_ps3_function_name(hle_code)); } else if (hle_code) { - LOG_SUCCESS(HLE, "Last function: %s (0x%llx)", SysCalls::GetFuncName(hle_code), hle_code); + LOG_SUCCESS(HLE, "Last function: %s (0x%llx)", get_ps3_function_name(hle_code), hle_code); } CPUThread::dump_info(); @@ -214,7 +214,7 @@ int FPRdouble::Cmp(PPCdouble a, PPCdouble b) u64 PPUThread::get_stack_arg(s32 i) { - return vm::read64(VM_CAST(GPR[1] + 0x70 + 0x8 * (i - 9))); + return vm::ps3::read64(VM_CAST(GPR[1] + 0x70 + 0x8 * (i - 9))); } void PPUThread::fast_call(u32 addr, u32 rtoc) @@ -293,7 +293,7 @@ void PPUThread::task() { while (true) { - if (m_state.load() && check_status()) break; + if (m_state && check_status()) break; // decode instruction using specified decoder m_dec->DecodeMemory(PC); @@ -310,10 +310,10 @@ void PPUThread::task() const auto func = exec_map[PC / 4]; // check status - if (!m_state.load()) + if (!m_state) { // call interpreter function - func(*this, { vm::read32(PC) }); + func(*this, { vm::ps3::read32(PC) }); // next instruction PC += 4; @@ -335,8 +335,8 @@ ppu_thread::ppu_thread(u32 entry, const std::string& name, u32 stack_size, s32 p if (entry) { - ppu->PC = vm::read32(entry); - ppu->GPR[2] = vm::read32(entry + 4); // rtoc + ppu->PC = vm::ps3::read32(entry); + ppu->GPR[2] = vm::ps3::read32(entry + 4); // rtoc } ppu->stack_size = stack_size ? stack_size : Emu.GetPrimaryStackSize(); diff --git a/rpcs3/Emu/Cell/PPUThread.h b/rpcs3/Emu/Cell/PPUThread.h index 11a0e1047b..bfad145322 100644 --- a/rpcs3/Emu/Cell/PPUThread.h +++ b/rpcs3/Emu/Cell/PPUThread.h @@ -1012,3 +1012,20 @@ force_inline T cast_from_ppu_gpr(const u64 reg) { return cast_ppu_gpr::from_gpr(reg); } + +// flags set in ModuleFunc +enum : u32 +{ + MFF_FORCED_HLE = (1 << 0), // always call HLE function + MFF_NO_RETURN = (1 << 1), // uses EIF_USE_BRANCH flag with LLE, ignored with MFF_FORCED_HLE +}; + +// flags passed with index +enum : u32 +{ + EIF_SAVE_RTOC = (1 << 25), // save RTOC in [SP+0x28] before calling HLE/LLE function + EIF_PERFORM_BLR = (1 << 24), // do BLR after calling HLE/LLE function + EIF_USE_BRANCH = (1 << 23), // do only branch, LLE must be set, last_syscall must be zero + + EIF_FLAGS = 0x3800000, // all flags +}; diff --git a/rpcs3/Emu/Cell/RawSPUThread.cpp b/rpcs3/Emu/Cell/RawSPUThread.cpp index 1ad595d2d9..c7c844721e 100644 --- a/rpcs3/Emu/Cell/RawSPUThread.cpp +++ b/rpcs3/Emu/Cell/RawSPUThread.cpp @@ -67,7 +67,7 @@ bool RawSPUThread::read_reg(const u32 addr, u32& value) case SPU_Status_offs: { - value = status.load(); + value = status; return true; } } @@ -201,7 +201,7 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value) break; } - run_ctrl.store(value); + run_ctrl = value; return true; } @@ -212,7 +212,7 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value) break; } - npc.store(value); + npc = value; return true; } @@ -245,5 +245,5 @@ void RawSPUThread::task() SPUThread::task(); // save next PC and current SPU Interrupt status - npc.store(pc | u32{ (ch_event_stat.load() & SPU_EVENT_INTR_ENABLED) != 0 }); + npc = pc | ((ch_event_stat & SPU_EVENT_INTR_ENABLED) != 0); } diff --git a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp index c53ed35363..71d7631589 100644 --- a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp @@ -272,7 +272,7 @@ void spu_recompiler::InterpreterCall(spu_opcode_t op) const u32 old_pc = _spu->pc; - if (_spu->m_state.load() && _spu->check_status()) + if (_spu->m_state && _spu->check_status()) { return 0x2000000 | _spu->pc; } @@ -343,12 +343,12 @@ void spu_recompiler::FunctionCall() LOG_ERROR(SPU, "Branch-to-self"); } - while (!_spu->m_state.load() || !_spu->check_status()) + while (!_spu->m_state || !_spu->check_status()) { // Call override function directly since the type is known static_cast(*_spu->m_dec).DecodeMemory(_spu->offset + _spu->pc); - if (_spu->m_state.load() & CPU_STATE_RETURN) + if (_spu->m_state & CPU_STATE_RETURN) { break; } diff --git a/rpcs3/Emu/Cell/SPUAnalyser.cpp b/rpcs3/Emu/Cell/SPUAnalyser.cpp index 27ab0954bd..a6dcbb5051 100644 --- a/rpcs3/Emu/Cell/SPUAnalyser.cpp +++ b/rpcs3/Emu/Cell/SPUAnalyser.cpp @@ -40,8 +40,6 @@ SPUDatabase::~SPUDatabase() std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 entry, u32 max_limit) { - std::lock_guard lock(m_mutex); - // Check arguments (bounds and alignment) if (max_limit > 0x40000 || entry >= max_limit || entry % 4 || max_limit % 4) { @@ -51,7 +49,19 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en // Key for multimap const u64 key = entry | u64{ ls[entry / 4] } << 32; - // Try to find existing function in the database + { + std::shared_lock lock(m_mutex); + + // Try to find existing function in the database + if (auto func = find(ls + entry / 4, key, max_limit - entry)) + { + return func; + } + } + + std::lock_guard lock(m_mutex); + + // Double-check if (auto func = find(ls + entry / 4, key, max_limit - entry)) { return func; diff --git a/rpcs3/Emu/Cell/SPUAnalyser.h b/rpcs3/Emu/Cell/SPUAnalyser.h index b252911aa9..eb695520f3 100644 --- a/rpcs3/Emu/Cell/SPUAnalyser.h +++ b/rpcs3/Emu/Cell/SPUAnalyser.h @@ -1,6 +1,7 @@ #pragma once #include "Emu/Cell/SPUOpcodes.h" +#include "Utilities/SharedMutex.h" class SPUThread; @@ -258,7 +259,7 @@ struct spu_function_t // SPU Function Database (must be global or PS3 process-local) class SPUDatabase final { - std::mutex m_mutex; + shared_mutex_t m_mutex; // All registered functions (uses addr and first instruction as a key) std::unordered_multimap> m_db; diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 48780b9dc2..252e95cf02 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -29,7 +29,7 @@ thread_local bool spu_channel_t::notification_required; void spu_int_ctrl_t::set(u64 ints) { // leave only enabled interrupts - ints &= mask.load(); + ints &= mask; // notify if at least 1 bit was set if (ints && ~stat._or(ints) & ints && tag) @@ -118,7 +118,7 @@ void SPUThread::task() while (true) { - if (!m_state.load()) + if (!m_state) { // read opcode const u32 opcode = base[pc / 4]; @@ -146,7 +146,7 @@ void SPUThread::task() return custom_task(*this); } - while (!m_state.load() || !check_status()) + while (!m_state || !check_status()) { // decode instruction using specified decoder pc += m_dec->DecodeMemory(pc + offset); @@ -162,32 +162,34 @@ void SPUThread::init_regs() mfc_queue.clear(); ch_tag_mask = 0; - ch_tag_stat = {}; - ch_stall_stat = {}; - ch_atomic_stat = {}; + ch_tag_stat.data.store({}); + ch_stall_stat.data.store({}); + ch_atomic_stat.data.store({}); ch_in_mbox.clear(); - ch_out_mbox = {}; - ch_out_intr_mbox = {}; + ch_out_mbox.data.store({}); + ch_out_intr_mbox.data.store({}); snr_config = 0; - ch_snr1 = {}; - ch_snr2 = {}; + ch_snr1.data.store({}); + ch_snr2.data.store({}); - ch_event_mask = {}; - ch_event_stat = {}; + ch_event_mask = 0; + ch_event_stat = 0; last_raddr = 0; ch_dec_start_timestamp = get_timebased_time(); // ??? ch_dec_value = 0; - run_ctrl = {}; - status = {}; - npc = {}; + run_ctrl = 0; + status = 0; + npc = 0; - int_ctrl = {}; + int_ctrl[0].clear(); + int_ctrl[1].clear(); + int_ctrl[2].clear(); gpr[1]._u32[3] = 0x3FFF0; // initial stack frame pointer } @@ -511,7 +513,7 @@ u32 SPUThread::get_events(bool waiting) // polling with atomically set/removed SPU_EVENT_WAITING flag return ch_event_stat.atomic_op([this](u32& stat) -> u32 { - if (u32 res = stat & ch_event_mask.load()) + if (u32 res = stat & ch_event_mask) { stat &= ~SPU_EVENT_WAITING; return res; @@ -525,7 +527,7 @@ u32 SPUThread::get_events(bool waiting) } // simple polling - return ch_event_stat.load() & ch_event_mask.load(); + return ch_event_stat & ch_event_mask; } void SPUThread::set_events(u32 mask) @@ -543,7 +545,7 @@ void SPUThread::set_events(u32 mask) { std::lock_guard lock(mutex); - if (ch_event_stat.load() & SPU_EVENT_WAITING) + if (ch_event_stat & SPU_EVENT_WAITING) { cv.notify_one(); } @@ -555,7 +557,7 @@ void SPUThread::set_interrupt_status(bool enable) if (enable) { // detect enabling interrupts with events masked - if (u32 mask = ch_event_mask.load()) + if (u32 mask = ch_event_mask) { throw EXCEPTION("SPU Interrupts not implemented (mask=0x%x)", mask); } @@ -710,7 +712,7 @@ u32 SPUThread::get_ch_value(u32 ch) case SPU_RdEventMask: { - return ch_event_mask.load(); + return ch_event_mask; } case SPU_RdEventStat: @@ -723,7 +725,7 @@ u32 SPUThread::get_ch_value(u32 ch) return res; } - if (ch_event_mask.load() & SPU_EVENT_LR) + if (ch_event_mask & SPU_EVENT_LR) { // register waiter if polling reservation status is required vm::wait_op(*this, last_raddr, 128, WRAP_EXPR(get_events(true) || is_stopped())); @@ -752,7 +754,7 @@ u32 SPUThread::get_ch_value(u32 ch) { // HACK: "Not isolated" status // Return SPU Interrupt status in LSB - return (ch_event_stat.load() & SPU_EVENT_INTR_ENABLED) != 0; + return (ch_event_stat & SPU_EVENT_INTR_ENABLED) != 0; } } @@ -1120,7 +1122,7 @@ void SPUThread::set_ch_value(u32 ch, u32 value) case SPU_WrEventMask: { // detect masking events with enabled interrupt status - if (value && ch_event_stat.load() & SPU_EVENT_INTR_ENABLED) + if (value && ch_event_stat & SPU_EVENT_INTR_ENABLED) { throw EXCEPTION("SPU Interrupts not implemented (mask=0x%x)", value); } @@ -1131,7 +1133,7 @@ void SPUThread::set_ch_value(u32 ch, u32 value) break; } - ch_event_mask.store(value); + ch_event_mask = value; return; } diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index ced3748d78..726ad61ad1 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -147,13 +147,13 @@ struct spu_channel_t u32 value; }; - atomic_t sync_var; + atomic_t data; public: // returns true on success bool try_push(u32 value) { - const auto old = sync_var.atomic_op([=](sync_var_t& data) + const auto old = data.atomic_op([=](sync_var_t& data) { if ((data.wait = data.count) == false) { @@ -168,7 +168,7 @@ public: // push performing bitwise OR with previous value, may require notification void push_or(u32 value) { - const auto old = sync_var.atomic_op([=](sync_var_t& data) + const auto old = data.atomic_op([=](sync_var_t& data) { data.count = true; data.wait = false; @@ -181,7 +181,7 @@ public: // push unconditionally (overwriting previous value), may require notification void push(u32 value) { - const auto old = sync_var.atomic_op([=](sync_var_t& data) + const auto old = data.atomic_op([=](sync_var_t& data) { data.count = true; data.wait = false; @@ -194,7 +194,7 @@ public: // returns true on success and loaded value std::tuple try_pop() { - const auto old = sync_var.atomic_op([](sync_var_t& data) + const auto old = data.atomic_op([](sync_var_t& data) { data.wait = !data.count; data.count = false; @@ -207,7 +207,7 @@ public: // pop unconditionally (loading last value), may require notification u32 pop() { - const auto old = sync_var.atomic_op([](sync_var_t& data) + const auto old = data.atomic_op([](sync_var_t& data) { data.wait = false; data.count = false; @@ -221,17 +221,17 @@ public: void set_value(u32 value, bool count = true) { - sync_var.store({ count, false, value }); + data.store({ count, false, value }); } - u32 get_value() volatile + u32 get_value() { - return sync_var.data.value; + return data.load().value; } - u32 get_count() volatile + u32 get_count() { - return sync_var.data.count; + return data.load().count; } }; @@ -250,22 +250,22 @@ struct spu_channel_4_t u32 value2; }; - atomic_t sync_var; + atomic_t values; atomic_t value3; public: void clear() { - sync_var = {}; - value3 = {}; + values = sync_var_t{}; + value3 = 0; } // push unconditionally (overwriting latest value), returns true if needs signaling bool push(u32 value) { - value3.exchange(value); + value3 = value; _mm_sfence(); - return sync_var.atomic_op([=](sync_var_t& data) -> bool + return values.atomic_op([=](sync_var_t& data) -> bool { switch (data.count++) { @@ -289,7 +289,7 @@ public: // returns true on success and two u32 values: data and count after removing the first element std::tuple try_pop() { - return sync_var.atomic_op([this](sync_var_t& data) + return values.atomic_op([this](sync_var_t& data) { const auto result = std::make_tuple(data.count != 0, u32{ data.value0 }, u32{ data.count - 1u }); @@ -300,7 +300,8 @@ public: data.value0 = data.value1; data.value1 = data.value2; - data.value2 = value3.load_sync(); + _mm_lfence(); + data.value2 = this->value3; } else { @@ -311,19 +312,15 @@ public: }); } - u32 get_count() volatile + u32 get_count() { - return sync_var.data.count; + return values.raw().count; } void set_values(u32 count, u32 value0, u32 value1 = 0, u32 value2 = 0, u32 value3 = 0) { - sync_var.data.waiting = 0; - sync_var.data.count = count; - sync_var.data.value0 = value0; - sync_var.data.value1 = value1; - sync_var.data.value2 = value2; - this->value3.store(value3); + this->values.raw() = { 0, count, value0, value1, value2 }; + this->value3 = value3; } }; @@ -337,6 +334,13 @@ struct spu_int_ctrl_t void set(u64 ints); void clear(u64 ints); + + void clear() + { + mask = 0; + stat = 0; + tag = nullptr; + } }; struct spu_imm_table_t diff --git a/rpcs3/Emu/DbgCommand.cpp b/rpcs3/Emu/DbgCommand.cpp deleted file mode 100644 index 8be005e73c..0000000000 --- a/rpcs3/Emu/DbgCommand.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "stdafx.h" -#include "DbgCommand.h" - -SendDbgCommandCb SendDbgCommandFunc = nullptr; - -void SendDbgCommand(DbgCommand id, CPUThread* t) -{ - SendDbgCommandFunc(id, t); -} - -void SetSendDbgCommandCallback(SendDbgCommandCb cb) -{ - SendDbgCommandFunc = cb; -} \ No newline at end of file diff --git a/rpcs3/Emu/DbgCommand.h b/rpcs3/Emu/DbgCommand.h index 2973079729..4009aaa988 100644 --- a/rpcs3/Emu/DbgCommand.h +++ b/rpcs3/Emu/DbgCommand.h @@ -1,7 +1,5 @@ #pragma once -class CPUThread; - enum DbgCommand { DID_FIRST_COMMAND = 0x500, @@ -35,9 +33,3 @@ enum DbgCommand DID_LAST_COMMAND, }; - -typedef void(*SendDbgCommandCb)(DbgCommand id, CPUThread* t); - -void SetSendDbgCommandCallback(SendDbgCommandCb value); - -void SendDbgCommand(DbgCommand id, CPUThread* thr = nullptr); \ No newline at end of file diff --git a/rpcs3/Emu/IdManager.cpp b/rpcs3/Emu/IdManager.cpp index 46b597d9ea..d9e2d6720d 100644 --- a/rpcs3/Emu/IdManager.cpp +++ b/rpcs3/Emu/IdManager.cpp @@ -1,35 +1,14 @@ #include "stdafx.h" #include "IdManager.h" -namespace idm -{ - std::mutex g_id_mutex; +std::mutex idm::g_mutex; - std::unordered_map g_id_map; +std::unordered_map idm::g_map; - thread_local u32 g_tls_last_id = 0xdeadbeef; +u32 idm::g_last_raw_id = 0; - u32 g_last_raw_id = 0; +thread_local u32 idm::g_tls_last_id = 0xdeadbeef; - void clear() - { - std::lock_guard lock(g_id_mutex); +std::mutex fxm::g_mutex; - g_id_map.clear(); - g_last_raw_id = 0; - } -} - -namespace fxm -{ - std::mutex g_fx_mutex; - - std::unordered_map> g_fx_map; - - void clear() - { - std::lock_guard lock(g_fx_mutex); - - g_fx_map.clear(); - } -} +std::unordered_map> fxm::g_map; diff --git a/rpcs3/Emu/IdManager.h b/rpcs3/Emu/IdManager.h index 3ee541c583..f35e01a7c8 100644 --- a/rpcs3/Emu/IdManager.h +++ b/rpcs3/Emu/IdManager.h @@ -2,6 +2,15 @@ #define ID_MANAGER_INCLUDED +template struct type_info_t { static char value; }; + +template char type_info_t::value = 42; + +template constexpr inline const void* get_type_index() +{ + return &type_info_t::value; +} + // default traits for any arbitrary type template struct id_traits { @@ -15,24 +24,16 @@ template struct id_traits static u32 out_id(u32 raw_id) { return raw_id; } }; -class id_data_t final +struct id_data_t final { -public: - const std::shared_ptr data; - const std::type_info& info; - const std::size_t hash; + std::shared_ptr data; + const std::type_info* info; + const void* type_index; - template force_inline id_data_t(std::shared_ptr data) + template inline id_data_t(std::shared_ptr data) : data(std::move(data)) - , info(typeid(T)) - , hash(typeid(T).hash_code()) - { - } - - id_data_t(id_data_t&& right) - : data(std::move(const_cast&>(right.data))) - , info(right.info) - , hash(right.hash) + , info(&typeid(T)) + , type_index(get_type_index()) { } }; @@ -43,64 +44,63 @@ public: // 0x80000000+ : reserved (may be used through id_traits specializations) namespace idm { - // can be called from the constructor called through make() or make_ptr() to get the ID of currently created object - inline u32 get_last_id() - { - thread_local extern u32 g_tls_last_id; + extern std::mutex g_mutex; + extern std::unordered_map g_map; + + extern u32 g_last_raw_id; + + thread_local extern u32 g_tls_last_id; + + // can be called from the constructor called through make() or make_ptr() to get the ID of the object being created + inline static u32 get_last_id() + { return g_tls_last_id; } // reinitialize ID manager - void clear(); + static void clear() + { + std::lock_guard lock(g_mutex); + + g_map.clear(); + g_last_raw_id = 0; + } // check if ID of specified type exists - template bool check(u32 id) + template static bool check(u32 id) { - extern std::mutex g_id_mutex; - extern std::unordered_map g_id_map; + std::lock_guard lock(g_mutex); + + const auto found = g_map.find(id_traits::in_id(id)); - std::lock_guard lock(g_id_mutex); - - const auto found = g_id_map.find(id_traits::in_id(id)); - - return found != g_id_map.end() && found->second.info == typeid(T); + return found != g_map.end() && found->second.type_index == get_type_index(); } // check if ID exists and return its type or nullptr - inline const std::type_info* get_type(u32 raw_id) + inline static const std::type_info* get_type(u32 raw_id) { - extern std::mutex g_id_mutex; - extern std::unordered_map g_id_map; + std::lock_guard lock(g_mutex); - std::lock_guard lock(g_id_mutex); + const auto found = g_map.find(raw_id); - const auto found = g_id_map.find(raw_id); - - return found == g_id_map.end() ? nullptr : &found->second.info; + return found == g_map.end() ? nullptr : found->second.info; } // add 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) + template static std::enable_if_t::value, std::shared_ptr> make_ptr(Args&&... args) { - extern std::mutex g_id_mutex; - extern std::unordered_map g_id_map; - extern u32 g_last_raw_id; - thread_local extern u32 g_tls_last_id; + std::lock_guard lock(g_mutex); - std::lock_guard lock(g_id_mutex); - - u32 raw_id = g_last_raw_id; - - while ((raw_id = id_traits::next_id(raw_id))) + for (u32 raw_id = g_last_raw_id; (raw_id = id_traits::next_id(raw_id)); /**/) { - if (g_id_map.find(raw_id) != g_id_map.end()) continue; + if (g_map.find(raw_id) != g_map.end()) continue; g_tls_last_id = id_traits::out_id(raw_id); auto ptr = std::make_shared(std::forward(args)...); - g_id_map.emplace(raw_id, id_data_t(ptr)); + g_map.emplace(raw_id, id_data_t(ptr)); if (raw_id < 0x80000000) g_last_raw_id = raw_id; @@ -111,24 +111,17 @@ namespace idm } // add 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) { - extern std::mutex g_id_mutex; - extern std::unordered_map g_id_map; - extern u32 g_last_raw_id; - thread_local extern u32 g_tls_last_id; + std::lock_guard lock(g_mutex); - std::lock_guard lock(g_id_mutex); - - u32 raw_id = g_last_raw_id; - - while ((raw_id = id_traits::next_id(raw_id))) + for (u32 raw_id = g_last_raw_id; (raw_id = id_traits::next_id(raw_id)); /**/) { - if (g_id_map.find(raw_id) != g_id_map.end()) continue; + if (g_map.find(raw_id) != g_map.end()) continue; g_tls_last_id = id_traits::out_id(raw_id); - g_id_map.emplace(raw_id, id_data_t(std::make_shared(std::forward(args)...))); + g_map.emplace(raw_id, id_data_t(std::make_shared(std::forward(args)...))); if (raw_id < 0x80000000) g_last_raw_id = raw_id; @@ -139,24 +132,17 @@ namespace idm } // add new ID for an existing object provided (don't use for initial object creation) - template u32 import(const std::shared_ptr& ptr) + template static u32 import(const std::shared_ptr& ptr) { - extern std::mutex g_id_mutex; - extern std::unordered_map g_id_map; - extern u32 g_last_raw_id; - thread_local extern u32 g_tls_last_id; + std::lock_guard lock(g_mutex); - std::lock_guard lock(g_id_mutex); - - u32 raw_id = g_last_raw_id; - - while ((raw_id = id_traits::next_id(raw_id))) + for (u32 raw_id = g_last_raw_id; (raw_id = id_traits::next_id(raw_id)); /**/) { - if (g_id_map.find(raw_id) != g_id_map.end()) continue; + if (g_map.find(raw_id) != g_map.end()) continue; g_tls_last_id = id_traits::out_id(raw_id); - g_id_map.emplace(raw_id, id_data_t(ptr)); + g_map.emplace(raw_id, id_data_t(ptr)); if (raw_id < 0x80000000) g_last_raw_id = raw_id; @@ -167,16 +153,13 @@ namespace idm } // get ID of specified type - template std::shared_ptr get(u32 id) + template static std::shared_ptr get(u32 id) { - extern std::mutex g_id_mutex; - extern std::unordered_map g_id_map; + std::lock_guard lock(g_mutex); - std::lock_guard lock(g_id_mutex); + const auto found = g_map.find(id_traits::in_id(id)); - const auto found = g_id_map.find(id_traits::in_id(id)); - - if (found == g_id_map.end() || found->second.info != typeid(T)) + if (found == g_map.end() || found->second.type_index != get_type_index()) { return nullptr; } @@ -185,20 +168,17 @@ namespace idm } // get all IDs of specified type T (unsorted) - template std::vector> get_all() + template static std::vector> get_all() { - extern std::mutex g_id_mutex; - extern std::unordered_map g_id_map; - - std::lock_guard lock(g_id_mutex); + std::lock_guard lock(g_mutex); std::vector> result; - const std::size_t hash = typeid(T).hash_code(); + const auto type = get_type_index(); - for (auto& v : g_id_map) + for (auto& v : g_map) { - if (v.second.hash == hash && v.second.info == typeid(T)) + if (v.second.type_index == type) { result.emplace_back(std::static_pointer_cast(v.second.data)); } @@ -208,61 +188,52 @@ namespace idm } // remove ID created with type T - template bool remove(u32 id) + template static bool remove(u32 id) { - extern std::mutex g_id_mutex; - extern std::unordered_map g_id_map; + std::lock_guard lock(g_mutex); - std::lock_guard lock(g_id_mutex); + const auto found = g_map.find(id_traits::in_id(id)); - const auto found = g_id_map.find(id_traits::in_id(id)); - - if (found == g_id_map.end() || found->second.info != typeid(T)) + if (found == g_map.end() || found->second.type_index != get_type_index()) { return false; } - g_id_map.erase(found); + g_map.erase(found); return true; } // remove ID created with type T and return the object - template std::shared_ptr withdraw(u32 id) + template static std::shared_ptr withdraw(u32 id) { - extern std::mutex g_id_mutex; - extern std::unordered_map g_id_map; + std::lock_guard lock(g_mutex); - std::lock_guard lock(g_id_mutex); + const auto found = g_map.find(id_traits::in_id(id)); - const auto found = g_id_map.find(id_traits::in_id(id)); - - if (found == g_id_map.end() || found->second.info != typeid(T)) + if (found == g_map.end() || found->second.type_index != get_type_index()) { return nullptr; } auto ptr = std::static_pointer_cast(found->second.data); - g_id_map.erase(found); + g_map.erase(found); return ptr; } - template u32 get_count() + template static u32 get_count() { - extern std::mutex g_id_mutex; - extern std::unordered_map g_id_map; - - std::lock_guard lock(g_id_mutex); + std::lock_guard lock(g_mutex); u32 result = 0; - const std::size_t hash = typeid(T).hash_code(); + const auto type = get_type_index(); - for (auto& v : g_id_map) + for (auto& v : g_map) { - if (v.second.hash == hash && v.second.info == typeid(T)) + if (v.second.type_index == type) { result++; } @@ -272,20 +243,17 @@ namespace idm } // get sorted ID list of specified type - template std::set get_set() + template static std::set get_set() { - extern std::mutex g_id_mutex; - extern std::unordered_map g_id_map; - - std::lock_guard lock(g_id_mutex); + std::lock_guard lock(g_mutex); std::set result; - const std::size_t hash = typeid(T).hash_code(); + const auto type = get_type_index(); - for (auto& v : g_id_map) + for (auto& v : g_map) { - if (v.second.hash == hash && v.second.info == typeid(T)) + if (v.second.type_index == type) { result.insert(id_traits::out_id(v.first)); } @@ -295,20 +263,17 @@ namespace idm } // get sorted ID map (ID value -> ID data) of specified type - template std::map> get_map() + template static std::map> get_map() { - extern std::mutex g_id_mutex; - extern std::unordered_map g_id_map; - - std::lock_guard lock(g_id_mutex); + std::lock_guard lock(g_mutex); std::map> result; - const std::size_t hash = typeid(T).hash_code(); + const auto type = get_type_index(); - for (auto& v : g_id_map) + for (auto& v : g_map) { - if (v.second.hash == hash && v.second.info == typeid(T)) + if (v.second.type_index == type) { result[id_traits::out_id(v.first)] = std::static_pointer_cast(v.second.data); } @@ -316,69 +281,102 @@ namespace idm 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 { + extern std::mutex g_mutex; + + extern std::unordered_map> g_map; + // reinitialize - void clear(); + static void clear() + { + std::lock_guard lock(g_mutex); + + g_map.clear(); + } // add fixed object of specified type only if it doesn't exist (one unique object per type may exist) - 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) { - extern std::mutex g_fx_mutex; - extern std::unordered_map> g_fx_map; + std::lock_guard lock(g_mutex); - std::lock_guard lock(g_fx_mutex); + const auto index = get_type_index(); - const auto found = g_fx_map.find(typeid(T)); + const auto found = g_map.find(index); // only if object of this type doesn't exist - if (found == g_fx_map.end()) + if (found == g_map.end()) { auto ptr = std::make_shared(std::forward(args)...); - g_fx_map.emplace(typeid(T), ptr); + g_map.emplace(index, ptr); - return std::move(ptr); + return ptr; } return nullptr; } // add fixed object of specified type, replacing previous one 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) { - extern std::mutex g_fx_mutex; - extern std::unordered_map> g_fx_map; - - std::lock_guard lock(g_fx_mutex); + std::lock_guard lock(g_mutex); auto ptr = std::make_shared(std::forward(args)...); - g_fx_map[typeid(T)] = ptr; + g_map[get_type_index()] = ptr; + + return ptr; + } + + // import existing fixed object of specified type only if it doesn't exist (don't use) + template static std::shared_ptr import(std::shared_ptr&& ptr) + { + std::lock_guard lock(g_mutex); + + const auto index = get_type_index(); + + const auto found = g_map.find(index); + + if (found == g_map.end()) + { + g_map.emplace(index, ptr); + + return ptr; + } + + return nullptr; + } + + // import existing fixed object of specified type, replacing previous one if it exists (don't use) + template static std::shared_ptr import_always(std::shared_ptr&& ptr) + { + std::lock_guard lock(g_mutex); + + g_map[get_type_index()] = ptr; return ptr; } // get fixed object of specified type (always returns an object, it's created 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) { - extern std::mutex g_fx_mutex; - extern std::unordered_map> g_fx_map; + std::lock_guard lock(g_mutex); - std::lock_guard lock(g_fx_mutex); + const auto index = get_type_index(); - const auto found = g_fx_map.find(typeid(T)); + const auto found = g_map.find(index); - if (found == g_fx_map.end()) + if (found == g_map.end()) { auto ptr = std::make_shared(std::forward(args)...); - g_fx_map[typeid(T)] = ptr; + g_map[index] = ptr; return ptr; } @@ -387,27 +385,21 @@ namespace fxm } // check whether the object exists - template bool check() + template static bool check() { - extern std::mutex g_fx_mutex; - extern std::unordered_map> g_fx_map; + std::lock_guard lock(g_mutex); - std::lock_guard lock(g_fx_mutex); - - return g_fx_map.find(typeid(T)) != g_fx_map.end(); + return g_map.find(get_type_index()) != g_map.end(); } // get fixed object of specified type (returns nullptr if it doesn't exist) - template std::shared_ptr get() + template static std::shared_ptr get() { - extern std::mutex g_fx_mutex; - extern std::unordered_map> g_fx_map; + std::lock_guard lock(g_mutex); - std::lock_guard lock(g_fx_mutex); + const auto found = g_map.find(get_type_index()); - const auto found = g_fx_map.find(typeid(T)); - - if (found == g_fx_map.end()) + if (found == g_map.end()) { return nullptr; } @@ -416,40 +408,34 @@ namespace fxm } // remove fixed object created with type T - template bool remove() + template static bool remove() { - extern std::mutex g_fx_mutex; - extern std::unordered_map> g_fx_map; + std::lock_guard lock(g_mutex); - std::lock_guard lock(g_fx_mutex); + const auto found = g_map.find(get_type_index()); - const auto found = g_fx_map.find(typeid(T)); - - if (found == g_fx_map.end()) + if (found == g_map.end()) { return false; } - return g_fx_map.erase(found), true; + return g_map.erase(found), true; } // remove fixed object created with type T and return it - template std::shared_ptr withdraw() + template static std::shared_ptr withdraw() { - extern std::mutex g_fx_mutex; - extern std::unordered_map> g_fx_map; + std::lock_guard lock(g_mutex); - std::lock_guard lock(g_fx_mutex); + const auto found = g_map.find(get_type_index()); - const auto found = g_fx_map.find(typeid(T)); - - if (found == g_fx_map.end()) + if (found == g_map.end()) { return nullptr; } auto ptr = std::static_pointer_cast(std::move(found->second)); - return g_fx_map.erase(found), ptr; + return g_map.erase(found), ptr; } -} +}; diff --git a/rpcs3/Emu/Io/Keyboard.cpp b/rpcs3/Emu/Io/Keyboard.cpp index e23f325b87..052cb2d843 100644 --- a/rpcs3/Emu/Io/Keyboard.cpp +++ b/rpcs3/Emu/Io/Keyboard.cpp @@ -1,60 +1,15 @@ #include "stdafx.h" -#include "rpcs3/Ini.h" -#include "Null/NullKeyboardHandler.h" +#include "Emu/System.h" + #include "Keyboard.h" -GetKeyboardHandlerCountCb GetKeyboardHandlerCount = []() +void KeyboardManager::Init(u32 max_connect) { - return 1; -}; - -GetKeyboardHandlerCb GetKeyboardHandler = [](int i) -> KeyboardHandlerBase* -{ - return new NullKeyboardHandler; -}; - -void SetGetKeyboardHandlerCountCallback(GetKeyboardHandlerCountCb cb) -{ - GetKeyboardHandlerCount = cb; -} - -void SetGetKeyboardHandlerCallback(GetKeyboardHandlerCb cb) -{ - GetKeyboardHandler = cb; -} - -KeyboardManager::KeyboardManager() - : m_keyboard_handler(nullptr) - , m_inited(false) -{ -} - -KeyboardManager::~KeyboardManager() -{ -} - -void KeyboardManager::Init(const u32 max_connect) -{ - if(m_inited) - return; - - // NOTE: Change these to std::make_unique assignments when C++14 comes out. - int numHandlers = GetKeyboardHandlerCount(); - int selectedHandler = Ini.KeyboardHandlerMode.GetValue(); - if (selectedHandler > numHandlers) - { - selectedHandler = 0; - } - m_keyboard_handler.reset(GetKeyboardHandler(selectedHandler)); - + m_keyboard_handler = Emu.GetCallbacks().get_kb_handler(); m_keyboard_handler->Init(max_connect); - m_inited = true; } void KeyboardManager::Close() { - if(m_keyboard_handler) m_keyboard_handler->Close(); - m_keyboard_handler = nullptr; - - m_inited = false; + m_keyboard_handler.reset(); } diff --git a/rpcs3/Emu/Io/Keyboard.h b/rpcs3/Emu/Io/Keyboard.h index 140c06ed4a..c61916dc3b 100644 --- a/rpcs3/Emu/Io/Keyboard.h +++ b/rpcs3/Emu/Io/Keyboard.h @@ -1,16 +1,13 @@ #pragma once + #include "KeyboardHandler.h" class KeyboardManager { - bool m_inited = false; std::unique_ptr m_keyboard_handler; public: - KeyboardManager(); - ~KeyboardManager(); - - void Init(const u32 max_connect); + void Init(u32 max_connect); void Close(); std::vector& GetKeyboards() { return m_keyboard_handler->GetKeyboards(); } @@ -19,11 +16,5 @@ public: KbData& GetData(const u32 keyboard) { return m_keyboard_handler->GetData(keyboard); } KbConfig& GetConfig(const u32 keyboard) { return m_keyboard_handler->GetConfig(keyboard); } - bool IsInited() const { return m_inited; } + bool IsInited() const { return m_keyboard_handler.operator bool(); } }; - -typedef int(*GetKeyboardHandlerCountCb)(); -typedef KeyboardHandlerBase*(*GetKeyboardHandlerCb)(int i); - -void SetGetKeyboardHandlerCountCallback(GetKeyboardHandlerCountCb cb); -void SetGetKeyboardHandlerCallback(GetKeyboardHandlerCb cb); \ No newline at end of file diff --git a/rpcs3/Emu/Io/Mouse.cpp b/rpcs3/Emu/Io/Mouse.cpp index 5a0f191dae..e07534e3c8 100644 --- a/rpcs3/Emu/Io/Mouse.cpp +++ b/rpcs3/Emu/Io/Mouse.cpp @@ -1,60 +1,15 @@ #include "stdafx.h" -#include "rpcs3/Ini.h" -#include "Null/NullMouseHandler.h" +#include "Emu/System.h" + #include "Mouse.h" -GetMouseHandlerCountCb GetMouseHandlerCount = []() +void MouseManager::Init(u32 max_connect) { - return 1; -}; - -GetMouseHandlerCb GetMouseHandler = [](int i) -> MouseHandlerBase* -{ - return new NullMouseHandler; -}; - -void SetGetMouseHandlerCountCallback(GetMouseHandlerCountCb cb) -{ - GetMouseHandlerCount = cb; -} - -void SetGetMouseHandlerCallback(GetMouseHandlerCb cb) -{ - GetMouseHandler = cb; -} - -MouseManager::MouseManager() - : m_mouse_handler(nullptr) - , m_inited(false) -{ -} - -MouseManager::~MouseManager() -{ -} - -void MouseManager::Init(const u32 max_connect) -{ - if(m_inited) - return; - - // NOTE: Change these to std::make_unique assignments when C++14 is available. - int numHandlers = GetMouseHandlerCount(); - int selectedHandler = Ini.MouseHandlerMode.GetValue(); - if (selectedHandler > numHandlers) - { - selectedHandler = 0; - } - m_mouse_handler.reset(GetMouseHandler(selectedHandler)); - + m_mouse_handler = Emu.GetCallbacks().get_mouse_handler(); m_mouse_handler->Init(max_connect); - m_inited = true; } void MouseManager::Close() { - if(m_mouse_handler) m_mouse_handler->Close(); - m_mouse_handler = nullptr; - - m_inited = false; + m_mouse_handler.reset(); } diff --git a/rpcs3/Emu/Io/Mouse.h b/rpcs3/Emu/Io/Mouse.h index c6dbdd61dd..98d86185c4 100644 --- a/rpcs3/Emu/Io/Mouse.h +++ b/rpcs3/Emu/Io/Mouse.h @@ -1,16 +1,13 @@ #pragma once + #include "MouseHandler.h" class MouseManager { - bool m_inited; std::unique_ptr m_mouse_handler; public: - MouseManager(); - ~MouseManager(); - - void Init(const u32 max_connect); + void Init(u32 max_connect); void Close(); std::vector& GetMice() { return m_mouse_handler->GetMice(); } @@ -18,11 +15,5 @@ public: MouseData& GetData(const u32 mouse) { return m_mouse_handler->GetData(mouse); } MouseRawData& GetRawData(const u32 mouse) { return m_mouse_handler->GetRawData(mouse); } - bool IsInited() const { return m_inited; } + bool IsInited() const { return m_mouse_handler.operator bool(); } }; - -typedef int(*GetMouseHandlerCountCb)(); -typedef MouseHandlerBase*(*GetMouseHandlerCb)(int i); - -void SetGetMouseHandlerCountCallback(GetMouseHandlerCountCb cb); -void SetGetMouseHandlerCallback(GetMouseHandlerCb cb); \ No newline at end of file diff --git a/rpcs3/Emu/Io/Pad.cpp b/rpcs3/Emu/Io/Pad.cpp index 72efc937bd..5c3328337d 100644 --- a/rpcs3/Emu/Io/Pad.cpp +++ b/rpcs3/Emu/Io/Pad.cpp @@ -1,60 +1,15 @@ #include "stdafx.h" -#include "rpcs3/Ini.h" -#include "Null/NullPadHandler.h" +#include "Emu/System.h" + #include "Pad.h" -GetPadHandlerCountCb GetPadHandlerCount = []() +void PadManager::Init(u32 max_connect) { - return 1; -}; - -GetPadHandlerCb GetPadHandler = [](int i) -> PadHandlerBase* -{ - return new NullPadHandler; -}; - -void SetGetPadHandlerCountCallback(GetPadHandlerCountCb cb) -{ - GetPadHandlerCount = cb; -} - -void SetGetPadHandlerCallback(GetPadHandlerCb cb) -{ - GetPadHandler = cb; -} - -PadManager::PadManager() - : m_pad_handler(nullptr) - , m_inited(false) -{ -} - -PadManager::~PadManager() -{ -} - -void PadManager::Init(const u32 max_connect) -{ - if(m_inited) - return; - - // NOTE: Change these to std::make_unique assignments when C++14 is available. - int numHandlers = GetPadHandlerCount(); - int selectedHandler = Ini.PadHandlerMode.GetValue(); - if (selectedHandler > numHandlers) - { - selectedHandler = 0; - } - m_pad_handler.reset(GetPadHandler(selectedHandler)); - + m_pad_handler = Emu.GetCallbacks().get_pad_handler(); m_pad_handler->Init(max_connect); - m_inited = true; } void PadManager::Close() { - if(m_pad_handler) m_pad_handler->Close(); - m_pad_handler = nullptr; - - m_inited = false; -} \ No newline at end of file + m_pad_handler.reset(); +} diff --git a/rpcs3/Emu/Io/Pad.h b/rpcs3/Emu/Io/Pad.h index e6a3260464..8bbb3a01f3 100644 --- a/rpcs3/Emu/Io/Pad.h +++ b/rpcs3/Emu/Io/Pad.h @@ -1,27 +1,18 @@ #pragma once + #include "PadHandler.h" class PadManager { - bool m_inited; std::unique_ptr m_pad_handler; public: - PadManager(); - ~PadManager(); - - void Init(const u32 max_connect); + void Init(u32 max_connect); void Close(); std::vector& GetPads() { return m_pad_handler->GetPads(); } PadInfo& GetInfo() { return m_pad_handler->GetInfo(); } std::vector