Merge pull request #1219 from Nekotekina/master

Terrifying PKG installer fix
This commit is contained in:
Hykem 2015-09-22 15:18:13 +01:00
commit faf0a0d851
204 changed files with 4008 additions and 3729 deletions

717
Utilities/Atomic.h Normal file
View File

@ -0,0 +1,717 @@
#pragma once
#if defined(__GNUG__)
template<typename T, typename T2> inline std::enable_if_t<IS_INTEGRAL(T), T> sync_val_compare_and_swap(volatile T* dest, T2 comp, T2 exch)
{
return __sync_val_compare_and_swap(dest, comp, exch);
}
template<typename T, typename T2> inline std::enable_if_t<IS_INTEGRAL(T), bool> sync_bool_compare_and_swap(volatile T* dest, T2 comp, T2 exch)
{
return __sync_bool_compare_and_swap(dest, comp, exch);
}
template<typename T, typename T2> inline std::enable_if_t<IS_INTEGRAL(T), T> sync_lock_test_and_set(volatile T* dest, T2 value)
{
return __sync_lock_test_and_set(dest, value);
}
template<typename T, typename T2> inline std::enable_if_t<IS_INTEGRAL(T), T> sync_fetch_and_add(volatile T* dest, T2 value)
{
return __sync_fetch_and_add(dest, value);
}
template<typename T, typename T2> inline std::enable_if_t<IS_INTEGRAL(T), T> sync_fetch_and_sub(volatile T* dest, T2 value)
{
return __sync_fetch_and_sub(dest, value);
}
template<typename T, typename T2> inline std::enable_if_t<IS_INTEGRAL(T), T> sync_fetch_and_or(volatile T* dest, T2 value)
{
return __sync_fetch_and_or(dest, value);
}
template<typename T, typename T2> inline std::enable_if_t<IS_INTEGRAL(T), T> sync_fetch_and_and(volatile T* dest, T2 value)
{
return __sync_fetch_and_and(dest, value);
}
template<typename T, typename T2> inline std::enable_if_t<IS_INTEGRAL(T), 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<typename T, std::size_t Size = sizeof(T)> struct atomic_storage
{
static_assert(!Size, "Invalid atomic type");
};
template<typename T> struct atomic_storage<T, 1>
{
using type = u8;
};
template<typename T> struct atomic_storage<T, 2>
{
using type = u16;
};
template<typename T> struct atomic_storage<T, 4>
{
using type = u32;
};
template<typename T> struct atomic_storage<T, 8>
{
using type = u64;
};
template<typename T> struct atomic_storage<T, 16>
{
using type = u128;
};
template<typename T> using atomic_storage_t = typename atomic_storage<T>::type;
// result wrapper to deal with void result type
template<typename T, typename RT, typename VT> struct atomic_op_result_t
{
RT result;
template<typename... Args> inline atomic_op_result_t(T func, VT& var, Args&&... args)
: result(std::move(func(var, std::forward<Args>(args)...)))
{
}
inline RT move()
{
return std::move(result);
}
};
// void specialization: result is the initial value of the first arg
template<typename T, typename VT> struct atomic_op_result_t<T, void, VT>
{
VT result;
template<typename... Args> inline atomic_op_result_t(T func, VT& var, Args&&... args)
: result(var)
{
func(var, std::forward<Args>(args)...);
}
inline VT move()
{
return std::move(result);
}
};
// member function specialization
template<typename CT, typename... FArgs, typename RT, typename VT> struct atomic_op_result_t<RT(CT::*)(FArgs...), RT, VT>
{
RT result;
template<typename... Args> inline atomic_op_result_t(RT(CT::*func)(FArgs...), VT& var, Args&&... args)
: result(std::move((var.*func)(std::forward<Args>(args)...)))
{
}
inline RT move()
{
return std::move(result);
}
};
// member function void specialization
template<typename CT, typename... FArgs, typename VT> struct atomic_op_result_t<void(CT::*)(FArgs...), void, VT>
{
VT result;
template<typename... Args> inline atomic_op_result_t(void(CT::*func)(FArgs...), VT& var, Args&&... args)
: result(var)
{
(var.*func)(std::forward<Args>(args)...);
}
inline VT move()
{
return std::move(result);
}
};
template<typename T> class atomic_t
{
using type = std::remove_cv_t<T>;
using stype = atomic_storage_t<type>;
using storage = atomic_storage<type>;
static_assert(alignof(type) <= alignof(stype), "atomic_t<> error: unexpected alignment");
stype m_data;
template<typename T2> 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<typename T2> 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<volatile u128*>(&value), u128{0}, u128{0});
}
public:
static inline const stype to_subtype(const type& value)
{
return reinterpret_cast<const stype&>(value);
}
static inline const type from_subtype(const stype value)
{
return reinterpret_cast<const type&>(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<stype*>(&m_data);
}
// Unsafe direct access
type& raw()
{
return reinterpret_cast<type&>(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<typename F, typename... Args, typename RT = std::result_of_t<F(T&, Args...)>> auto atomic_op(F func, Args&&... args) volatile -> decltype(atomic_op_result_t<F, RT, 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<F, RT, T> result(func, reinterpret_cast<type&>(_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<typename T> inline std::enable_if_t<IS_INTEGRAL(T), T> operator ++(atomic_t<T>& left)
{
return left.from_subtype(sync_fetch_and_add(left.raw_data(), 1) + 1);
}
template<typename T> inline std::enable_if_t<IS_INTEGRAL(T), T> operator --(atomic_t<T>& left)
{
return left.from_subtype(sync_fetch_and_sub(left.raw_data(), 1) - 1);
}
template<typename T> inline std::enable_if_t<IS_INTEGRAL(T), T> operator ++(atomic_t<T>& left, int)
{
return left.from_subtype(sync_fetch_and_add(left.raw_data(), 1));
}
template<typename T> inline std::enable_if_t<IS_INTEGRAL(T), T> operator --(atomic_t<T>& left, int)
{
return left.from_subtype(sync_fetch_and_sub(left.raw_data(), 1));
}
template<typename T, typename T2> inline std::enable_if_t<IS_INTEGRAL(T) && std::is_convertible<T2, T>::value, T> operator +=(atomic_t<T>& left, const T2& right)
{
return left.from_subtype(sync_fetch_and_add(left.raw_data(), right) + right);
}
template<typename T, typename T2> inline std::enable_if_t<IS_INTEGRAL(T) && std::is_convertible<T2, T>::value, T> operator -=(atomic_t<T>& left, const T2& right)
{
return left.from_subtype(sync_fetch_and_sub(left.raw_data(), right) - right);
}
template<typename T> inline std::enable_if_t<IS_INTEGRAL(T), nse_t<T>> operator ++(atomic_t<nse_t<T>>& left)
{
return left.from_subtype(sync_fetch_and_add(left.raw_data(), 1) + 1);
}
template<typename T> inline std::enable_if_t<IS_INTEGRAL(T), nse_t<T>> operator --(atomic_t<nse_t<T>>& left)
{
return left.from_subtype(sync_fetch_and_sub(left.raw_data(), 1) - 1);
}
template<typename T> inline std::enable_if_t<IS_INTEGRAL(T), nse_t<T>> operator ++(atomic_t<nse_t<T>>& left, int)
{
return left.from_subtype(sync_fetch_and_add(left.raw_data(), 1));
}
template<typename T> inline std::enable_if_t<IS_INTEGRAL(T), nse_t<T>> operator --(atomic_t<nse_t<T>>& left, int)
{
return left.from_subtype(sync_fetch_and_sub(left.raw_data(), 1));
}
template<typename T, typename T2> inline std::enable_if_t<IS_INTEGRAL(T) && std::is_convertible<T2, T>::value, nse_t<T>> operator +=(atomic_t<nse_t<T>>& left, const T2& right)
{
return left.from_subtype(sync_fetch_and_add(left.raw_data(), right) + right);
}
template<typename T, typename T2> inline std::enable_if_t<IS_INTEGRAL(T) && std::is_convertible<T2, T>::value, nse_t<T>> operator -=(atomic_t<nse_t<T>>& left, const T2& right)
{
return left.from_subtype(sync_fetch_and_sub(left.raw_data(), right) - right);
}
template<typename T> inline std::enable_if_t<IS_INTEGRAL(T), se_t<T>> operator ++(atomic_t<se_t<T>>& left)
{
return left.atomic_op([](se_t<T>& value) -> se_t<T>
{
return ++value;
});
}
template<typename T> inline std::enable_if_t<IS_INTEGRAL(T), se_t<T>> operator --(atomic_t<se_t<T>>& left)
{
return left.atomic_op([](se_t<T>& value) -> se_t<T>
{
return --value;
});
}
template<typename T> inline std::enable_if_t<IS_INTEGRAL(T), se_t<T>> operator ++(atomic_t<se_t<T>>& left, int)
{
return left.atomic_op([](se_t<T>& value) -> se_t<T>
{
return value++;
});
}
template<typename T> inline std::enable_if_t<IS_INTEGRAL(T), se_t<T>> operator --(atomic_t<se_t<T>>& left, int)
{
return left.atomic_op([](se_t<T>& value) -> se_t<T>
{
return value--;
});
}
template<typename T, typename T2> inline std::enable_if_t<IS_INTEGRAL(T) && std::is_convertible<T2, T>::value, se_t<T>> operator +=(atomic_t<se_t<T>>& left, const T2& right)
{
return left.atomic_op([&](se_t<T>& value) -> se_t<T>
{
return value += right;
});
}
template<typename T, typename T2> inline std::enable_if_t<IS_INTEGRAL(T) && std::is_convertible<T2, T>::value, se_t<T>> operator -=(atomic_t<se_t<T>>& left, const T2& right)
{
return left.atomic_op([&](se_t<T>& value) -> se_t<T>
{
return value -= right;
});
}
template<typename T> using atomic_be_t = atomic_t<be_t<T>>; // Atomic BE Type (for PS3 virtual memory)
template<typename T> using atomic_le_t = atomic_t<le_t<T>>; // Atomic LE Type (for PSV virtual memory)
// Algorithm for std::atomic; similar to atomic_t::atomic_op()
template<typename T, typename F, typename... Args, typename RT = std::result_of_t<F(T&, Args...)>> auto atomic_op(std::atomic<T>& var, F func, Args&&... args) -> decltype(atomic_op_result_t<F, RT, T>::result)
{
auto old = var.load();
while (true)
{
auto _new = old;
atomic_op_result_t<F, RT, T> result(func, _new, args...);
if (var.compare_exchange_strong(old, _new)) return result.move();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -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<typename T, typename TT = void> using if_integral_t = std::enable_if_t<std::is_integral<T>::value || std::is_same<std::remove_cv_t<T>, __uint128_t>::value, TT>;
#if defined(__GNUG__)
template<typename T, typename T2> inline if_integral_t<T, T> sync_val_compare_and_swap(volatile T* dest, T2 comp, T2 exch)
{
return __sync_val_compare_and_swap(dest, comp, exch);
}
template<typename T, typename T2> inline if_integral_t<T, bool> sync_bool_compare_and_swap(volatile T* dest, T2 comp, T2 exch)
{
return __sync_bool_compare_and_swap(dest, comp, exch);
}
template<typename T, typename T2> inline if_integral_t<T, T> sync_lock_test_and_set(volatile T* dest, T2 value)
{
return __sync_lock_test_and_set(dest, value);
}
template<typename T, typename T2> inline if_integral_t<T, T> sync_fetch_and_add(volatile T* dest, T2 value)
{
return __sync_fetch_and_add(dest, value);
}
template<typename T, typename T2> inline if_integral_t<T, T> sync_fetch_and_sub(volatile T* dest, T2 value)
{
return __sync_fetch_and_sub(dest, value);
}
template<typename T, typename T2> inline if_integral_t<T, T> sync_fetch_and_or(volatile T* dest, T2 value)
{
return __sync_fetch_and_or(dest, value);
}
template<typename T, typename T2> inline if_integral_t<T, T> sync_fetch_and_and(volatile T* dest, T2 value)
{
return __sync_fetch_and_and(dest, value);
}
template<typename T, typename T2> inline if_integral_t<T, 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)

View File

@ -1,42 +1,32 @@
#pragma once
template<typename T>
struct BaseInterval
template<typename T1, typename T2> 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<typename T1, typename T2> constexpr range_t<std::decay_t<T1>, std::decay_t<T2>> make_range(T1&& _min, T2&& _max)
{
return{ std::forward<T1>(_min), std::forward<T2>(_max) };
}
static BaseInterval<T> make(T min_value, T max_value)
{
BaseInterval<T> res = { min_value, max_value };
return res;
}
template<typename T1, typename T2, typename T> constexpr bool operator <(const range_t<T1, T2>& range, const T& value)
{
return range._min < value && range._max < value;
}
static BaseInterval<T> make()
{
return make((T&)zero, (T&)notz);
}
template<typename T1, typename T2, typename T> constexpr bool operator <(const T& value, const range_t<T1, T2>& 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<typename T1, typename T2, typename T> constexpr bool operator ==(const range_t<T1, T2>& range, const T& value)
{
return !(value < range._min) && !(range._max < value);
}
bool isindef()
{
if (T == float)
{
}
}
};
template<typename T1, typename T2, typename T> constexpr bool operator ==(const T& value, const range_t<T1, T2>& range)
{
return !(value < range._min) && !(range._max < value);
}

View File

@ -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)
{
}

152
Utilities/SharedMutex.cpp Normal file
View File

@ -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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> lock(m_mutex);
if (info.waiting_writers) m_wcv.notify_one();
else if (info.waiting_readers) m_rcv.notify_all();
}
}

46
Utilities/SharedMutex.h Normal file
View File

@ -0,0 +1,46 @@
#pragma once
#include <shared_mutex>
// 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<ownership_info_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();
};

View File

@ -145,8 +145,7 @@ namespace fmt
std::string to_udec(u64 value);
std::string to_sdec(s64 value);
template<typename T, bool is_enum = std::is_enum<T>::value>
struct unveil
template<typename T, bool is_enum = std::is_enum<T>::value> struct unveil
{
using result_type = T;
@ -156,8 +155,7 @@ namespace fmt
}
};
template<>
struct unveil<char*, false>
template<> struct unveil<char*, false>
{
using result_type = const char*;
@ -167,8 +165,7 @@ namespace fmt
}
};
template<size_t N>
struct unveil<const char[N], false>
template<std::size_t N> struct unveil<const char[N], false>
{
using result_type = const char*;
@ -178,8 +175,7 @@ namespace fmt
}
};
template<>
struct unveil<std::string, false>
template<> struct unveil<std::string, false>
{
using result_type = const char*;
@ -189,8 +185,7 @@ namespace fmt
}
};
template<typename T>
struct unveil<T, true>
template<typename T> struct unveil<T, true>
{
using result_type = std::underlying_type_t<T>;
@ -200,25 +195,13 @@ namespace fmt
}
};
template<typename T>
struct unveil<be_t<T>, false>
template<typename T, bool Se> struct unveil<se_t<T, Se>, false>
{
using result_type = typename unveil<T>::result_type;
force_inline static result_type get_value(const be_t<T>& arg)
force_inline static result_type get_value(const se_t<T, Se>& arg)
{
return unveil<T>::get_value(arg.value());
}
};
template<typename T>
struct unveil<le_t<T>, false>
{
using result_type = typename unveil<T>::result_type;
force_inline static result_type get_value(const le_t<T>& arg)
{
return unveil<T>::get_value(arg.value());
return unveil<T>::get_value(arg);
}
};
@ -270,11 +253,11 @@ namespace fmt
}
}
struct exception
struct exception : public std::exception
{
std::unique_ptr<char[]> message;
template<typename... Args> never_inline safe_buffers exception(const char* file, int line, const char* func, const char* text, Args... args)
template<typename... Args> 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();
}

View File

@ -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<std::string()> name, std::function<void
LOG_NOTICE(GENERAL, "Thread ended");
}
}
catch (const fmt::exception& e)
{
LOG_ERROR(GENERAL, "Exception: %s", e.message.get());
Emu.Pause();
}
catch (const std::exception& e)
{
LOG_ERROR(GENERAL, "STD Exception: %s", e.what());
LOG_ERROR(GENERAL, "Exception: %s", e.what());
Emu.Pause();
}
catch (EmulationStopped)

View File

@ -147,7 +147,7 @@ class squeue_t
public:
squeue_t()
: m_sync({})
: m_sync(squeue_sync_var_t{})
{
}
@ -156,9 +156,9 @@ public:
return sq_size;
}
bool is_full() const volatile
bool is_full() const
{
return m_sync.data.count == sq_size;
return m_sync.load().count == sq_size;
}
bool push(const T& data, const std::function<bool()>& test_exit)

View File

@ -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: <wx/progdlg.h>")
#pragma warning(disable : 4996)
#include <wx/progdlg.h>
#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<u64>& hi = (be_t<u64>&)iv[0];
be_t<u64>& lo = (be_t<u64>&)iv[8];
// Allocate buffers with BUF_SIZE size or more if required
const u64 buffer_size = std::max<u64>(BUF_SIZE, sizeof(PKGEntry) * header.file_count);
const std::unique_ptr<u8[]> 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<u128[]> buf(new u128[std::max<u64>(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<u64> 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<u64>*)&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<u8*>(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<u128> 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<u8*>(&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<char*>(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<u64>(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;

View File

@ -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<u64> data_offset; // Encrypted data offset
be_t<u64> 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<u64> qa_digest[2]; // This should be the hash of "files + attribs"
be_t<u128> klicensee; // Nonce
};
struct PKGEntry
@ -59,6 +58,4 @@ struct PKGEntry
be_t<u32> 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);

View File

@ -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);
}

View File

@ -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<ARMv7Thread>(id);
});
idm::remove<ARMv7Thread>(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<s32> pNumWaitThr
*pNumWaitThreads = static_cast<u32>(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<SceKernelEventFlagInfo> pInfo)
pInfo->attr = evf->attr;
pInfo->initPattern = evf->init;
pInfo->currentPattern = evf->pattern.load();
pInfo->currentPattern = evf->pattern;
pInfo->numWaitThreads = static_cast<u32>(evf->sq.size());
return SCE_OK;

View File

@ -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<std::mutex> 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);
}
};

View File

@ -188,7 +188,7 @@ namespace sce_libc_func
sceLibc.Success("Process finished");
CallAfter([]()
Emu.CallAfter([]()
{
Emu.Stop();
});

View File

@ -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<std::string()> 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<std::mutex> 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;

View File

@ -45,7 +45,7 @@ protected:
using named_thread_t::join;
using named_thread_t::joinable;
atomic_t<u64> m_state; // thread state flags
atomic_t<u64> m_state{ CPU_STATE_STOPPED }; // thread state flags
std::unique_ptr<CPUDecoder> 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;

View File

@ -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<RawSPUThread> CPUThreadManager::NewRawSPUThread()
break;
}
}
return result;
}

View File

@ -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("");
}

View File

@ -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 <stdint.h>
@ -16,7 +13,7 @@
#include <fenv.h>
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)

View File

@ -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"

View File

@ -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<void>("PPUThread.FastStop", &PPUThread::fast_stop, m_state.args[CompileTaskState::Args::State]);
Call<void>("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 },

View File

@ -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]);
}
}

View File

@ -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();

View File

@ -1012,3 +1012,20 @@ force_inline T cast_from_ppu_gpr(const u64 reg)
{
return cast_ppu_gpr<T>::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
};

View File

@ -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);
}

View File

@ -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<SPURecompilerDecoder&>(*_spu->m_dec).DecodeMemory(_spu->offset + _spu->pc);
if (_spu->m_state.load() & CPU_STATE_RETURN)
if (_spu->m_state & CPU_STATE_RETURN)
{
break;
}

View File

@ -40,8 +40,6 @@ SPUDatabase::~SPUDatabase()
std::shared_ptr<spu_function_t> SPUDatabase::analyse(const be_t<u32>* ls, u32 entry, u32 max_limit)
{
std::lock_guard<std::mutex> 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<spu_function_t> SPUDatabase::analyse(const be_t<u32>* 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<shared_mutex_t> 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<shared_mutex_t> lock(m_mutex);
// Double-check
if (auto func = find(ls + entry / 4, key, max_limit - entry))
{
return func;

View File

@ -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<u64, std::shared_ptr<spu_function_t>> m_db;

View File

@ -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<std::mutex> 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;
}

View File

@ -147,13 +147,13 @@ struct spu_channel_t
u32 value;
};
atomic_t<sync_var_t> sync_var;
atomic_t<sync_var_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<bool, u32> 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_t> sync_var;
atomic_t<sync_var_t> values;
atomic_t<u32> 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<bool, u32, u32> 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

View File

@ -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;
}

View File

@ -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);

View File

@ -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<u32, id_data_t> g_id_map;
std::unordered_map<u32, id_data_t> 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<std::mutex> 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<std::type_index, std::shared_ptr<void>> g_fx_map;
void clear()
{
std::lock_guard<std::mutex> lock(g_fx_mutex);
g_fx_map.clear();
}
}
std::unordered_map<const void*, std::shared_ptr<void>> fxm::g_map;

View File

@ -2,6 +2,15 @@
#define ID_MANAGER_INCLUDED
template<typename T> struct type_info_t { static char value; };
template<typename T> char type_info_t<T>::value = 42;
template<typename T> constexpr inline const void* get_type_index()
{
return &type_info_t<T>::value;
}
// default traits for any arbitrary type
template<typename T> struct id_traits
{
@ -15,24 +24,16 @@ template<typename T> 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<void> data;
const std::type_info& info;
const std::size_t hash;
std::shared_ptr<void> data;
const std::type_info* info;
const void* type_index;
template<typename T> force_inline id_data_t(std::shared_ptr<T> data)
template<typename T> inline id_data_t(std::shared_ptr<T> 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<std::shared_ptr<void>&>(right.data)))
, info(right.info)
, hash(right.hash)
, info(&typeid(T))
, type_index(get_type_index<T>())
{
}
};
@ -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<u32, id_data_t> 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<std::mutex> lock(g_mutex);
g_map.clear();
g_last_raw_id = 0;
}
// check if ID of specified type exists
template<typename T> bool check(u32 id)
template<typename T> static bool check(u32 id)
{
extern std::mutex g_id_mutex;
extern std::unordered_map<u32, id_data_t> g_id_map;
std::lock_guard<std::mutex> lock(g_mutex);
const auto found = g_map.find(id_traits<T>::in_id(id));
std::lock_guard<std::mutex> lock(g_id_mutex);
const auto found = g_id_map.find(id_traits<T>::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<T>();
}
// 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<u32, id_data_t> g_id_map;
std::lock_guard<std::mutex> lock(g_mutex);
std::lock_guard<std::mutex> 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<typename T, typename... Args> std::enable_if_t<std::is_constructible<T, Args...>::value, std::shared_ptr<T>> make_ptr(Args&&... args)
template<typename T, typename... Args> static std::enable_if_t<std::is_constructible<T, Args...>::value, std::shared_ptr<T>> make_ptr(Args&&... args)
{
extern std::mutex g_id_mutex;
extern std::unordered_map<u32, id_data_t> g_id_map;
extern u32 g_last_raw_id;
thread_local extern u32 g_tls_last_id;
std::lock_guard<std::mutex> lock(g_mutex);
std::lock_guard<std::mutex> lock(g_id_mutex);
u32 raw_id = g_last_raw_id;
while ((raw_id = id_traits<T>::next_id(raw_id)))
for (u32 raw_id = g_last_raw_id; (raw_id = id_traits<T>::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<T>::out_id(raw_id);
auto ptr = std::make_shared<T>(std::forward<Args>(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<typename T, typename... Args> std::enable_if_t<std::is_constructible<T, Args...>::value, u32> make(Args&&... args)
template<typename T, typename... Args> static std::enable_if_t<std::is_constructible<T, Args...>::value, u32> make(Args&&... args)
{
extern std::mutex g_id_mutex;
extern std::unordered_map<u32, id_data_t> g_id_map;
extern u32 g_last_raw_id;
thread_local extern u32 g_tls_last_id;
std::lock_guard<std::mutex> lock(g_mutex);
std::lock_guard<std::mutex> lock(g_id_mutex);
u32 raw_id = g_last_raw_id;
while ((raw_id = id_traits<T>::next_id(raw_id)))
for (u32 raw_id = g_last_raw_id; (raw_id = id_traits<T>::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<T>::out_id(raw_id);
g_id_map.emplace(raw_id, id_data_t(std::make_shared<T>(std::forward<Args>(args)...)));
g_map.emplace(raw_id, id_data_t(std::make_shared<T>(std::forward<Args>(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<typename T> u32 import(const std::shared_ptr<T>& ptr)
template<typename T> static u32 import(const std::shared_ptr<T>& ptr)
{
extern std::mutex g_id_mutex;
extern std::unordered_map<u32, id_data_t> g_id_map;
extern u32 g_last_raw_id;
thread_local extern u32 g_tls_last_id;
std::lock_guard<std::mutex> lock(g_mutex);
std::lock_guard<std::mutex> lock(g_id_mutex);
u32 raw_id = g_last_raw_id;
while ((raw_id = id_traits<T>::next_id(raw_id)))
for (u32 raw_id = g_last_raw_id; (raw_id = id_traits<T>::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<T>::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<typename T> std::shared_ptr<T> get(u32 id)
template<typename T> static std::shared_ptr<T> get(u32 id)
{
extern std::mutex g_id_mutex;
extern std::unordered_map<u32, id_data_t> g_id_map;
std::lock_guard<std::mutex> lock(g_mutex);
std::lock_guard<std::mutex> lock(g_id_mutex);
const auto found = g_map.find(id_traits<T>::in_id(id));
const auto found = g_id_map.find(id_traits<T>::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<T>())
{
return nullptr;
}
@ -185,20 +168,17 @@ namespace idm
}
// get all IDs of specified type T (unsorted)
template<typename T> std::vector<std::shared_ptr<T>> get_all()
template<typename T> static std::vector<std::shared_ptr<T>> get_all()
{
extern std::mutex g_id_mutex;
extern std::unordered_map<u32, id_data_t> g_id_map;
std::lock_guard<std::mutex> lock(g_id_mutex);
std::lock_guard<std::mutex> lock(g_mutex);
std::vector<std::shared_ptr<T>> result;
const std::size_t hash = typeid(T).hash_code();
const auto type = get_type_index<T>();
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<T>(v.second.data));
}
@ -208,61 +188,52 @@ namespace idm
}
// remove ID created with type T
template<typename T> bool remove(u32 id)
template<typename T> static bool remove(u32 id)
{
extern std::mutex g_id_mutex;
extern std::unordered_map<u32, id_data_t> g_id_map;
std::lock_guard<std::mutex> lock(g_mutex);
std::lock_guard<std::mutex> lock(g_id_mutex);
const auto found = g_map.find(id_traits<T>::in_id(id));
const auto found = g_id_map.find(id_traits<T>::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<T>())
{
return false;
}
g_id_map.erase(found);
g_map.erase(found);
return true;
}
// remove ID created with type T and return the object
template<typename T> std::shared_ptr<T> withdraw(u32 id)
template<typename T> static std::shared_ptr<T> withdraw(u32 id)
{
extern std::mutex g_id_mutex;
extern std::unordered_map<u32, id_data_t> g_id_map;
std::lock_guard<std::mutex> lock(g_mutex);
std::lock_guard<std::mutex> lock(g_id_mutex);
const auto found = g_map.find(id_traits<T>::in_id(id));
const auto found = g_id_map.find(id_traits<T>::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<T>())
{
return nullptr;
}
auto ptr = std::static_pointer_cast<T>(found->second.data);
g_id_map.erase(found);
g_map.erase(found);
return ptr;
}
template<typename T> u32 get_count()
template<typename T> static u32 get_count()
{
extern std::mutex g_id_mutex;
extern std::unordered_map<u32, id_data_t> g_id_map;
std::lock_guard<std::mutex> lock(g_id_mutex);
std::lock_guard<std::mutex> lock(g_mutex);
u32 result = 0;
const std::size_t hash = typeid(T).hash_code();
const auto type = get_type_index<T>();
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<typename T> std::set<u32> get_set()
template<typename T> static std::set<u32> get_set()
{
extern std::mutex g_id_mutex;
extern std::unordered_map<u32, id_data_t> g_id_map;
std::lock_guard<std::mutex> lock(g_id_mutex);
std::lock_guard<std::mutex> lock(g_mutex);
std::set<u32> result;
const std::size_t hash = typeid(T).hash_code();
const auto type = get_type_index<T>();
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<T>::out_id(v.first));
}
@ -295,20 +263,17 @@ namespace idm
}
// get sorted ID map (ID value -> ID data) of specified type
template<typename T> std::map<u32, std::shared_ptr<T>> get_map()
template<typename T> static std::map<u32, std::shared_ptr<T>> get_map()
{
extern std::mutex g_id_mutex;
extern std::unordered_map<u32, id_data_t> g_id_map;
std::lock_guard<std::mutex> lock(g_id_mutex);
std::lock_guard<std::mutex> lock(g_mutex);
std::map<u32, std::shared_ptr<T>> result;
const std::size_t hash = typeid(T).hash_code();
const auto type = get_type_index<T>();
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<T>::out_id(v.first)] = std::static_pointer_cast<T>(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<const void*, std::shared_ptr<void>> g_map;
// reinitialize
void clear();
static void clear()
{
std::lock_guard<std::mutex> 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<typename T, typename... Args> std::enable_if_t<std::is_constructible<T, Args...>::value, std::shared_ptr<T>> make(Args&&... args)
template<typename T, typename... Args> static std::enable_if_t<std::is_constructible<T, Args...>::value, std::shared_ptr<T>> make(Args&&... args)
{
extern std::mutex g_fx_mutex;
extern std::unordered_map<std::type_index, std::shared_ptr<void>> g_fx_map;
std::lock_guard<std::mutex> lock(g_mutex);
std::lock_guard<std::mutex> lock(g_fx_mutex);
const auto index = get_type_index<T>();
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<T>(std::forward<Args>(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<typename T, typename... Args> std::enable_if_t<std::is_constructible<T, Args...>::value, std::shared_ptr<T>> make_always(Args&&... args)
template<typename T, typename... Args> static std::enable_if_t<std::is_constructible<T, Args...>::value, std::shared_ptr<T>> make_always(Args&&... args)
{
extern std::mutex g_fx_mutex;
extern std::unordered_map<std::type_index, std::shared_ptr<void>> g_fx_map;
std::lock_guard<std::mutex> lock(g_fx_mutex);
std::lock_guard<std::mutex> lock(g_mutex);
auto ptr = std::make_shared<T>(std::forward<Args>(args)...);
g_fx_map[typeid(T)] = ptr;
g_map[get_type_index<T>()] = ptr;
return ptr;
}
// import existing fixed object of specified type only if it doesn't exist (don't use)
template<typename T> static std::shared_ptr<T> import(std::shared_ptr<T>&& ptr)
{
std::lock_guard<std::mutex> lock(g_mutex);
const auto index = get_type_index<T>();
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<typename T> static std::shared_ptr<T> import_always(std::shared_ptr<T>&& ptr)
{
std::lock_guard<std::mutex> lock(g_mutex);
g_map[get_type_index<T>()] = ptr;
return ptr;
}
// get fixed object of specified type (always returns an object, it's created if it doesn't exist)
template<typename T, typename... Args> std::enable_if_t<std::is_constructible<T, Args...>::value, std::shared_ptr<T>> get_always(Args&&... args)
template<typename T, typename... Args> static std::enable_if_t<std::is_constructible<T, Args...>::value, std::shared_ptr<T>> get_always(Args&&... args)
{
extern std::mutex g_fx_mutex;
extern std::unordered_map<std::type_index, std::shared_ptr<void>> g_fx_map;
std::lock_guard<std::mutex> lock(g_mutex);
std::lock_guard<std::mutex> lock(g_fx_mutex);
const auto index = get_type_index<T>();
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<T>(std::forward<Args>(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<typename T> bool check()
template<typename T> static bool check()
{
extern std::mutex g_fx_mutex;
extern std::unordered_map<std::type_index, std::shared_ptr<void>> g_fx_map;
std::lock_guard<std::mutex> lock(g_mutex);
std::lock_guard<std::mutex> lock(g_fx_mutex);
return g_fx_map.find(typeid(T)) != g_fx_map.end();
return g_map.find(get_type_index<T>()) != g_map.end();
}
// get fixed object of specified type (returns nullptr if it doesn't exist)
template<typename T> std::shared_ptr<T> get()
template<typename T> static std::shared_ptr<T> get()
{
extern std::mutex g_fx_mutex;
extern std::unordered_map<std::type_index, std::shared_ptr<void>> g_fx_map;
std::lock_guard<std::mutex> lock(g_mutex);
std::lock_guard<std::mutex> lock(g_fx_mutex);
const auto found = g_map.find(get_type_index<T>());
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<typename T> bool remove()
template<typename T> static bool remove()
{
extern std::mutex g_fx_mutex;
extern std::unordered_map<std::type_index, std::shared_ptr<void>> g_fx_map;
std::lock_guard<std::mutex> lock(g_mutex);
std::lock_guard<std::mutex> lock(g_fx_mutex);
const auto found = g_map.find(get_type_index<T>());
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<typename T> std::shared_ptr<T> withdraw()
template<typename T> static std::shared_ptr<T> withdraw()
{
extern std::mutex g_fx_mutex;
extern std::unordered_map<std::type_index, std::shared_ptr<void>> g_fx_map;
std::lock_guard<std::mutex> lock(g_mutex);
std::lock_guard<std::mutex> lock(g_fx_mutex);
const auto found = g_map.find(get_type_index<T>());
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<T>(std::move(found->second));
return g_fx_map.erase(found), ptr;
return g_map.erase(found), ptr;
}
}
};

View File

@ -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();
}

View File

@ -1,16 +1,13 @@
#pragma once
#include "KeyboardHandler.h"
class KeyboardManager
{
bool m_inited = false;
std::unique_ptr<KeyboardHandlerBase> m_keyboard_handler;
public:
KeyboardManager();
~KeyboardManager();
void Init(const u32 max_connect);
void Init(u32 max_connect);
void Close();
std::vector<Keyboard>& 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);

View File

@ -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();
}

View File

@ -1,16 +1,13 @@
#pragma once
#include "MouseHandler.h"
class MouseManager
{
bool m_inited;
std::unique_ptr<MouseHandlerBase> m_mouse_handler;
public:
MouseManager();
~MouseManager();
void Init(const u32 max_connect);
void Init(u32 max_connect);
void Close();
std::vector<Mouse>& 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);

View File

@ -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;
}
m_pad_handler.reset();
}

View File

@ -1,27 +1,18 @@
#pragma once
#include "PadHandler.h"
class PadManager
{
bool m_inited;
std::unique_ptr<PadHandlerBase> m_pad_handler;
public:
PadManager();
~PadManager();
void Init(const u32 max_connect);
void Init(u32 max_connect);
void Close();
std::vector<Pad>& GetPads() { return m_pad_handler->GetPads(); }
PadInfo& GetInfo() { return m_pad_handler->GetInfo(); }
std::vector<Button>& GetButtons(const u32 pad) { return m_pad_handler->GetButtons(pad); }
bool IsInited() const { return m_inited; }
bool IsInited() const { return m_pad_handler.operator bool(); }
};
typedef int(*GetPadHandlerCountCb)();
typedef PadHandlerBase*(*GetPadHandlerCb)(int i);
void SetGetPadHandlerCountCallback(GetPadHandlerCountCb cb);
void SetGetPadHandlerCallback(GetPadHandlerCb cb);

View File

@ -1,355 +0,0 @@
#pragma once
template<typename T, size_t size = sizeof(T)> struct _to_atomic_subtype
{
static_assert(size == 1 || size == 2 || size == 4 || size == 8 || size == 16, "Invalid atomic type");
};
template<typename T> struct _to_atomic_subtype<T, 1>
{
using type = u8;
};
template<typename T> struct _to_atomic_subtype<T, 2>
{
using type = u16;
};
template<typename T> struct _to_atomic_subtype<T, 4>
{
using type = u32;
};
template<typename T> struct _to_atomic_subtype<T, 8>
{
using type = u64;
};
template<typename T> struct _to_atomic_subtype<T, 16>
{
using type = u128;
};
template<typename T> using atomic_subtype_t = typename _to_atomic_subtype<T>::type;
// result wrapper to deal with void result type
template<typename T, typename RT, typename VT> struct atomic_op_result_t
{
RT result;
template<typename... Args> inline atomic_op_result_t(T func, VT& var, Args&&... args)
: result(std::move(func(var, std::forward<Args>(args)...)))
{
}
inline RT move()
{
return std::move(result);
}
};
// void specialization: result is the initial value of the first arg
template<typename T, typename VT> struct atomic_op_result_t<T, void, VT>
{
VT result;
template<typename... Args> inline atomic_op_result_t(T func, VT& var, Args&&... args)
: result(var)
{
func(var, std::forward<Args>(args)...);
}
inline VT move()
{
return std::move(result);
}
};
// member function specialization
template<typename CT, typename... FArgs, typename RT, typename VT> struct atomic_op_result_t<RT(CT::*)(FArgs...), RT, VT>
{
RT result;
template<typename... Args> inline atomic_op_result_t(RT(CT::*func)(FArgs...), VT& var, Args&&... args)
: result(std::move((var.*func)(std::forward<Args>(args)...)))
{
}
inline RT move()
{
return std::move(result);
}
};
// member function void specialization
template<typename CT, typename... FArgs, typename VT> struct atomic_op_result_t<void(CT::*)(FArgs...), void, VT>
{
VT result;
template<typename... Args> inline atomic_op_result_t(void(CT::*func)(FArgs...), VT& var, Args&&... args)
: result(var)
{
(var.*func)(std::forward<Args>(args)...);
}
inline VT move()
{
return std::move(result);
}
};
template<typename T> union _atomic_base
{
using type = std::remove_cv_t<T>;
using subtype = atomic_subtype_t<type>;
type data; // unsafe direct access
subtype sub_data; // unsafe direct access to substitute type
force_inline static const subtype to_subtype(const type& value)
{
return reinterpret_cast<const subtype&>(value);
}
force_inline static const type from_subtype(const subtype value)
{
return reinterpret_cast<const type&>(value);
}
force_inline static type& to_type(subtype& value)
{
return reinterpret_cast<type&>(value);
}
private:
template<typename T2> force_inline static void write_relaxed(volatile T2& data, const T2& value)
{
data = value;
}
force_inline static void write_relaxed(volatile u128& data, const u128& value)
{
sync_lock_test_and_set(&data, value);
}
template<typename T2> force_inline static T2 read_relaxed(const volatile T2& data)
{
return data;
}
force_inline static u128 read_relaxed(const volatile u128& value)
{
return sync_val_compare_and_swap(const_cast<volatile u128*>(&value), u128{0}, u128{0});
}
public:
// atomically compare data with cmp, replace with exch if equal, return previous data value anyway
force_inline const type compare_and_swap(const type& cmp, const type& exch) volatile
{
return from_subtype(sync_val_compare_and_swap(&sub_data, to_subtype(cmp), to_subtype(exch)));
}
// atomically compare data with cmp, replace with exch if equal, return true if data was replaced
force_inline bool compare_and_swap_test(const type& cmp, const type& exch) volatile
{
return sync_bool_compare_and_swap(&sub_data, to_subtype(cmp), to_subtype(exch));
}
// read data with memory barrier
force_inline const type load_sync() const volatile
{
const subtype zero = {};
return from_subtype(sync_val_compare_and_swap(const_cast<subtype*>(&sub_data), zero, zero));
}
// atomically replace data with exch, return previous data value
force_inline const type exchange(const type& exch) volatile
{
return from_subtype(sync_lock_test_and_set(&sub_data, to_subtype(exch)));
}
// read data without memory barrier (works as load_sync() for 128 bit)
force_inline const type load() const volatile
{
return from_subtype(read_relaxed(sub_data));
}
// write data without memory barrier (works as exchange() for 128 bit, discarding result)
force_inline void store(const type& value) volatile
{
write_relaxed(sub_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<typename F, typename... Args, typename RT = std::result_of_t<F(T&, Args...)>> auto atomic_op(F func, Args&&... args) volatile -> decltype(atomic_op_result_t<F, RT, T>::result)
{
while (true)
{
// read the old value from memory
const subtype old = read_relaxed(sub_data);
// copy the old value
subtype _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<F, RT, T> result(func, to_type(_new), args...);
// atomically compare value with `old`, replace with `_new` and return on success
if (sync_bool_compare_and_swap(&sub_data, old, _new)) return result.move();
}
}
// atomic bitwise OR, returns previous data
force_inline const type _or(const type& right) volatile
{
return from_subtype(sync_fetch_and_or(&sub_data, to_subtype(right)));
}
// atomic bitwise AND, returns previous data
force_inline const type _and(const type& right) volatile
{
return from_subtype(sync_fetch_and_and(&sub_data, to_subtype(right)));
}
// atomic bitwise AND NOT (inverts right argument), returns previous data
force_inline const type _and_not(const type& right) volatile
{
return from_subtype(sync_fetch_and_and(&sub_data, ~to_subtype(right)));
}
// atomic bitwise XOR, returns previous data
force_inline const type _xor(const type& right) volatile
{
return from_subtype(sync_fetch_and_xor(&sub_data, to_subtype(right)));
}
force_inline const type operator |=(const type& right) volatile
{
return from_subtype(sync_fetch_and_or(&sub_data, to_subtype(right)) | to_subtype(right));
}
force_inline const type operator &=(const type& right) volatile
{
return from_subtype(sync_fetch_and_and(&sub_data, to_subtype(right)) & to_subtype(right));
}
force_inline const type operator ^=(const type& right) volatile
{
return from_subtype(sync_fetch_and_xor(&sub_data, to_subtype(right)) ^ to_subtype(right));
}
};
template<typename T, typename = if_integral_t<T>> inline T operator ++(_atomic_base<T>& left)
{
return left.from_subtype(sync_fetch_and_add(&left.sub_data, 1) + 1);
}
template<typename T, typename = if_integral_t<T>> inline T operator --(_atomic_base<T>& left)
{
return left.from_subtype(sync_fetch_and_sub(&left.sub_data, 1) - 1);
}
template<typename T, typename = if_integral_t<T>> inline T operator ++(_atomic_base<T>& left, int)
{
return left.from_subtype(sync_fetch_and_add(&left.sub_data, 1));
}
template<typename T, typename = if_integral_t<T>> inline T operator --(_atomic_base<T>& left, int)
{
return left.from_subtype(sync_fetch_and_sub(&left.sub_data, 1));
}
template<typename T, typename T2, typename = if_integral_t<T>> inline auto operator +=(_atomic_base<T>& left, T2 right) -> decltype(std::declval<T>() + std::declval<T2>())
{
return left.from_subtype(sync_fetch_and_add(&left.sub_data, right) + right);
}
template<typename T, typename T2, typename = if_integral_t<T>> inline auto operator -=(_atomic_base<T>& left, T2 right) -> decltype(std::declval<T>() - std::declval<T2>())
{
return left.from_subtype(sync_fetch_and_sub(&left.sub_data, right) - right);
}
template<typename T, typename = if_integral_t<T>> inline le_t<T> operator ++(_atomic_base<le_t<T>>& left)
{
return left.from_subtype(sync_fetch_and_add(&left.sub_data, 1) + 1);
}
template<typename T, typename = if_integral_t<T>> inline le_t<T> operator --(_atomic_base<le_t<T>>& left)
{
return left.from_subtype(sync_fetch_and_sub(&left.sub_data, 1) - 1);
}
template<typename T, typename = if_integral_t<T>> inline le_t<T> operator ++(_atomic_base<le_t<T>>& left, int)
{
return left.from_subtype(sync_fetch_and_add(&left.sub_data, 1));
}
template<typename T, typename = if_integral_t<T>> inline le_t<T> operator --(_atomic_base<le_t<T>>& left, int)
{
return left.from_subtype(sync_fetch_and_sub(&left.sub_data, 1));
}
template<typename T, typename T2, typename = if_integral_t<T>> inline auto operator +=(_atomic_base<le_t<T>>& left, T2 right) -> decltype(std::declval<T>() + std::declval<T2>())
{
return left.from_subtype(sync_fetch_and_add(&left.sub_data, right) + right);
}
template<typename T, typename T2, typename = if_integral_t<T>> inline auto operator -=(_atomic_base<le_t<T>>& left, T2 right) -> decltype(std::declval<T>() - std::declval<T2>())
{
return left.from_subtype(sync_fetch_and_sub(&left.sub_data, right) - right);
}
template<typename T, typename = if_integral_t<T>> inline be_t<T> operator ++(_atomic_base<be_t<T>>& left)
{
return left.atomic_op([](be_t<T>& value) -> be_t<T>
{
return ++value;
});
}
template<typename T, typename = if_integral_t<T>> inline be_t<T> operator --(_atomic_base<be_t<T>>& left)
{
return left.atomic_op([](be_t<T>& value) -> be_t<T>
{
return --value;
});
}
template<typename T, typename = if_integral_t<T>> inline be_t<T> operator ++(_atomic_base<be_t<T>>& left, int)
{
return left.atomic_op([](be_t<T>& value) -> be_t<T>
{
return value++;
});
}
template<typename T, typename = if_integral_t<T>> inline be_t<T> operator --(_atomic_base<be_t<T>>& left, int)
{
return left.atomic_op([](be_t<T>& value) -> be_t<T>
{
return value--;
});
}
template<typename T, typename T2, typename = if_integral_t<T>> inline auto operator +=(_atomic_base<be_t<T>>& left, T2 right) -> be_t<decltype(std::declval<T>() + std::declval<T2>())>
{
return left.atomic_op([right](be_t<T>& value) -> be_t<T>
{
return value += right;
});
}
template<typename T, typename T2, typename = if_integral_t<T>> inline auto operator -=(_atomic_base<be_t<T>>& left, T2 right) -> be_t<decltype(std::declval<T>() - std::declval<T2>())>
{
return left.atomic_op([right](be_t<T>& value) -> be_t<T>
{
return value -= right;
});
}
template<typename T> using atomic_t = _atomic_base<T>; // Atomic Type with native endianness (for emulator memory)
template<typename T> using atomic_be_t = _atomic_base<to_be_t<T>>; // Atomic BE Type (for PS3 virtual memory)
template<typename T> using atomic_le_t = _atomic_base<to_le_t<T>>; // Atomic LE Type (for PSV virtual memory)

View File

@ -77,7 +77,7 @@ namespace vm
void* const g_base_addr = (atexit(finalize), initialize());
void* g_priv_addr;
std::array<atomic_t<u8>, 0x100000000ull / 4096> g_pages = {}; // information about every page
std::array<atomic_t<u8>, 0x100000000ull / 4096> g_pages{}; // information about every page
const thread_ctrl_t* const INVALID_THREAD = reinterpret_cast<const thread_ctrl_t*>(~0ull);
@ -85,16 +85,11 @@ namespace vm
class reservation_mutex_t
{
atomic_t<const thread_ctrl_t*> m_owner;
atomic_t<const thread_ctrl_t*> m_owner{ INVALID_THREAD };
std::condition_variable m_cv;
std::mutex m_mutex;
public:
reservation_mutex_t()
{
m_owner.store(INVALID_THREAD);
}
bool do_notify = false;
never_inline void lock()
@ -105,7 +100,7 @@ namespace vm
while (!m_owner.compare_and_swap_test(INVALID_THREAD, owner))
{
if (m_owner.load() == owner)
if (m_owner == owner)
{
throw EXCEPTION("Deadlock");
}
@ -423,7 +418,7 @@ namespace vm
throw EXCEPTION("Invalid arguments (addr=0x%x, size=0x%x)", addr, size);
}
const u8 flags = g_pages[addr >> 12].load();
const u8 flags = g_pages[addr >> 12];
if (!(flags & page_writable) || !(flags & page_allocated) || (flags & page_no_reservations))
{
@ -587,7 +582,7 @@ namespace vm
for (u32 i = addr / 4096; i < addr / 4096 + size / 4096; i++)
{
if (g_pages[i].load())
if (g_pages[i])
{
throw EXCEPTION("Memory already mapped (addr=0x%x, size=0x%x, flags=0x%x, current_addr=0x%x)", addr, size, flags, i * 4096);
}
@ -630,7 +625,7 @@ namespace vm
for (u32 i = addr / 4096; i < addr / 4096 + size / 4096; i++)
{
if ((g_pages[i].load() & flags_test) != (flags_test | page_allocated))
if ((g_pages[i] & flags_test) != (flags_test | page_allocated))
{
return false;
}
@ -677,7 +672,7 @@ namespace vm
for (u32 i = addr / 4096; i < addr / 4096 + size / 4096; i++)
{
if (!(g_pages[i].load() & page_allocated))
if ((g_pages[i] & page_allocated) == 0)
{
throw EXCEPTION("Memory not mapped (addr=0x%x, size=0x%x, current_addr=0x%x)", addr, size, i * 4096);
}
@ -719,7 +714,7 @@ namespace vm
for (u32 i = addr / 4096; i <= (addr + size - 1) / 4096; i++)
{
if ((g_pages[i].load() & page_allocated) != page_allocated)
if ((g_pages[i] & page_allocated) == 0)
{
return false;
}
@ -788,7 +783,7 @@ namespace vm
// check if memory area is already mapped
for (u32 i = addr / 4096; i <= (addr + size - 1) / 4096; i++)
{
if (g_pages[i].load())
if (g_pages[i])
{
return false;
}
@ -862,7 +857,7 @@ namespace vm
return addr;
}
if (used.load() + size > this->size)
if (used + size > this->size)
{
return 0;
}
@ -941,7 +936,7 @@ namespace vm
for (u32 i = addr / 4096; i < addr / 4096 + size / 4096; i++)
{
if (g_pages[i].load())
if (g_pages[i])
{
throw EXCEPTION("Unexpected pages allocated (current_addr=0x%x)", i * 4096);
}

View File

@ -269,19 +269,11 @@ namespace vm
}
};
template<typename T> struct cast_ptr<be_t<T>>
template<typename T, bool Se> struct cast_ptr<se_t<T, Se>>
{
force_inline static u32 cast(const be_t<T>& addr, const char* file, int line, const char* func)
force_inline static u32 cast(const se_t<T, Se>& addr, const char* file, int line, const char* func)
{
return cast_ptr<T>::cast(addr.value(), file, line, func);
}
};
template<typename T> struct cast_ptr<le_t<T>>
{
force_inline static u32 cast(const le_t<T>& addr, const char* file, int line, const char* func)
{
return cast_ptr<T>::cast(addr.value(), file, line, func);
return cast_ptr<T>::cast(addr, file, line, func);
}
};

View File

@ -7,13 +7,6 @@
#include "Emu/System.h"
#include "GLGSRender.h"
GetGSFrameCb GetGSFrame = nullptr;
void SetGetGSFrameCallback(GetGSFrameCb value)
{
GetGSFrame = value;
}
#define CMD_DEBUG 0
#define DUMP_VERTEX_DATA 0
@ -789,7 +782,7 @@ GLGSRender::GLGSRender()
, m_vp_buf_num(-1)
, m_context(nullptr)
{
m_frame = GetGSFrame();
m_frame = Emu.GetCallbacks().get_gs_frame().release();
}
GLGSRender::~GLGSRender()

View File

@ -130,10 +130,6 @@ public:
};
typedef GSFrameBase*(*GetGSFrameCb)();
void SetGetGSFrameCallback(GetGSFrameCb value);
class GLGSRender final : public GSRender
{
private:

View File

@ -2531,8 +2531,8 @@ void RSXThread::Task()
inc = 1;
u32 put = m_ctrl->put.load();
u32 get = m_ctrl->get.load();
const be_t<u32> put = m_ctrl->put;
const be_t<u32> get = m_ctrl->get;
if (put == get || !Emu.IsRunning())
{

View File

@ -2,7 +2,7 @@
#include "Modules.h"
#include "SysCalls.h"
std::string SysCalls::GetFuncName(const u64 fid)
std::string get_ps3_function_name(u64 fid)
{
// check syscalls
switch (~fid)

View File

@ -9,7 +9,7 @@ bool LogBase::CheckLogging() const
return Ini.HLELogging.GetValue() || m_logging;
}
void LogBase::LogOutput(LogType type, const std::string& text) const
void LogBase::LogOutput(LogType type, std::string text) const
{
switch (type)
{

View File

@ -14,13 +14,18 @@ class LogBase
LogTodo,
};
void LogOutput(LogType type, const std::string& text) const;
void LogOutput(LogType type, std::string text) const;
template<typename... Args> never_inline void LogPrepare(LogType type, const char* fmt, Args... args) const
template<typename... Args> never_inline safe_buffers void LogPrepare(LogType type, const char* fmt, Args... args) const
{
LogOutput(type, fmt::format(fmt, args...));
}
never_inline safe_buffers void LogPrepare(LogType type, const char* fmt) const
{
LogOutput(type, fmt);
}
public:
void SetLogging(bool value)
{

View File

@ -2,116 +2,116 @@
#include "Modules.h"
#include "ModuleManager.h"
extern Module cellAdec;
extern Module cellAtrac;
extern Module cellAtracMulti;
extern Module cellAudio;
extern Module cellAvconfExt;
extern Module cellBGDL;
extern Module cellCamera;
extern Module cellCelp8Enc;
extern Module cellCelpEnc;
extern Module cellDaisy;
extern Module cellDmux;
extern Module cellFiber;
extern Module cellFont;
extern Module cellFontFT;
extern Module cellFs;
extern Module cellGame;
extern Module cellGameExec;
extern Module cellGcmSys;
extern Module cellGem;
extern Module cellGifDec;
extern Module cellHttp;
extern Module cellHttps;
extern Module cellHttpUtil;
extern Module cellImeJp;
extern Module cellJpgDec;
extern Module cellJpgEnc;
extern Module cellKey2char;
extern Module cellL10n;
extern Module cellMic;
extern Module cellMusic;
extern Module cellMusicDecode;
extern Module cellMusicExport;
extern Module cellNetCtl;
extern Module cellOskDialog;
extern Module cellOvis;
extern Module cellPamf;
extern Module cellPhotoDecode;
extern Module cellPhotoExport;
extern Module cellPhotoImportUtil;
extern Module cellPngDec;
extern Module cellPngEnc;
extern Module cellPrint;
extern Module cellRec;
extern Module cellRemotePlay;
extern Module cellResc;
extern Module cellRtc;
extern Module cellRudp;
extern Module cellSail;
extern Module cellSailRec;
extern Module cellSaveData;
extern Module cellMinisSaveData;
extern Module cellScreenshot;
extern Module cellSearch;
extern Module cellSheap;
extern Module cellSpudll;
extern Module cellSpurs;
extern Module cellSpursJq;
extern Module cellSsl;
extern Module cellSubdisplay;
extern Module cellSync;
extern Module cellSync2;
extern Module cellSysconf;
extern Module cellSysmodule;
extern Module cellSysutil;
extern Module cellSysutilAp;
extern Module cellSysutilAvc;
extern Module cellSysutilAvc2;
extern Module cellSysutilMisc;
extern Module cellUsbd;
extern Module cellUsbPspcm;
extern Module cellUserInfo;
extern Module cellVdec;
extern Module cellVideoExport;
extern Module cellVideoUpload;
extern Module cellVoice;
extern Module cellVpost;
extern Module libmixer;
extern Module libsnd3;
extern Module libsynth2;
extern Module sceNp;
extern Module sceNp2;
extern Module sceNpClans;
extern Module sceNpCommerce2;
extern Module sceNpSns;
extern Module sceNpTrophy;
extern Module sceNpTus;
extern Module sceNpUtil;
extern Module sys_io;
extern Module libnet;
extern Module sysPrxForUser;
extern Module sys_libc;
extern Module sys_lv2dbg;
extern Module<> cellAdec;
extern Module<> cellAtrac;
extern Module<> cellAtracMulti;
extern Module<> cellAudio;
extern Module<> cellAvconfExt;
extern Module<> cellBGDL;
extern Module<> cellCamera;
extern Module<> cellCelp8Enc;
extern Module<> cellCelpEnc;
extern Module<> cellDaisy;
extern Module<> cellDmux;
extern Module<> cellFiber;
extern Module<> cellFont;
extern Module<> cellFontFT;
extern Module<> cellFs;
extern Module<> cellGame;
extern Module<> cellGameExec;
extern Module<> cellGcmSys;
extern Module<> cellGem;
extern Module<> cellGifDec;
extern Module<> cellHttp;
extern Module<> cellHttps;
extern Module<> cellHttpUtil;
extern Module<> cellImeJp;
extern Module<> cellJpgDec;
extern Module<> cellJpgEnc;
extern Module<> cellKey2char;
extern Module<> cellL10n;
extern Module<> cellMic;
extern Module<> cellMusic;
extern Module<> cellMusicDecode;
extern Module<> cellMusicExport;
extern Module<> cellNetCtl;
extern Module<> cellOskDialog;
extern Module<> cellOvis;
extern Module<> cellPamf;
extern Module<> cellPhotoDecode;
extern Module<> cellPhotoExport;
extern Module<> cellPhotoImportUtil;
extern Module<> cellPngDec;
extern Module<> cellPngEnc;
extern Module<> cellPrint;
extern Module<> cellRec;
extern Module<> cellRemotePlay;
extern Module<> cellResc;
extern Module<> cellRtc;
extern Module<> cellRudp;
extern Module<> cellSail;
extern Module<> cellSailRec;
extern Module<> cellSaveData;
extern Module<> cellMinisSaveData;
extern Module<> cellScreenshot;
extern Module<> cellSearch;
extern Module<> cellSheap;
extern Module<> cellSpudll;
extern Module<> cellSpurs;
extern Module<> cellSpursJq;
extern Module<> cellSsl;
extern Module<> cellSubdisplay;
extern Module<> cellSync;
extern Module<struct Sync2Instance> cellSync2;
extern Module<> cellSysconf;
extern Module<> cellSysmodule;
extern Module<> cellSysutil;
extern Module<> cellSysutilAp;
extern Module<> cellSysutilAvc;
extern Module<> cellSysutilAvc2;
extern Module<> cellSysutilMisc;
extern Module<> cellUsbd;
extern Module<> cellUsbPspcm;
extern Module<> cellUserInfo;
extern Module<> cellVdec;
extern Module<> cellVideoExport;
extern Module<> cellVideoUpload;
extern Module<> cellVoice;
extern Module<> cellVpost;
extern Module<> libmixer;
extern Module<> libsnd3;
extern Module<> libsynth2;
extern Module<> sceNp;
extern Module<> sceNp2;
extern Module<> sceNpClans;
extern Module<> sceNpCommerce2;
extern Module<> sceNpSns;
extern Module<> sceNpTrophy;
extern Module<> sceNpTus;
extern Module<> sceNpUtil;
extern Module<> sys_io;
extern Module<> libnet;
extern Module<> sysPrxForUser;
extern Module<> sys_libc;
extern Module<> sys_lv2dbg;
struct ModuleInfo
{
const s32 id; // -1 if the module doesn't have corresponding CELL_SYSMODULE_* id
const char* const name;
Module* const module;
Module<>* const module;
explicit operator bool() const
{
return module != nullptr;
}
operator Module*() const
operator Module<>*() const
{
return module;
}
Module* operator ->() const
Module<>* operator ->() const
{
return module;
}
@ -243,7 +243,7 @@ void ModuleManager::Init()
clear_ppu_functions();
std::unordered_set<Module*> processed;
std::unordered_set<Module<>*> processed;
for (auto& module : g_module_list)
{
@ -272,7 +272,7 @@ void ModuleManager::Close()
return;
}
std::unordered_set<Module*> processed;
std::unordered_set<Module<>*> processed;
for (auto& module : g_module_list)
{
@ -285,7 +285,25 @@ void ModuleManager::Close()
m_init = false;
}
Module* ModuleManager::GetModuleByName(const char* name)
void ModuleManager::Alloc()
{
if (!m_init)
{
return;
}
std::unordered_set<Module<>*> processed;
for (auto& module : g_module_list)
{
if (module && module->on_alloc && processed.emplace(module).second)
{
module->on_alloc();
}
}
}
Module<>* ModuleManager::GetModuleByName(const char* name)
{
for (auto& module : g_module_list)
{
@ -298,7 +316,7 @@ Module* ModuleManager::GetModuleByName(const char* name)
return nullptr;
}
Module* ModuleManager::GetModuleById(u16 id)
Module<>* ModuleManager::GetModuleById(u16 id)
{
for (auto& module : g_module_list)
{

View File

@ -1,6 +1,6 @@
#pragma once
class Module;
template<typename T> class Module;
class ModuleManager
{
@ -12,8 +12,9 @@ public:
void Init();
void Close();
void Alloc();
static Module* GetModuleByName(const char* name);
static Module* GetModuleById(u16 id);
static Module<void>* GetModuleByName(const char* name);
static Module<void>* GetModuleById(u16 id);
static bool CheckModuleId(u16 id);
};

View File

@ -11,6 +11,7 @@
std::vector<ModuleFunc> g_ppu_func_list;
std::vector<StaticFunc> g_ppu_func_subs;
std::vector<ModuleVariable> g_ps3_var_list;
u32 add_ppu_func(ModuleFunc func)
{
@ -25,21 +26,52 @@ u32 add_ppu_func(ModuleFunc func)
if (f.id == func.id)
{
// if NIDs overlap or if the same function is added twice
throw EXCEPTION("NID already exists: 0x%08x (%s)", f.id, f.name);
throw EXCEPTION("FNID already exists: 0x%08x (%s)", f.id, f.name);
}
}
g_ppu_func_list.push_back(func);
g_ppu_func_list.emplace_back(std::move(func));
return (u32)g_ppu_func_list.size() - 1;
}
void add_variable(u32 nid, Module<>* module, const char* name, u32(*addr)())
{
if (g_ps3_var_list.empty())
{
g_ps3_var_list.reserve(0x4000); // as g_ppu_func_list
}
for (auto& v : g_ps3_var_list)
{
if (v.id == nid)
{
throw EXCEPTION("VNID already exists: 0x%08x (%s)", nid, name);
}
}
g_ps3_var_list.emplace_back(ModuleVariable{ nid, module, name, addr });
}
ModuleVariable* get_variable_by_nid(u32 nid)
{
for (auto& v : g_ps3_var_list)
{
if (v.id == nid)
{
return &v;
}
}
return nullptr;
}
u32 add_ppu_func_sub(StaticFunc func)
{
g_ppu_func_subs.emplace_back(func);
return func.index;
}
u32 add_ppu_func_sub(const std::initializer_list<SearchPatternEntry>& ops, const char* name, Module* module, ppu_func_caller func)
u32 add_ppu_func_sub(const std::initializer_list<SearchPatternEntry>& ops, const char* name, Module<>* module, ppu_func_caller func)
{
StaticFunc sf;
sf.index = add_ppu_func(ModuleFunc(get_function_id(name), 0, module, name, func));
@ -80,18 +112,18 @@ ModuleFunc* get_ppu_func_by_index(u32 index)
return &g_ppu_func_list[index];
}
void execute_ppu_func_by_index(PPUThread& CPU, u32 index)
void execute_ppu_func_by_index(PPUThread& ppu, u32 index)
{
if (auto func = get_ppu_func_by_index(index))
{
// save RTOC if necessary
if (index & EIF_SAVE_RTOC)
{
vm::write64(VM_CAST(CPU.GPR[1] + 0x28), CPU.GPR[2]);
vm::write64(VM_CAST(ppu.GPR[1] + 0x28), ppu.GPR[2]);
}
// save old syscall/NID value
const auto last_code = CPU.hle_code;
const auto last_code = ppu.hle_code;
// branch directly to the LLE function
if (index & EIF_USE_BRANCH)
@ -100,39 +132,39 @@ void execute_ppu_func_by_index(PPUThread& CPU, u32 index)
if (last_code)
{
throw EXCEPTION("This function cannot be called from the callback: %s (0x%llx)", SysCalls::GetFuncName(func->id), func->id);
throw EXCEPTION("This function cannot be called from the callback: %s (0x%llx)", get_ps3_function_name(func->id), func->id);
}
if (!func->lle_func)
{
throw EXCEPTION("LLE function not set: %s (0x%llx)", SysCalls::GetFuncName(func->id), func->id);
throw EXCEPTION("LLE function not set: %s (0x%llx)", get_ps3_function_name(func->id), func->id);
}
if (func->flags & MFF_FORCED_HLE)
{
throw EXCEPTION("Forced HLE enabled: %s (0x%llx)", SysCalls::GetFuncName(func->id), func->id);
throw EXCEPTION("Forced HLE enabled: %s (0x%llx)", get_ps3_function_name(func->id), func->id);
}
if (Ini.HLELogging.GetValue())
{
LOG_NOTICE(HLE, "Branch to LLE function: %s (0x%llx)", SysCalls::GetFuncName(func->id), func->id);
LOG_NOTICE(HLE, "Branch to LLE function: %s (0x%llx)", get_ps3_function_name(func->id), func->id);
}
if (index & EIF_PERFORM_BLR)
{
throw EXCEPTION("TODO: Branch with link: %s (0x%llx)", SysCalls::GetFuncName(func->id), func->id);
throw EXCEPTION("TODO: Branch with link: %s (0x%llx)", get_ps3_function_name(func->id), func->id);
// CPU.LR = CPU.PC + 4;
}
const auto data = vm::get_ptr<be_t<u32>>(func->lle_func.addr());
CPU.PC = data[0] - 4;
CPU.GPR[2] = data[1]; // set rtoc
ppu.PC = data[0] - 4;
ppu.GPR[2] = data[1]; // set rtoc
return;
}
// change current syscall/NID value
CPU.hle_code = func->id;
ppu.hle_code = func->id;
if (func->lle_func && !(func->flags & MFF_FORCED_HLE))
{
@ -144,49 +176,49 @@ void execute_ppu_func_by_index(PPUThread& CPU, u32 index)
if (Ini.HLELogging.GetValue())
{
LOG_NOTICE(HLE, "LLE function called: %s", SysCalls::GetFuncName(func->id));
LOG_NOTICE(HLE, "LLE function called: %s", get_ps3_function_name(func->id));
}
CPU.fast_call(pc, rtoc);
ppu.fast_call(pc, rtoc);
if (Ini.HLELogging.GetValue())
{
LOG_NOTICE(HLE, "LLE function finished: %s -> 0x%llx", SysCalls::GetFuncName(func->id), CPU.GPR[3]);
LOG_NOTICE(HLE, "LLE function finished: %s -> 0x%llx", get_ps3_function_name(func->id), ppu.GPR[3]);
}
}
else if (func->func)
{
if (Ini.HLELogging.GetValue())
{
LOG_NOTICE(HLE, "HLE function called: %s", SysCalls::GetFuncName(func->id));
LOG_NOTICE(HLE, "HLE function called: %s", get_ps3_function_name(func->id));
}
func->func(CPU);
func->func(ppu);
if (Ini.HLELogging.GetValue())
{
LOG_NOTICE(HLE, "HLE function finished: %s -> 0x%llx", SysCalls::GetFuncName(func->id), CPU.GPR[3]);
LOG_NOTICE(HLE, "HLE function finished: %s -> 0x%llx", get_ps3_function_name(func->id), ppu.GPR[3]);
}
}
else
{
LOG_ERROR(HLE, "Unimplemented function: %s -> CELL_OK", SysCalls::GetFuncName(func->id));
CPU.GPR[3] = 0;
LOG_ERROR(HLE, "Unimplemented function: %s -> CELL_OK", get_ps3_function_name(func->id));
ppu.GPR[3] = 0;
}
if (index & EIF_PERFORM_BLR)
{
// return if necessary
CPU.PC = VM_CAST(CPU.LR & ~3) - 4;
ppu.PC = VM_CAST(ppu.LR & ~3) - 4;
}
// execute module-specific error check
if ((s64)CPU.GPR[3] < 0 && func->module && func->module->on_error)
if ((s64)ppu.GPR[3] < 0 && func->module && func->module->on_error)
{
func->module->on_error(CPU.GPR[3], func);
func->module->on_error(ppu.GPR[3], func);
}
CPU.hle_code = last_code;
ppu.hle_code = last_code;
}
else
{
@ -198,6 +230,7 @@ void clear_ppu_functions()
{
g_ppu_func_list.clear();
g_ppu_func_subs.clear();
g_ps3_var_list.clear();
}
u32 get_function_id(const char* name)
@ -239,10 +272,10 @@ void hook_ppu_func(vm::ptr<u32> base, u32 pos, u32 size)
continue;
}
const u32 data = sub.ops[x].data.data();
const u32 mask = sub.ops[x].mask.data();
const be_t<u32> data = sub.ops[x].data;
const be_t<u32> mask = sub.ops[x].mask;
const bool match = (base[k].data() & mask) == data;
const bool match = (base[k] & mask) == data;
switch (sub.ops[x].type)
{
@ -268,8 +301,8 @@ void hook_ppu_func(vm::ptr<u32> base, u32 pos, u32 size)
}
case SPET_LABEL:
{
const auto addr = (base + k--).addr();
const auto lnum = data;
const u32 addr = (base + k--).addr();
const u32 lnum = data;
const auto label = sub.labels.find(lnum);
if (label == sub.labels.end()) // register the label
@ -497,18 +530,18 @@ bool patch_ppu_import(u32 addr, u32 index)
return false;
}
Module::Module(const char* name, void(*init)())
Module<>::Module(const char* name, void(*init)())
: m_is_loaded(false)
, m_name(name)
, m_init(init)
{
}
Module::~Module()
Module<>::~Module()
{
}
void Module::Init()
void Module<>::Init()
{
on_load = nullptr;
on_unload = nullptr;
@ -518,7 +551,7 @@ void Module::Init()
m_init();
}
void Module::Load()
void Module<>::Load()
{
if (IsLoaded())
{
@ -533,7 +566,7 @@ void Module::Load()
SetLoaded(true);
}
void Module::Unload()
void Module<>::Unload()
{
if (!IsLoaded())
{
@ -548,22 +581,22 @@ void Module::Unload()
SetLoaded(false);
}
void Module::SetLoaded(bool loaded)
void Module<>::SetLoaded(bool loaded)
{
m_is_loaded = loaded;
}
bool Module::IsLoaded() const
bool Module<>::IsLoaded() const
{
return m_is_loaded;
}
const std::string& Module::GetName() const
const std::string& Module<>::GetName() const
{
return m_name;
}
void Module::SetName(const std::string& name)
void Module<>::SetName(const std::string& name)
{
m_name = name;
}

View File

@ -7,30 +7,13 @@
namespace vm { using namespace ps3; }
class Module;
// 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
};
template<typename T = void> class Module;
struct ModuleFunc
{
u32 id;
u32 flags;
Module* module;
Module<>* module;
const char* name;
ppu_func_caller func;
vm::ptr<void()> lle_func;
@ -39,7 +22,7 @@ struct ModuleFunc
{
}
ModuleFunc(u32 id, u32 flags, Module* module, const char* name, ppu_func_caller func, vm::ptr<void()> lle_func = vm::null)
ModuleFunc(u32 id, u32 flags, Module<>* module, const char* name, ppu_func_caller func, vm::ptr<void()> lle_func = vm::null)
: id(id)
, flags(flags)
, module(module)
@ -50,6 +33,14 @@ struct ModuleFunc
}
};
struct ModuleVariable
{
u32 id;
Module<>* module;
const char* name;
u32(*retrieve_addr)();
};
enum : u32
{
SPET_MASKED_OPCODE,
@ -76,15 +67,19 @@ struct StaticFunc
std::unordered_map<u32, u32> labels;
};
class Module : public LogBase
template<> class Module<void> : public LogBase
{
friend class ModuleManager;
std::string m_name;
bool m_is_loaded;
void(*m_init)();
Module() = delete;
protected:
std::function<void()> on_alloc;
public:
Module() = delete;
Module(const char* name, void(*init)());
Module(Module& other) = delete;
@ -111,47 +106,82 @@ public:
void SetName(const std::string& name);
};
// Module<> with an instance of specified type in PS3 memory
template<typename T> class Module : public Module<void>
{
u32 m_addr;
public:
Module(const char* name, void(*init)())
: Module<void>(name, init)
{
on_alloc = [this]
{
static_assert(std::is_trivially_destructible<T>::value, "Module<> instance must be trivially destructible");
//static_assert(std::is_trivially_copy_assignable<T>::value, "Module<> instance must be trivially copy-assignable");
// Allocate module instance and call the default constructor
new(vm::get_ptr<T>(m_addr = vm::alloc(sizeof(T), vm::main)))T{};
};
}
T* operator ->() const
{
return vm::get_ptr<T>(m_addr);
}
};
u32 add_ppu_func(ModuleFunc func);
void add_variable(u32 nid, Module<>* module, const char* name, u32(*addr)());
ModuleFunc* get_ppu_func_by_nid(u32 nid, u32* out_index = nullptr);
ModuleFunc* get_ppu_func_by_index(u32 index);
void execute_ppu_func_by_index(PPUThread& CPU, u32 id);
ModuleVariable* get_variable_by_nid(u32 nid);
void execute_ppu_func_by_index(PPUThread& ppu, u32 id);
extern std::string get_ps3_function_name(u64 fid);
void clear_ppu_functions();
u32 get_function_id(const char* name);
u32 add_ppu_func_sub(StaticFunc sf);
u32 add_ppu_func_sub(const std::initializer_list<SearchPatternEntry>& ops, const char* name, Module* module, ppu_func_caller func);
u32 add_ppu_func_sub(const std::initializer_list<SearchPatternEntry>& ops, const char* name, Module<>* module, ppu_func_caller func);
void hook_ppu_funcs(vm::ptr<u32> base, u32 size);
bool patch_ppu_import(u32 addr, u32 index);
// call specified function directly if LLE is not available, call LLE equivalent in callback style otherwise
template<typename T, typename... Args> inline auto hle_call_func(PPUThread& CPU, T func, u32 index, Args&&... args) -> decltype(func(std::forward<Args>(args)...))
// Variable associated with registered HLE function
template<typename T, T Func> struct ppu_func_by_func { static u32 index; };
template<typename T, T Func> u32 ppu_func_by_func<T, Func>::index = 0xffffffffu;
template<typename T, T Func, typename... Args, typename RT = std::result_of_t<T(Args...)>> inline RT call_ppu_func(PPUThread& ppu, Args&&... args)
{
const auto mfunc = get_ppu_func_by_index(index);
const auto mfunc = get_ppu_func_by_index(ppu_func_by_func<T, Func>::index);
if (mfunc && mfunc->lle_func && (mfunc->flags & MFF_FORCED_HLE) == 0 && (mfunc->flags & MFF_NO_RETURN) == 0)
{
const u32 pc = vm::read32(mfunc->lle_func.addr());
const u32 rtoc = vm::read32(mfunc->lle_func.addr() + 4);
return cb_call<decltype(func(std::forward<Args>(args)...)), Args...>(CPU, pc, rtoc, std::forward<Args>(args)...);
return cb_call<RT, Args...>(ppu, pc, rtoc, std::forward<Args>(args)...);
}
else
{
return func(std::forward<Args>(args)...);
return Func(std::forward<Args>(args)...);
}
}
#define CALL_FUNC(cpu, func, ...) hle_call_func(cpu, func, g_ppu_func_index__##func, __VA_ARGS__)
// Call specified function directly if LLE is not available, call LLE equivalent in callback style otherwise
#define CALL_FUNC(ppu, func, ...) call_ppu_func<decltype(&func), &func>(ppu, __VA_ARGS__)
#define REG_FUNC(module, name) add_ppu_func(ModuleFunc(get_function_id(#name), 0, &module, #name, bind_func(name)))
#define REG_FUNC_FH(module, name) add_ppu_func(ModuleFunc(get_function_id(#name), MFF_FORCED_HLE, &module, #name, bind_func(name)))
#define REG_FUNC_NR(module, name) add_ppu_func(ModuleFunc(get_function_id(#name), MFF_NO_RETURN, &module, #name, bind_func(name)))
#define REG_FNID(module, nid, func, ...) (ppu_func_by_func<decltype(&func), &func>::index = add_ppu_func(ModuleFunc(nid, { __VA_ARGS__ }, &module, #func, BIND_FUNC(func))))
#define REG_UNNAMED(module, nid) add_ppu_func(ModuleFunc(0x##nid, 0, &module, "_nid_"#nid, bind_func(_nid_##nid)))
#define REG_FUNC(module, func, ...) REG_FNID(module, get_function_id(#func), func, __VA_ARGS__)
#define REG_SUB(module, ns, name, ...) add_ppu_func_sub({ __VA_ARGS__ }, #name, &module, bind_func(ns::name))
#define REG_VNID(module, nid, var) add_variable(nid, &module, #var, []{ return vm::get_addr(&module->var); })
#define REG_VARIABLE(module, var) REG_VNID(module, get_function_id(#var), var)
#define REG_SUB(module, ns, name, ...) add_ppu_func_sub({ __VA_ARGS__ }, #name, &module, BIND_FUNC(ns::name))
#define SP_OP(type, op, sup) []() { s32 XXX = 0; SearchPatternEntry res = { (type), (op), 0, (sup) }; XXX = -1; res.mask = (op) ^ ~res.data; return res; }()
#define SP_I(op) SP_OP(SPET_MASKED_OPCODE, op, 0)

View File

@ -16,7 +16,7 @@ extern "C"
#include "cellPamf.h"
#include "cellAdec.h"
extern Module cellAdec;
extern Module<> cellAdec;
AudioDecoder::AudioDecoder(s32 type, u32 addr, u32 size, vm::ptr<CellAdecCbMsg> func, u32 arg)
: type(type)
@ -863,7 +863,7 @@ s32 cellAdecGetPcmItem(u32 handle, vm::pptr<CellAdecPcmItem> pcmItem)
return CELL_OK;
}
Module cellAdec("cellAdec", []()
Module<> cellAdec("cellAdec", []()
{
REG_FUNC(cellAdec, cellAdecQueryAttr);
REG_FUNC(cellAdec, cellAdecOpen);

View File

@ -194,7 +194,7 @@ s32 cellAtracGetInternalErrorInfo(vm::ptr<CellAtracHandle> pHandle, vm::ptr<s32>
return CELL_OK;
}
Module cellAtrac("cellAtrac", []()
Module<> cellAtrac("cellAtrac", []()
{
REG_FUNC(cellAtrac, cellAtracSetDataAndGetMemSize);

View File

@ -58,4 +58,4 @@ struct CellAtracExtRes
u8 priority[8];
};
extern Module cellAtrac;
extern Module<> cellAtrac;

View File

@ -202,7 +202,7 @@ s32 cellAtracMultiGetInternalErrorInfo(vm::ptr<CellAtracMultiHandle> pHandle, vm
return CELL_OK;
}
Module cellAtracMulti("cellAtrac", []()
Module<> cellAtracMulti("cellAtrac", []()
{
REG_FUNC(cellAtracMulti, cellAtracMultiSetDataAndGetMemSize);

View File

@ -59,4 +59,4 @@ struct CellAtracMultiExtRes
u8 priority[8];
};
extern Module cellAtracMulti;
extern Module<> cellAtracMulti;

View File

@ -14,7 +14,7 @@
#include "cellAudio.h"
extern Module cellAudio;
extern Module<> cellAudio;
extern u64 get_system_time();
@ -32,7 +32,7 @@ s32 cellAudioInit()
// clear ports
for (auto& port : g_audio.ports)
{
port.state.store(AUDIO_PORT_STATE_CLOSED);
port.state = AUDIO_PORT_STATE_CLOSED;
}
// reset variables
@ -90,7 +90,7 @@ s32 cellAudioInit()
bool opened = false;
float* buffer;
while (out_queue.pop(buffer, [](){ return g_audio.state.load() != AUDIO_STATE_INITIALIZED; }))
while (out_queue.pop(buffer, [](){ return g_audio.state != AUDIO_STATE_INITIALIZED; }))
{
if (use_u16)
{
@ -137,7 +137,7 @@ s32 cellAudioInit()
Emu.GetAudioManager().GetAudioOut().Quit();
});
while (g_audio.state.load() == AUDIO_STATE_INITIALIZED && !Emu.IsStopped())
while (g_audio.state == AUDIO_STATE_INITIALIZED && !Emu.IsStopped())
{
if (Emu.IsPaused())
{
@ -176,7 +176,7 @@ s32 cellAudioInit()
// mixing:
for (auto& port : g_audio.ports)
{
if (port.state.load() != AUDIO_PORT_STATE_STARTED) continue;
if (port.state != AUDIO_PORT_STATE_STARTED) continue;
const u32 block_size = port.channel * AUDIO_SAMPLES;
const u32 position = port.tag % port.block; // old value
@ -340,7 +340,7 @@ s32 cellAudioInit()
memset(out_buffer[out_pos].get(), 0, out_buffer_size * sizeof(float));
}
if (!out_queue.push(out_buffer[out_pos].get(), [](){ return g_audio.state.load() != AUDIO_STATE_INITIALIZED; }))
if (!out_queue.push(out_buffer[out_pos].get(), [](){ return g_audio.state != AUDIO_STATE_INITIALIZED; }))
{
break;
}
@ -356,7 +356,7 @@ s32 cellAudioInit()
{
AudioPortConfig& port = g_audio.ports[i];
if (port.state.load() != AUDIO_PORT_STATE_STARTED) continue;
if (port.state != AUDIO_PORT_STATE_STARTED) continue;
u32 position = port.tag % port.block; // old value
port.counter = g_audio.counter;
@ -428,7 +428,7 @@ s32 cellAudioPortOpen(vm::ptr<CellAudioPortParam> audioParam, vm::ptr<u32> portN
{
cellAudio.Warning("cellAudioPortOpen(audioParam=*0x%x, portNum=*0x%x)", audioParam, portNum);
if (g_audio.state.load() != AUDIO_STATE_INITIALIZED)
if (g_audio.state != AUDIO_STATE_INITIALIZED)
{
return CELL_AUDIO_ERROR_NOT_INIT;
}
@ -520,7 +520,7 @@ s32 cellAudioPortOpen(vm::ptr<CellAudioPortParam> audioParam, vm::ptr<u32> portN
port.level = 1.0f;
}
port.level_set.data = { port.level, 0.0f };
port.level_set.store({ port.level, 0.0f });
*portNum = port_index;
cellAudio.Warning("*** audio port opened(nChannel=%d, nBlock=%d, attr=0x%llx, level=%f): port = %d", channel, block, attr, port.level, port_index);
@ -532,7 +532,7 @@ s32 cellAudioGetPortConfig(u32 portNum, vm::ptr<CellAudioPortConfig> portConfig)
{
cellAudio.Warning("cellAudioGetPortConfig(portNum=%d, portConfig=*0x%x)", portNum, portConfig);
if (g_audio.state.load() != AUDIO_STATE_INITIALIZED)
if (g_audio.state != AUDIO_STATE_INITIALIZED)
{
return CELL_AUDIO_ERROR_NOT_INIT;
}
@ -565,7 +565,7 @@ s32 cellAudioPortStart(u32 portNum)
{
cellAudio.Warning("cellAudioPortStart(portNum=%d)", portNum);
if (g_audio.state.load() != AUDIO_STATE_INITIALIZED)
if (g_audio.state != AUDIO_STATE_INITIALIZED)
{
return CELL_AUDIO_ERROR_NOT_INIT;
}
@ -588,7 +588,7 @@ s32 cellAudioPortClose(u32 portNum)
{
cellAudio.Warning("cellAudioPortClose(portNum=%d)", portNum);
if (g_audio.state.load() != AUDIO_STATE_INITIALIZED)
if (g_audio.state != AUDIO_STATE_INITIALIZED)
{
return CELL_AUDIO_ERROR_NOT_INIT;
}
@ -611,7 +611,7 @@ s32 cellAudioPortStop(u32 portNum)
{
cellAudio.Warning("cellAudioPortStop(portNum=%d)", portNum);
if (g_audio.state.load() != AUDIO_STATE_INITIALIZED)
if (g_audio.state != AUDIO_STATE_INITIALIZED)
{
return CELL_AUDIO_ERROR_NOT_INIT;
}
@ -634,7 +634,7 @@ s32 cellAudioGetPortTimestamp(u32 portNum, u64 tag, vm::ptr<u64> stamp)
{
cellAudio.Log("cellAudioGetPortTimestamp(portNum=%d, tag=0x%llx, stamp=*0x%x)", portNum, tag, stamp);
if (g_audio.state.load() != AUDIO_STATE_INITIALIZED)
if (g_audio.state != AUDIO_STATE_INITIALIZED)
{
return CELL_AUDIO_ERROR_NOT_INIT;
}
@ -646,7 +646,7 @@ s32 cellAudioGetPortTimestamp(u32 portNum, u64 tag, vm::ptr<u64> stamp)
AudioPortConfig& port = g_audio.ports[portNum];
if (port.state.load() == AUDIO_PORT_STATE_CLOSED)
if (port.state == AUDIO_PORT_STATE_CLOSED)
{
return CELL_AUDIO_ERROR_PORT_NOT_OPEN;
}
@ -664,7 +664,7 @@ s32 cellAudioGetPortBlockTag(u32 portNum, u64 blockNo, vm::ptr<u64> tag)
{
cellAudio.Log("cellAudioGetPortBlockTag(portNum=%d, blockNo=0x%llx, tag=*0x%x)", portNum, blockNo, tag);
if (g_audio.state.load() != AUDIO_STATE_INITIALIZED)
if (g_audio.state != AUDIO_STATE_INITIALIZED)
{
return CELL_AUDIO_ERROR_NOT_INIT;
}
@ -676,7 +676,7 @@ s32 cellAudioGetPortBlockTag(u32 portNum, u64 blockNo, vm::ptr<u64> tag)
AudioPortConfig& port = g_audio.ports[portNum];
if (port.state.load() == AUDIO_PORT_STATE_CLOSED)
if (port.state == AUDIO_PORT_STATE_CLOSED)
{
return CELL_AUDIO_ERROR_PORT_NOT_OPEN;
}
@ -707,7 +707,7 @@ s32 cellAudioSetPortLevel(u32 portNum, float level)
{
cellAudio.Log("cellAudioSetPortLevel(portNum=%d, level=%f)", portNum, level);
if (g_audio.state.load() != AUDIO_STATE_INITIALIZED)
if (g_audio.state != AUDIO_STATE_INITIALIZED)
{
return CELL_AUDIO_ERROR_NOT_INIT;
}
@ -719,7 +719,7 @@ s32 cellAudioSetPortLevel(u32 portNum, float level)
AudioPortConfig& port = g_audio.ports[portNum];
if (port.state.load() == AUDIO_PORT_STATE_CLOSED)
if (port.state == AUDIO_PORT_STATE_CLOSED)
{
return CELL_AUDIO_ERROR_PORT_NOT_OPEN;
}
@ -775,7 +775,7 @@ s32 cellAudioSetNotifyEventQueue(u64 key)
{
cellAudio.Warning("cellAudioSetNotifyEventQueue(key=0x%llx)", key);
if (g_audio.state.load() != AUDIO_STATE_INITIALIZED)
if (g_audio.state != AUDIO_STATE_INITIALIZED)
{
return CELL_AUDIO_ERROR_NOT_INIT;
}
@ -808,7 +808,7 @@ s32 cellAudioRemoveNotifyEventQueue(u64 key)
{
cellAudio.Warning("cellAudioRemoveNotifyEventQueue(key=0x%llx)", key);
if (g_audio.state.load() != AUDIO_STATE_INITIALIZED)
if (g_audio.state != AUDIO_STATE_INITIALIZED)
{
return CELL_AUDIO_ERROR_NOT_INIT;
}
@ -841,7 +841,7 @@ s32 cellAudioAddData(u32 portNum, vm::ptr<float> src, u32 samples, float volume)
{
cellAudio.Log("cellAudioAddData(portNum=%d, src=*0x%x, samples=%d, volume=%f)", portNum, src, samples, volume);
if (g_audio.state.load() != AUDIO_STATE_INITIALIZED)
if (g_audio.state != AUDIO_STATE_INITIALIZED)
{
return CELL_AUDIO_ERROR_NOT_INIT;
}
@ -874,7 +874,7 @@ s32 cellAudioAdd2chData(u32 portNum, vm::ptr<float> src, u32 samples, float volu
{
cellAudio.Log("cellAudioAdd2chData(portNum=%d, src=*0x%x, samples=%d, volume=%f)", portNum, src, samples, volume);
if (g_audio.state.load() != AUDIO_STATE_INITIALIZED)
if (g_audio.state != AUDIO_STATE_INITIALIZED)
{
return CELL_AUDIO_ERROR_NOT_INIT;
}
@ -937,7 +937,7 @@ s32 cellAudioAdd6chData(u32 portNum, vm::ptr<float> src, float volume)
{
cellAudio.Log("cellAudioAdd6chData(portNum=%d, src=*0x%x, volume=%f)", portNum, src, volume);
if (g_audio.state.load() != AUDIO_STATE_INITIALIZED)
if (g_audio.state != AUDIO_STATE_INITIALIZED)
{
return CELL_AUDIO_ERROR_NOT_INIT;
}
@ -1001,9 +1001,9 @@ s32 cellAudioUnsetPersonalDevice(s32 iPersonalStream)
return CELL_OK;
}
Module cellAudio("cellAudio", []()
Module<> cellAudio("cellAudio", []()
{
g_audio.state.store(AUDIO_STATE_NOT_INITIALIZED);
g_audio.state = AUDIO_STATE_NOT_INITIALIZED;
g_audio.buffer = 0;
g_audio.indexes = 0;

View File

@ -4,7 +4,7 @@
#include "cellAudioOut.h"
extern Module cellSysutil;
extern Module<> cellSysutil;
s32 cellAudioOutGetSoundAvailability(u32 audioOut, u32 type, u32 fs, u32 option)
{

View File

@ -7,7 +7,7 @@
#include "cellAudioOut.h"
#include "cellVideoOut.h"
extern Module cellAvconfExt;
extern Module<> cellAvconfExt;
f32 g_gamma;
@ -137,7 +137,7 @@ s32 cellVideoOutGetScreenSize(u32 videoOut, vm::ptr<float> screenSize)
}
Module cellAvconfExt("cellAvconfExt", []()
Module<> cellAvconfExt("cellAvconfExt", []()
{
g_gamma = 1.0f;

View File

@ -3,7 +3,7 @@
#include "Emu/System.h"
#include "Emu/SysCalls/Modules.h"
extern Module cellBGDL;
extern Module<> cellBGDL;
// Return Codes
enum
@ -40,7 +40,7 @@ s32 cellBGDLGetMode()
return CELL_OK;
}
Module cellBGDL("cellBGDL", []()
Module<> cellBGDL("cellBGDL", []()
{
REG_FUNC(cellBGDL, cellBGDLGetInfo);
REG_FUNC(cellBGDL, cellBGDLGetInfo2);

View File

@ -7,7 +7,7 @@
#include "cellCamera.h"
extern Module cellCamera;
extern Module<> cellCamera;
static const char* get_camera_attr_name(s32 value)
{
@ -371,7 +371,7 @@ s32 cellCameraRemoveNotifyEventQueue2(u64 key)
return CELL_OK;
}
Module cellCamera("cellCamera", []()
Module<> cellCamera("cellCamera", []()
{
REG_FUNC(cellCamera, cellCameraInit);
REG_FUNC(cellCamera, cellCameraEnd);

View File

@ -3,7 +3,7 @@
#include "Emu/System.h"
#include "Emu/SysCalls/Modules.h"
extern Module cellCelp8Enc;
extern Module<> cellCelp8Enc;
// Return Codes
enum
@ -70,7 +70,7 @@ s32 cellCelp8EncGetAu()
return CELL_OK;
}
Module cellCelp8Enc("cellCelp8Enc", []()
Module<> cellCelp8Enc("cellCelp8Enc", []()
{
REG_FUNC(cellCelp8Enc, cellCelp8EncQueryAttr);
REG_FUNC(cellCelp8Enc, cellCelp8EncOpen);

View File

@ -3,7 +3,7 @@
#include "Emu/System.h"
#include "Emu/SysCalls/Modules.h"
extern Module cellCelpEnc;
extern Module<> cellCelpEnc;
// Return Codes
enum
@ -70,7 +70,7 @@ s32 cellCelpEncGetAu()
return CELL_OK;
}
Module cellCelpEnc("cellCelpEnc", []()
Module<> cellCelpEnc("cellCelpEnc", []()
{
REG_FUNC(cellCelpEnc, cellCelpEncQueryAttr);
REG_FUNC(cellCelpEnc, cellCelpEncOpen);

View File

@ -2,7 +2,7 @@
#include "Emu/Memory/Memory.h"
#include "Emu/SysCalls/Modules.h"
extern Module cellDaisy;
extern Module<> cellDaisy;
s32 _ZN4cell5Daisy17LFQueue2PushCloseEPNS0_8LFQueue2EPFiPvjE()
{
@ -265,7 +265,7 @@ s32 _QN4cell5Daisy22ScatterGatherInterlock7releaseEv()
}
Module cellDaisy("cellDaisy", []()
Module<> cellDaisy("cellDaisy", []()
{
REG_FUNC(cellDaisy, _ZN4cell5Daisy17LFQueue2PushCloseEPNS0_8LFQueue2EPFiPvjE);
REG_FUNC(cellDaisy, _ZN4cell5Daisy21LFQueue2GetPopPointerEPNS0_8LFQueue2EPij);

View File

@ -7,7 +7,7 @@
#include "cellPamf.h"
#include "cellDmux.h"
extern Module cellDmux;
extern Module<> cellDmux;
PesHeader::PesHeader(DemuxerStream& stream)
: pts(CODEC_TS_INVALID)
@ -1178,7 +1178,7 @@ s32 cellDmuxFlushEs(u32 esHandle)
return CELL_OK;
}
Module cellDmux("cellDmux", []()
Module<> cellDmux("cellDmux", []()
{
REG_FUNC(cellDmux, cellDmuxQueryAttr);
REG_FUNC(cellDmux, cellDmuxQueryAttr2);

View File

@ -5,7 +5,7 @@
#include "cellFiber.h"
extern Module cellFiber;
extern Module<> cellFiber;
s32 _cellFiberPpuInitialize()
{
@ -291,59 +291,59 @@ s32 cellFiberPpuUtilWorkerControlInitializeWithAttribute()
return CELL_OK;
}
Module cellFiber("cellFiber", []()
Module<> cellFiber("cellFiber", []()
{
REG_FUNC_NR(cellFiber, _cellFiberPpuInitialize);
REG_FUNC(cellFiber, _cellFiberPpuInitialize, MFF_NO_RETURN);
REG_FUNC_NR(cellFiber, _cellFiberPpuSchedulerAttributeInitialize);
REG_FUNC_NR(cellFiber, cellFiberPpuInitializeScheduler);
REG_FUNC_NR(cellFiber, cellFiberPpuFinalizeScheduler);
REG_FUNC_NR(cellFiber, cellFiberPpuRunFibers);
REG_FUNC_NR(cellFiber, cellFiberPpuCheckFlags);
REG_FUNC_NR(cellFiber, cellFiberPpuHasRunnableFiber);
REG_FUNC(cellFiber, _cellFiberPpuSchedulerAttributeInitialize, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuInitializeScheduler, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuFinalizeScheduler, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuRunFibers, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuCheckFlags, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuHasRunnableFiber, MFF_NO_RETURN);
REG_FUNC_NR(cellFiber, _cellFiberPpuAttributeInitialize);
REG_FUNC_NR(cellFiber, cellFiberPpuCreateFiber);
REG_FUNC_NR(cellFiber, cellFiberPpuExit);
REG_FUNC_NR(cellFiber, cellFiberPpuYield);
REG_FUNC_NR(cellFiber, cellFiberPpuJoinFiber);
REG_FUNC(cellFiber, _cellFiberPpuAttributeInitialize, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuCreateFiber, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuExit, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuYield, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuJoinFiber, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuSelf);
REG_FUNC_NR(cellFiber, cellFiberPpuSendSignal);
REG_FUNC_NR(cellFiber, cellFiberPpuWaitSignal);
REG_FUNC_NR(cellFiber, cellFiberPpuWaitFlag);
REG_FUNC_NR(cellFiber, cellFiberPpuGetScheduler);
REG_FUNC_NR(cellFiber, cellFiberPpuSetPriority);
REG_FUNC_NR(cellFiber, cellFiberPpuCheckStackLimit);
REG_FUNC(cellFiber, cellFiberPpuSendSignal, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuWaitSignal, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuWaitFlag, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuGetScheduler, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuSetPriority, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuCheckStackLimit, MFF_NO_RETURN);
REG_FUNC_NR(cellFiber, _cellFiberPpuContextAttributeInitialize);
REG_FUNC_NR(cellFiber, cellFiberPpuContextInitialize);
REG_FUNC_NR(cellFiber, cellFiberPpuContextFinalize);
REG_FUNC_NR(cellFiber, cellFiberPpuContextRun);
REG_FUNC_NR(cellFiber, cellFiberPpuContextSwitch);
REG_FUNC_NR(cellFiber, cellFiberPpuContextSelf);
REG_FUNC_NR(cellFiber, cellFiberPpuContextReturnToThread);
REG_FUNC_NR(cellFiber, cellFiberPpuContextCheckStackLimit);
REG_FUNC(cellFiber, _cellFiberPpuContextAttributeInitialize, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuContextInitialize, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuContextFinalize, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuContextRun, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuContextSwitch, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuContextSelf, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuContextReturnToThread, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuContextCheckStackLimit, MFF_NO_RETURN);
REG_FUNC_NR(cellFiber, cellFiberPpuContextRunScheduler);
REG_FUNC_NR(cellFiber, cellFiberPpuContextEnterScheduler);
REG_FUNC(cellFiber, cellFiberPpuContextRunScheduler, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuContextEnterScheduler, MFF_NO_RETURN);
REG_FUNC_NR(cellFiber, cellFiberPpuSchedulerTraceInitialize);
REG_FUNC_NR(cellFiber, cellFiberPpuSchedulerTraceFinalize);
REG_FUNC_NR(cellFiber, cellFiberPpuSchedulerTraceStart);
REG_FUNC_NR(cellFiber, cellFiberPpuSchedulerTraceStop);
REG_FUNC(cellFiber, cellFiberPpuSchedulerTraceInitialize, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuSchedulerTraceFinalize, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuSchedulerTraceStart, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuSchedulerTraceStop, MFF_NO_RETURN);
REG_FUNC_NR(cellFiber, _cellFiberPpuUtilWorkerControlAttributeInitialize);
REG_FUNC_NR(cellFiber, cellFiberPpuUtilWorkerControlRunFibers);
REG_FUNC_NR(cellFiber, cellFiberPpuUtilWorkerControlInitialize);
REG_FUNC_NR(cellFiber, cellFiberPpuUtilWorkerControlSetPollingMode);
REG_FUNC_NR(cellFiber, cellFiberPpuUtilWorkerControlJoinFiber);
REG_FUNC_NR(cellFiber, cellFiberPpuUtilWorkerControlDisconnectEventQueue);
REG_FUNC_NR(cellFiber, cellFiberPpuUtilWorkerControlSendSignal);
REG_FUNC_NR(cellFiber, cellFiberPpuUtilWorkerControlConnectEventQueueToSpurs);
REG_FUNC_NR(cellFiber, cellFiberPpuUtilWorkerControlFinalize);
REG_FUNC_NR(cellFiber, cellFiberPpuUtilWorkerControlWakeup);
REG_FUNC_NR(cellFiber, cellFiberPpuUtilWorkerControlCreateFiber);
REG_FUNC_NR(cellFiber, cellFiberPpuUtilWorkerControlShutdown);
REG_FUNC_NR(cellFiber, cellFiberPpuUtilWorkerControlCheckFlags);
REG_FUNC_NR(cellFiber, cellFiberPpuUtilWorkerControlInitializeWithAttribute);
REG_FUNC(cellFiber, _cellFiberPpuUtilWorkerControlAttributeInitialize, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlRunFibers, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlInitialize, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlSetPollingMode, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlJoinFiber, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlDisconnectEventQueue, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlSendSignal, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlConnectEventQueueToSpurs, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlFinalize, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlWakeup, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlCreateFiber, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlShutdown, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlCheckFlags, MFF_NO_RETURN);
REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlInitializeWithAttribute, MFF_NO_RETURN);
});

View File

@ -6,7 +6,7 @@
#include "Emu/FS/vfsFile.h"
#include "cellFont.h"
extern Module cellFont;
extern Module<> cellFont;
// Functions
s32 cellFontInitializeWithRevision(u64 revisionFlags, vm::ptr<CellFontConfig> config)
@ -741,7 +741,7 @@ s32 cellFontGraphicsGetLineRGBA()
}
Module cellFont("cellFont", []()
Module<> cellFont("cellFont", []()
{
REG_FUNC(cellFont, cellFontSetFontsetOpenMode);
REG_FUNC(cellFont, cellFontSetFontOpenMode);

View File

@ -4,7 +4,7 @@
#include "cellFontFT.h"
extern Module cellFontFT;
extern Module<> cellFontFT;
s32 cellFontInitLibraryFreeTypeWithRevision(u64 revisionFlags, vm::ptr<CellFontLibraryConfigFT> config, vm::pptr<CellFontLibrary> lib)
{
@ -27,7 +27,7 @@ s32 cellFontFTGetInitializedRevisionFlags()
return CELL_OK;
}
Module cellFontFT("cellFontFT", []()
Module<> cellFontFT("cellFontFT", []()
{
REG_FUNC(cellFontFT, cellFontInitLibraryFreeTypeWithRevision);
REG_FUNC(cellFontFT, cellFontFTGetRevisionFlags);

View File

@ -12,7 +12,7 @@
#include "Emu/SysCalls/lv2/sys_fs.h"
#include "cellFs.h"
extern Module cellFs;
extern Module<> cellFs;
s32 cellFsOpen(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, vm::cptr<void> arg, u64 size)
{
@ -397,7 +397,7 @@ s32 cellFsStReadGetRingBuf(u32 fd, vm::ptr<CellFsRingBuffer> ringbuf)
return CELL_FS_EBADF;
}
if (file->st_status.load() == SSS_NOT_INITIALIZED)
if (file->st_status == SSS_NOT_INITIALIZED)
{
return CELL_FS_ENXIO;
}
@ -455,7 +455,7 @@ s32 cellFsStReadGetRegid(u32 fd, vm::ptr<u64> regid)
return CELL_FS_EBADF;
}
if (file->st_status.load() == SSS_NOT_INITIALIZED)
if (file->st_status == SSS_NOT_INITIALIZED)
{
return CELL_FS_ENXIO;
}
@ -498,7 +498,7 @@ s32 cellFsStReadStart(u32 fd, u64 offset, u64 size)
{
std::unique_lock<std::mutex> lock(file->mutex);
while (file->st_status.load() == SSS_STARTED && !Emu.IsStopped())
while (file->st_status == SSS_STARTED && !Emu.IsStopped())
{
// check free space in buffer and available data in stream
if (file->st_total_read - file->st_copied <= file->st_ringbuf_size - file->st_block_size && file->st_total_read < file->st_read_size)
@ -518,11 +518,11 @@ s32 cellFsStReadStart(u32 fd, u64 offset, u64 size)
}
// check callback condition if set
if (file->st_callback.data.func)
if (file->st_callback.load().func)
{
const u64 available = file->st_total_read - file->st_copied;
if (available >= file->st_callback.data.size)
if (available >= file->st_callback.load().size)
{
const auto func = file->st_callback.exchange({}).func;
@ -540,7 +540,7 @@ s32 cellFsStReadStart(u32 fd, u64 offset, u64 size)
file->st_read_size = 0;
file->st_total_read = 0;
file->st_copied = 0;
file->st_callback.data = {};
file->st_callback.store({});
});
return CELL_OK;
@ -588,14 +588,14 @@ s32 cellFsStRead(u32 fd, vm::ptr<u8> buf, u64 size, vm::ptr<u64> rsize)
return CELL_FS_EBADF;
}
if (file->st_status.load() == SSS_NOT_INITIALIZED || file->st_copyless)
if (file->st_status == SSS_NOT_INITIALIZED || file->st_copyless)
{
return CELL_FS_ENXIO;
}
const u64 copied = file->st_copied.load();
const u64 copied = file->st_copied;
const u32 position = VM_CAST(file->st_buffer + copied % file->st_ringbuf_size);
const u64 total_read = file->st_total_read.load();
const u64 total_read = file->st_total_read;
const u64 copy_size = (*rsize = std::min<u64>(size, total_read - copied)); // write rsize
// copy data
@ -622,16 +622,16 @@ s32 cellFsStReadGetCurrentAddr(u32 fd, vm::ptr<u32> addr, vm::ptr<u64> size)
return CELL_FS_EBADF;
}
if (file->st_status.load() == SSS_NOT_INITIALIZED || !file->st_copyless)
if (file->st_status == SSS_NOT_INITIALIZED || !file->st_copyless)
{
return CELL_FS_ENXIO;
}
const u64 copied = file->st_copied.load();
const u64 copied = file->st_copied;
const u32 position = VM_CAST(file->st_buffer + copied % file->st_ringbuf_size);
const u64 total_read = file->st_total_read.load();
const u64 total_read = file->st_total_read;
if ((*size = std::min<u64>(file->st_ringbuf_size - (position - file->st_buffer), total_read - copied)).data())
if ((*size = std::min<u64>(file->st_ringbuf_size - (position - file->st_buffer), total_read - copied)))
{
*addr = position;
}
@ -655,13 +655,13 @@ s32 cellFsStReadPutCurrentAddr(u32 fd, vm::ptr<u8> addr, u64 size)
return CELL_FS_EBADF;
}
if (file->st_status.load() == SSS_NOT_INITIALIZED || !file->st_copyless)
if (file->st_status == SSS_NOT_INITIALIZED || !file->st_copyless)
{
return CELL_FS_ENXIO;
}
const u64 copied = file->st_copied.load();
const u64 total_read = file->st_total_read.load();
const u64 copied = file->st_copied;
const u64 total_read = file->st_total_read;
// notify
file->st_copied += size;
@ -682,7 +682,7 @@ s32 cellFsStReadWait(u32 fd, u64 size)
return CELL_FS_EBADF;
}
if (file->st_status.load() == SSS_NOT_INITIALIZED)
if (file->st_status == SSS_NOT_INITIALIZED)
{
return CELL_FS_ENXIO;
}
@ -711,7 +711,7 @@ s32 cellFsStReadWaitCallback(u32 fd, u64 size, fs_st_cb_t func)
return CELL_FS_EBADF;
}
if (file->st_status.load() == SSS_NOT_INITIALIZED)
if (file->st_status == SSS_NOT_INITIALIZED)
{
return CELL_FS_ENXIO;
}
@ -1051,7 +1051,7 @@ s32 cellFsUnregisterL10nCallbacks()
}
Module cellFs("cellFs", []()
Module<> cellFs("cellFs", []()
{
g_fs_aio_id = 1;

View File

@ -11,7 +11,7 @@
#include "cellSysutil.h"
#include "cellGame.h"
extern Module cellGame;
extern Module<> cellGame;
// Specified as second content_permission_t constructor argument to inform temporary directory
static struct temporary_content_dir_tag_t{} const temporary_content_dir_tag{};
@ -706,7 +706,7 @@ s32 cellGameUnregisterDiscChangeCallback()
void cellSysutil_GameData_init()
{
extern Module cellSysutil;
extern Module<> cellSysutil;
REG_FUNC(cellSysutil, cellHddGameCheck);
REG_FUNC(cellSysutil, cellHddGameCheck2);
@ -728,7 +728,7 @@ void cellSysutil_GameData_init()
REG_FUNC(cellSysutil, cellGameUnregisterDiscChangeCallback);
}
Module cellGame("cellGame", []()
Module<> cellGame("cellGame", []()
{
REG_FUNC(cellGame, cellGameBootCheck);
REG_FUNC(cellGame, cellGamePatchCheck);

View File

@ -4,7 +4,7 @@
#include "cellGame.h"
extern Module cellGameExec;
extern Module<> cellGameExec;
s32 cellGameSetExitParam()
{
@ -45,7 +45,7 @@ s32 cellGameGetBootGameInfo(vm::ptr<u32> type, vm::ptr<char> dirName, vm::ptr<u3
return CELL_OK;
}
Module cellGameExec("cellGameExec", []()
Module<> cellGameExec("cellGameExec", []()
{
REG_FUNC(cellGameExec, cellGameSetExitParam);
REG_FUNC(cellGameExec, cellGameGetHomeDataExportPath);

View File

@ -11,7 +11,7 @@
//#include "Emu/SysCalls/lv2/sys_process.h"
#include "cellGcmSys.h"
extern Module cellGcmSys;
extern Module<> cellGcmSys;
const u32 tiled_pitches[] = {
0x00000000, 0x00000200, 0x00000300, 0x00000400,
@ -383,9 +383,9 @@ s32 _cellGcmInitBody(vm::pptr<CellGcmContextData> context, u32 cmdSize, u32 ioSi
context->set(gcm_info.context_addr);
auto& ctrl = vm::get_ref<CellGcmControl>(gcm_info.control_addr);
ctrl.put.store(0);
ctrl.get.store(0);
ctrl.ref.store(-1);
ctrl.put = 0;
ctrl.get = 0;
ctrl.ref = -1;
auto& render = Emu.GetGSManager().GetRender();
render.m_ctxt_addr = context.addr();
@ -1297,7 +1297,7 @@ s32 cellGcmCallback(vm::ptr<CellGcmContextData> context, u32 count)
//----------------------------------------------------------------------------
Module cellGcmSys("cellGcmSys", []()
Module<> cellGcmSys("cellGcmSys", []()
{
current_config.ioAddress = 0;
current_config.localAddress = 0;

View File

@ -5,7 +5,7 @@
#include "cellGem.h"
extern Module cellGem;
extern Module<> cellGem;
struct gem_t
{
@ -273,7 +273,7 @@ s32 cellGemWriteExternalPort()
return CELL_OK;
}
Module cellGem("cellGem", []()
Module<> cellGem("cellGem", []()
{
REG_FUNC(cellGem, cellGemCalibrate);
REG_FUNC(cellGem, cellGemClearStatusFlags);

View File

@ -16,7 +16,7 @@ extern "C"
#include "cellGifDec.h"
extern Module cellGifDec;
extern Module<> cellGifDec;
// cellGifDec aliases (only for cellGifDec.cpp)
using PPMainHandle = vm::pptr<GifDecoder>;
@ -303,7 +303,7 @@ s32 cellGifDecDestroy(PMainHandle mainHandle)
return CELL_OK;
}
Module cellGifDec("cellGifDec", []()
Module<> cellGifDec("cellGifDec", []()
{
REG_FUNC(cellGifDec, cellGifDecCreate);
REG_FUNC(cellGifDec, cellGifDecExtCreate);

View File

@ -2,8 +2,8 @@
#include "Emu/Memory/Memory.h"
#include "Emu/SysCalls/Modules.h"
extern Module cellHttp;
extern Module cellHttps;
extern Module<> cellHttp;
extern Module<> cellHttps;
s32 cellHttpInit()
{
@ -599,7 +599,7 @@ s32 cellHttpClientSetSslIdDestroyCallback()
return CELL_OK;
}
Module cellHttp("cellHttp", []()
Module<> cellHttp("cellHttp", []()
{
REG_FUNC(cellHttp, cellHttpInit);
REG_FUNC(cellHttp, cellHttpEnd);
@ -713,7 +713,7 @@ Module cellHttp("cellHttp", []()
REG_FUNC(cellHttp, cellHttpClientSetSslIdDestroyCallback);
});
Module cellHttps("cellHttps", []()
Module<> cellHttps("cellHttps", []()
{
// cellHttps doesn't have functions (cellHttpsInit belongs to cellHttp, for example)
});

View File

@ -2,7 +2,7 @@
#include "Emu/Memory/Memory.h"
#include "Emu/SysCalls/Modules.h"
extern Module cellHttpUtil;
extern Module<> cellHttpUtil;
s32 cellHttpUtilParseUri()
{
@ -124,7 +124,7 @@ s32 cellHttpUtilBase64Decoder()
return CELL_OK;
}
Module cellHttpUtil("cellHttpUtil", []()
Module<> cellHttpUtil("cellHttpUtil", []()
{
REG_FUNC(cellHttpUtil, cellHttpUtilParseUri);
REG_FUNC(cellHttpUtil, cellHttpUtilParseUriPath);

View File

@ -2,7 +2,7 @@
#include "Emu/Memory/Memory.h"
#include "Emu/SysCalls/Modules.h"
extern Module cellImeJp;
extern Module<> cellImeJp;
// Return Codes
enum
@ -262,7 +262,7 @@ s32 cellImeJpConfirmPrediction()
return CELL_OK;
}
Module cellImeJp("cellImeJp", []()
Module<> cellImeJp("cellImeJp", []()
{
REG_FUNC(cellImeJp, cellImeJpOpen);
REG_FUNC(cellImeJp, cellImeJpOpen2);

View File

@ -15,7 +15,7 @@ extern "C"
#include "cellJpgDec.h"
extern Module cellJpgDec;
extern Module<> cellJpgDec;
s32 cellJpgDecCreate(u32 mainHandle, u32 threadInParam, u32 threadOutParam)
{
@ -359,7 +359,7 @@ s32 cellJpgDecExtSetParameter()
}
Module cellJpgDec("cellJpgDec", []()
Module<> cellJpgDec("cellJpgDec", []()
{
REG_FUNC(cellJpgDec, cellJpgDecCreate);
REG_FUNC(cellJpgDec, cellJpgDecExtCreate);

View File

@ -2,7 +2,7 @@
#include "Emu/Memory/Memory.h"
#include "Emu/SysCalls/Modules.h"
extern Module cellJpgEnc;
extern Module<> cellJpgEnc;
// Error Codes
enum
@ -75,7 +75,7 @@ s32 cellJpgEncReset()
return CELL_OK;
}
Module cellJpgEnc("cellJpgEnc", []()
Module<> cellJpgEnc("cellJpgEnc", []()
{
REG_FUNC(cellJpgEnc, cellJpgEncQueryAttr);
REG_FUNC(cellJpgEnc, cellJpgEncOpen);

View File

@ -6,7 +6,7 @@
#include "Emu/Io/Keyboard.h"
#include "cellKb.h"
extern Module sys_io;
extern Module<> sys_io;
s32 cellKbInit(u32 max_connect)
{

View File

@ -2,7 +2,7 @@
#include "Emu/Memory/Memory.h"
#include "Emu/SysCalls/Modules.h"
extern Module cellKey2char;
extern Module<> cellKey2char;
// Return Codes
enum
@ -46,7 +46,7 @@ s32 cellKey2CharSetArrangement()
return CELL_OK;
}
Module cellKey2char("cellKey2char", []()
Module<> cellKey2char("cellKey2char", []()
{
REG_FUNC(cellKey2char, cellKey2CharOpen);
REG_FUNC(cellKey2char, cellKey2CharClose);

View File

@ -10,7 +10,7 @@
#include "cellL10n.h"
extern Module cellL10n;
extern Module<> cellL10n;
// Translate code id to code name. some codepage may has another name.
// If this makes your compilation fail, try replace the string code with one in "iconv -l"
@ -1163,7 +1163,8 @@ s32 UTF8stoUCS2s()
throw EXCEPTION("");
}
Module cellL10n("cellL10n", []()
Module<> cellL10n("cellL10n", []()
{
REG_FUNC(cellL10n, UCS2toEUCJP);
REG_FUNC(cellL10n, l10n_convert);

View File

@ -5,7 +5,7 @@
#include "cellMic.h"
extern Module cellMic;
extern Module<> cellMic;
s32 cellMicInit()
{
@ -260,7 +260,7 @@ s32 cellMicGetDeviceIdentifier()
return CELL_OK;
}
Module cellMic("cellMic", []()
Module<> cellMic("cellMic", []()
{
REG_FUNC(cellMic, cellMicInit);
REG_FUNC(cellMic, cellMicEnd);

View File

@ -6,7 +6,7 @@
#include "Emu/Io/Mouse.h"
#include "cellMouse.h"
extern Module sys_io;
extern Module<> sys_io;
s32 cellMouseInit(u32 max_connect)
{

View File

@ -1,26 +1,21 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/IdManager.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/Callback.h"
#include "cellSysutil.h"
#include "cellMsgDialog.h"
extern Module cellSysutil;
extern Module<> cellSysutil;
extern u64 get_system_time();
std::unique_ptr<MsgDialogInstance> g_msg_dialog;
MsgDialogInstance::MsgDialogInstance()
void MsgDialogBase::Close(s32 status)
{
}
void MsgDialogInstance::Close()
{
state = msgDialogClose;
wait_until = get_system_time();
if (state.compare_and_swap_test(MsgDialogState::Open, MsgDialogState::Close))
{
on_close(status);
}
}
s32 cellMsgDialogOpen()
@ -86,19 +81,20 @@ s32 cellMsgDialogOpen2(u32 type, vm::cptr<char> msgString, vm::ptr<CellMsgDialog
default: return CELL_MSGDIALOG_ERROR_PARAM;
}
MsgDialogState old = msgDialogNone;
if (!g_msg_dialog->state.compare_exchange_strong(old, msgDialogInit))
const auto dlg = fxm::import<MsgDialogBase>(Emu.GetCallbacks().get_msg_dialog());
if (!dlg)
{
return CELL_SYSUTIL_ERROR_BUSY;
}
g_msg_dialog->wait_until = get_system_time() + 31536000000000ull; // some big value
dlg->type = type;
switch (type & CELL_MSGDIALOG_TYPE_PROGRESSBAR)
{
case CELL_MSGDIALOG_TYPE_PROGRESSBAR_DOUBLE: g_msg_dialog->progress_bar_count = 2; break;
case CELL_MSGDIALOG_TYPE_PROGRESSBAR_SINGLE: g_msg_dialog->progress_bar_count = 1; break;
default: g_msg_dialog->progress_bar_count = 0; break;
case CELL_MSGDIALOG_TYPE_PROGRESSBAR_DOUBLE: dlg->progress_bar_count = 2; break;
case CELL_MSGDIALOG_TYPE_PROGRESSBAR_SINGLE: dlg->progress_bar_count = 1; break;
default: dlg->progress_bar_count = 0; break;
}
switch (type & CELL_MSGDIALOG_TYPE_SE_MUTE) // TODO
@ -107,75 +103,34 @@ s32 cellMsgDialogOpen2(u32 type, vm::cptr<char> msgString, vm::ptr<CellMsgDialog
case CELL_MSGDIALOG_TYPE_SE_MUTE_ON: break;
}
std::string msg = msgString.get_ptr();
switch (type & CELL_MSGDIALOG_TYPE_SE_TYPE)
{
case CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL: cellSysutil.Warning("%s", msg); break;
case CELL_MSGDIALOG_TYPE_SE_TYPE_ERROR: cellSysutil.Error("%s", msg); break;
case CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL: cellSysutil.Warning(msgString.get_ptr()); break;
case CELL_MSGDIALOG_TYPE_SE_TYPE_ERROR: cellSysutil.Error(msgString.get_ptr()); break;
}
g_msg_dialog->status = CELL_MSGDIALOG_BUTTON_NONE;
dlg->callback = callback;
dlg->user_data = userData;
dlg->extra_param = extParam;
CallAfter([type, msg]()
dlg->on_close = [](s32 status)
{
if (Emu.IsStopped())
const auto dlg = fxm::get<MsgDialogBase>();
if (dlg->callback)
{
g_msg_dialog->state.exchange(msgDialogNone);
return;
}
g_msg_dialog->Create(type, msg);
g_msg_dialog->state.exchange(msgDialogOpen);
});
while (g_msg_dialog->state == msgDialogInit)
{
if (Emu.IsStopped())
{
if (g_msg_dialog->state != msgDialogNone)
Emu.GetCallbackManager().Register([func = dlg->callback, status, arg = dlg->user_data](CPUThread& cpu)->s32
{
break;
}
CHECK_EMU_STATUS;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
}
named_thread_t(WRAP_EXPR("MsgDialog Thread"), [=]()
{
while (g_msg_dialog->state == msgDialogOpen || (s64)(get_system_time() - g_msg_dialog->wait_until) < 0)
{
if (Emu.IsStopped())
{
g_msg_dialog->state = msgDialogAbort;
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
}
if (callback && g_msg_dialog->state != msgDialogAbort)
{
const s32 status = g_msg_dialog->status;
Emu.GetCallbackManager().Register([=](CPUThread& cpu) -> s32
{
callback(static_cast<PPUThread&>(cpu), status, userData);
func(static_cast<PPUThread&>(cpu), status, arg);
return CELL_OK;
});
}
CallAfter([]()
{
g_msg_dialog->Destroy();
g_msg_dialog->state = msgDialogNone;
});
fxm::remove<MsgDialogBase>();
};
}).detach();
// call initialization asynchronously from the GUI thread, wait for the "result"
Emu.CallAfter(WRAP_EXPR(dlg->Create(type, msgString.get_ptr()))).get();
return CELL_OK;
}
@ -266,25 +221,35 @@ s32 cellMsgDialogOpenSimulViewWarning()
throw EXCEPTION("");
}
s32 cellMsgDialogClose(float delay)
s32 cellMsgDialogClose(f32 delay)
{
cellSysutil.Warning("cellMsgDialogClose(delay=%f)", delay);
MsgDialogState old = msgDialogOpen;
const auto dlg = fxm::get<MsgDialogBase>();
if (!g_msg_dialog->state.compare_exchange_strong(old, msgDialogClose))
if (!dlg)
{
if (old == msgDialogNone)
{
return CELL_MSGDIALOG_ERROR_DIALOG_NOT_OPENED;
}
else
{
return CELL_SYSUTIL_ERROR_BUSY;
}
return CELL_MSGDIALOG_ERROR_DIALOG_NOT_OPENED;
}
g_msg_dialog->wait_until = get_system_time() + static_cast<u64>(std::max<float>(delay, 0.0f) * 1000);
extern u64 get_system_time();
const u64 wait_until = get_system_time() + static_cast<u64>(std::max<float>(delay, 0.0f) * 1000);
named_thread_t(WRAP_EXPR("MsgDialog Thread"), [=]()
{
while (dlg->state == MsgDialogState::Open && get_system_time() < wait_until)
{
CHECK_EMU_STATUS;
std::this_thread::sleep_for(1ms);
}
Emu.CallAfter(COPY_EXPR(dlg->Destroy()));
dlg->Close(CELL_MSGDIALOG_BUTTON_NONE);
}).detach();
return CELL_OK;
}
@ -293,21 +258,25 @@ s32 cellMsgDialogAbort()
{
cellSysutil.Warning("cellMsgDialogAbort()");
MsgDialogState old = msgDialogOpen;
const auto dlg = fxm::get<MsgDialogBase>();
if (!g_msg_dialog->state.compare_exchange_strong(old, msgDialogAbort))
if (!dlg)
{
if (old == msgDialogNone)
{
return CELL_MSGDIALOG_ERROR_DIALOG_NOT_OPENED;
}
else
{
return CELL_SYSUTIL_ERROR_BUSY;
}
return CELL_MSGDIALOG_ERROR_DIALOG_NOT_OPENED;
}
g_msg_dialog->wait_until = get_system_time();
if (!dlg->state.compare_and_swap_test(MsgDialogState::Open, MsgDialogState::Abort))
{
return CELL_SYSUTIL_ERROR_BUSY;
}
if (!fxm::remove<MsgDialogBase>())
{
throw EXCEPTION("Failed to remove MsgDialog object");
}
// call finalization from the GUI thread
Emu.CallAfter(COPY_EXPR(dlg->Destroy()));
return CELL_OK;
}
@ -316,17 +285,22 @@ s32 cellMsgDialogProgressBarSetMsg(u32 progressBarIndex, vm::cptr<char> msgStrin
{
cellSysutil.Warning("cellMsgDialogProgressBarSetMsg(progressBarIndex=%d, msgString=*0x%x)", progressBarIndex, msgString);
if (g_msg_dialog->state != msgDialogOpen)
const auto dlg = fxm::get<MsgDialogBase>();
if (!dlg)
{
return CELL_MSGDIALOG_ERROR_DIALOG_NOT_OPENED;
}
if (progressBarIndex >= g_msg_dialog->progress_bar_count)
if (progressBarIndex >= dlg->progress_bar_count)
{
return CELL_MSGDIALOG_ERROR_PARAM;
}
g_msg_dialog->ProgressBarSetMsg(progressBarIndex, msgString.get_ptr());
Emu.CallAfter([=, msg = std::string{ msgString.get_ptr() }]
{
dlg->ProgressBarSetMsg(progressBarIndex, msg);
});
return CELL_OK;
}
@ -335,17 +309,19 @@ s32 cellMsgDialogProgressBarReset(u32 progressBarIndex)
{
cellSysutil.Warning("cellMsgDialogProgressBarReset(progressBarIndex=%d)", progressBarIndex);
if (g_msg_dialog->state != msgDialogOpen)
const auto dlg = fxm::get<MsgDialogBase>();
if (!dlg)
{
return CELL_MSGDIALOG_ERROR_DIALOG_NOT_OPENED;
}
if (progressBarIndex >= g_msg_dialog->progress_bar_count)
if (progressBarIndex >= dlg->progress_bar_count)
{
return CELL_MSGDIALOG_ERROR_PARAM;
}
g_msg_dialog->ProgressBarReset(progressBarIndex);
Emu.CallAfter(COPY_EXPR(dlg->ProgressBarReset(progressBarIndex)));
return CELL_OK;
}
@ -354,25 +330,25 @@ s32 cellMsgDialogProgressBarInc(u32 progressBarIndex, u32 delta)
{
cellSysutil.Warning("cellMsgDialogProgressBarInc(progressBarIndex=%d, delta=%d)", progressBarIndex, delta);
if (g_msg_dialog->state != msgDialogOpen)
const auto dlg = fxm::get<MsgDialogBase>();
if (!dlg)
{
return CELL_MSGDIALOG_ERROR_DIALOG_NOT_OPENED;
}
if (progressBarIndex >= g_msg_dialog->progress_bar_count)
if (progressBarIndex >= dlg->progress_bar_count)
{
return CELL_MSGDIALOG_ERROR_PARAM;
}
g_msg_dialog->ProgressBarInc(progressBarIndex, delta);
Emu.CallAfter(COPY_EXPR(dlg->ProgressBarInc(progressBarIndex, delta)));
return CELL_OK;
}
void cellSysutil_MsgDialog_init()
{
g_msg_dialog->state = msgDialogNone;
REG_FUNC(cellSysutil, cellMsgDialogOpen);
REG_FUNC(cellSysutil, cellMsgDialogOpen2);
REG_FUNC(cellSysutil, cellMsgDialogOpenErrorCode);

View File

@ -84,31 +84,33 @@ enum : s32
using CellMsgDialogCallback = void(s32 buttonType, vm::ptr<void> userData);
enum MsgDialogState
enum class MsgDialogState
{
msgDialogNone,
msgDialogInit,
msgDialogOpen,
msgDialogClose,
msgDialogAbort,
Open,
Abort,
Close,
};
struct MsgDialogInstance
class MsgDialogBase
{
std::atomic<MsgDialogState> state;
public:
atomic_t<MsgDialogState> state{ MsgDialogState::Open };
s32 status;
u64 wait_until;
u32 type;
u32 progress_bar_count;
MsgDialogInstance();
virtual ~MsgDialogInstance() = default;
vm::ptr<CellMsgDialogCallback> callback;
vm::ptr<void> user_data;
vm::ptr<void> extra_param;
virtual void Close();
std::function<void(s32 status)> on_close;
virtual void Create(u32 type, std::string msg) = 0;
void Close(s32 status);
virtual ~MsgDialogBase() = default;
virtual void Create(u32 type, const std::string& msg) = 0;
virtual void Destroy() = 0;
virtual void ProgressBarSetMsg(u32 progressBarIndex, std::string msg) = 0;
virtual void ProgressBarSetMsg(u32 progressBarIndex, const std::string& msg) = 0;
virtual void ProgressBarReset(u32 progressBarIndex) = 0;
virtual void ProgressBarInc(u32 progressBarIndex, u32 delta) = 0;
};

View File

@ -7,7 +7,7 @@
#include "cellMusic.h"
extern Module cellMusic;
extern Module<> cellMusic;
struct music2_t
{
@ -149,7 +149,7 @@ s32 cellMusicGetVolume2()
}
Module cellMusic("cellMusic", []()
Module<> cellMusic("cellMusic", []()
{
REG_FUNC(cellMusic, cellMusicGetSelectionContext);
REG_FUNC(cellMusic, cellMusicSetSelectionContext2);

View File

@ -2,7 +2,7 @@
#include "Emu/Memory/Memory.h"
#include "Emu/SysCalls/Modules.h"
extern Module cellMusicDecode;
extern Module<> cellMusicDecode;
// Return Codes
enum
@ -145,7 +145,7 @@ s32 cellMusicDecodeGetContentsId2()
}
Module cellMusicDecode("cellMusicDecode", []()
Module<> cellMusicDecode("cellMusicDecode", []()
{
REG_FUNC(cellMusicDecode, cellMusicDecodeInitialize);
REG_FUNC(cellMusicDecode, cellMusicDecodeInitializeSystemWorkload);

View File

@ -2,7 +2,7 @@
#include "Emu/Memory/Memory.h"
#include "Emu/SysCalls/Modules.h"
extern Module cellMusicExport;
extern Module<> cellMusicExport;
// Return Codes
enum
@ -51,7 +51,7 @@ s32 cellMusicExportProgress()
return CELL_OK;
}
Module cellMusicExport("cellMusicExport", []()
Module<> cellMusicExport("cellMusicExport", []()
{
REG_FUNC(cellMusicExport, cellMusicExportInitialize);
REG_FUNC(cellMusicExport, cellMusicExportInitialize2);

View File

@ -28,7 +28,7 @@
#include <fcntl.h>
#endif
extern Module cellNetCtl;
extern Module<> cellNetCtl;
s32 cellNetCtlInit()
{
@ -423,7 +423,7 @@ s32 cellGameUpdateCheckStartWithoutDialogAsyncEx()
}
Module cellNetCtl("cellNetCtl", []()
Module<> cellNetCtl("cellNetCtl", []()
{
REG_FUNC(cellNetCtl, cellNetCtlInit);
REG_FUNC(cellNetCtl, cellNetCtlTerm);

View File

@ -2,7 +2,7 @@
#include "Emu/Memory/Memory.h"
#include "Emu/SysCalls/Modules.h"
extern Module cellOskDialog;
extern Module<> cellOskDialog;
s32 cellOskDialogLoadAsync()
{
@ -153,7 +153,7 @@ s32 cellOskDialogExtRegisterForceFinishCallback()
void cellSysutil_OskDialog_init()
{
extern Module cellSysutil;
extern Module<> cellSysutil;
// cellOskDialog functions:
REG_FUNC(cellSysutil, cellOskDialogLoadAsync);
@ -171,7 +171,7 @@ void cellSysutil_OskDialog_init()
REG_FUNC(cellSysutil, cellOskDialogGetInputText);
}
Module cellOskDialog("cellOskDialog", []()
Module<> cellOskDialog("cellOskDialog", []()
{
// cellOskDialogExt functions:
REG_FUNC(cellOskDialog, cellOskDialogExtInputDeviceUnlock);

View File

@ -4,7 +4,7 @@
namespace vm { using namespace ps3; }
extern Module cellOvis;
extern Module<> cellOvis;
// Return Codes
enum
@ -38,7 +38,7 @@ s32 cellOvisInvalidateOverlappedSegments()
return CELL_OK;
}
Module cellOvis("cellOvis", []()
Module<> cellOvis("cellOvis", []()
{
REG_FUNC(cellOvis, cellOvisGetOverlayTableSize);
REG_FUNC(cellOvis, cellOvisInitializeOverlayTable);

View File

@ -6,7 +6,7 @@
#include "Emu/Io/Pad.h"
#include "cellPad.h"
extern Module sys_io;
extern Module<> sys_io;
s32 cellPadInit(u32 max_connect)
{

View File

@ -5,7 +5,7 @@
#include "cellPamf.h"
extern Module cellPamf;
extern Module<> cellPamf;
s32 pamfStreamTypeToEsFilterId(u8 type, u8 ch, CellCodecEsFilterId& pEsFilterId)
{
@ -733,7 +733,7 @@ s32 cellPamfEpIteratorMove(vm::ptr<CellPamfEpIterator> pIt, s32 steps, vm::ptr<C
return 0;
}
Module cellPamf("cellPamf", []()
Module<> cellPamf("cellPamf", []()
{
REG_FUNC(cellPamf, cellPamfGetHeaderSize);
REG_FUNC(cellPamf, cellPamfGetHeaderSize2);

View File

@ -2,7 +2,7 @@
#include "Emu/Memory/Memory.h"
#include "Emu/SysCalls/Modules.h"
extern Module cellPhotoDecode;
extern Module<> cellPhotoDecode;
// Return Codes
enum
@ -56,7 +56,7 @@ s32 cellPhotoDecodeFromFile()
return CELL_OK;
}
Module cellPhotoDecode("cellPhotoDecode", []()
Module<> cellPhotoDecode("cellPhotoDecode", []()
{
REG_FUNC(cellPhotoDecode, cellPhotoDecodeInitialize);
REG_FUNC(cellPhotoDecode, cellPhotoDecodeInitialize2);

View File

@ -2,7 +2,7 @@
#include "Emu/Memory/Memory.h"
#include "Emu/SysCalls/Modules.h"
extern Module cellPhotoExport;
extern Module<> cellPhotoExport;
// Return Codes
enum
@ -75,7 +75,7 @@ s32 cellPhotoExportProgress()
return CELL_OK;
}
Module cellPhotoExport("cellPhotoExport", []()
Module<> cellPhotoExport("cellPhotoExport", []()
{
REG_FUNC(cellPhotoExport, cellPhotoInitialize);
REG_FUNC(cellPhotoExport, cellPhotoFinalize);

Some files were not shown because too many files have changed in this diff Show More