mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-01-27 03:35:24 +00:00
vm::var improved, cleanup
Mostly vm::var initialization introduced. Added vm::make_var function.
This commit is contained in:
parent
cc02a147d3
commit
a974ee009e
@ -161,11 +161,7 @@ inline u128 sync_fetch_and_add(volatile u128* dest, u128 value)
|
||||
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;
|
||||
if (sync_bool_compare_and_swap(dest, old, old + value)) return old;
|
||||
}
|
||||
}
|
||||
|
||||
@ -199,11 +195,7 @@ inline u128 sync_fetch_and_sub(volatile u128* dest, u128 value)
|
||||
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;
|
||||
if (sync_bool_compare_and_swap(dest, old, old - value)) return old;
|
||||
}
|
||||
}
|
||||
|
||||
@ -237,11 +229,7 @@ inline u128 sync_fetch_and_or(volatile u128* dest, u128 value)
|
||||
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;
|
||||
if (sync_bool_compare_and_swap(dest, old, old | value)) return old;
|
||||
}
|
||||
}
|
||||
|
||||
@ -275,11 +263,7 @@ inline u128 sync_fetch_and_and(volatile u128* dest, u128 value)
|
||||
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;
|
||||
if (sync_bool_compare_and_swap(dest, old, old & value)) return old;
|
||||
}
|
||||
}
|
||||
|
||||
@ -313,11 +297,7 @@ inline u128 sync_fetch_and_xor(volatile u128* dest, u128 value)
|
||||
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;
|
||||
if (sync_bool_compare_and_swap(dest, old, old ^ value)) return old;
|
||||
}
|
||||
}
|
||||
|
||||
@ -355,17 +335,17 @@ template<typename T> struct atomic_storage<T, 16>
|
||||
|
||||
template<typename T> using atomic_storage_t = typename atomic_storage<T>::type;
|
||||
|
||||
// result wrapper to deal with void result type
|
||||
// atomic result wrapper; implements special behaviour for 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)
|
||||
template<typename... Args> atomic_op_result_t(T func, VT& var, Args&&... args)
|
||||
: result(std::move(func(var, std::forward<Args>(args)...)))
|
||||
{
|
||||
}
|
||||
|
||||
inline RT move()
|
||||
RT move()
|
||||
{
|
||||
return std::move(result);
|
||||
}
|
||||
@ -376,13 +356,13 @@ 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)
|
||||
template<typename... Args> atomic_op_result_t(T func, VT& var, Args&&... args)
|
||||
: result(var)
|
||||
{
|
||||
func(var, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
inline VT move()
|
||||
VT move()
|
||||
{
|
||||
return std::move(result);
|
||||
}
|
||||
@ -393,12 +373,12 @@ template<typename CT, typename... FArgs, typename RT, typename VT> struct atomic
|
||||
{
|
||||
RT result;
|
||||
|
||||
template<typename... Args> inline atomic_op_result_t(RT(CT::*func)(FArgs...), VT& var, Args&&... args)
|
||||
template<typename... Args> atomic_op_result_t(RT(CT::*func)(FArgs...), VT& var, Args&&... args)
|
||||
: result(std::move((var.*func)(std::forward<Args>(args)...)))
|
||||
{
|
||||
}
|
||||
|
||||
inline RT move()
|
||||
RT move()
|
||||
{
|
||||
return std::move(result);
|
||||
}
|
||||
@ -409,18 +389,19 @@ template<typename CT, typename... FArgs, typename VT> struct atomic_op_result_t<
|
||||
{
|
||||
VT result;
|
||||
|
||||
template<typename... Args> inline atomic_op_result_t(void(CT::*func)(FArgs...), VT& var, Args&&... args)
|
||||
template<typename... Args> atomic_op_result_t(void(CT::*func)(FArgs...), VT& var, Args&&... args)
|
||||
: result(var)
|
||||
{
|
||||
(var.*func)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
inline VT move()
|
||||
VT move()
|
||||
{
|
||||
return std::move(result);
|
||||
}
|
||||
};
|
||||
|
||||
// Atomic type with lock-free and standard layout guarantees (and appropriate limitations)
|
||||
template<typename T> class atomic_t
|
||||
{
|
||||
using type = std::remove_cv_t<T>;
|
||||
@ -466,18 +447,14 @@ public:
|
||||
|
||||
atomic_t(const atomic_t&) = delete;
|
||||
|
||||
atomic_t(atomic_t&&) = delete;
|
||||
|
||||
inline atomic_t(type value)
|
||||
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)
|
||||
atomic_t& operator =(type value)
|
||||
{
|
||||
return write_relaxed(m_data, to_subtype(value)), *this;
|
||||
}
|
||||
@ -500,31 +477,31 @@ public:
|
||||
}
|
||||
|
||||
// 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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
void store(const type& value) volatile
|
||||
{
|
||||
write_relaxed(m_data, to_subtype(value));
|
||||
}
|
||||
@ -550,40 +527,40 @@ public:
|
||||
}
|
||||
|
||||
// Atomic bitwise OR, returns previous data
|
||||
inline const type _or(const type& right) volatile
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
type operator ^=(const type& right) volatile
|
||||
{
|
||||
return from_subtype(sync_fetch_and_xor(&m_data, to_subtype(right)) ^ to_subtype(right));
|
||||
}
|
||||
@ -697,9 +674,11 @@ template<typename T, typename T2> inline std::enable_if_t<IS_INTEGRAL(T) && std:
|
||||
});
|
||||
}
|
||||
|
||||
template<typename T> using atomic_be_t = atomic_t<be_t<T>>; // Atomic BE Type (for PS3 virtual memory)
|
||||
// Atomic BE Type (for PS3 virtual memory)
|
||||
template<typename T> using atomic_be_t = atomic_t<be_t<T>>;
|
||||
|
||||
template<typename T> using atomic_le_t = atomic_t<le_t<T>>; // Atomic LE Type (for PSV virtual memory)
|
||||
// Atomic LE Type (for PSV virtual memory)
|
||||
template<typename T> using atomic_le_t = atomic_t<le_t<T>>;
|
||||
|
||||
// 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)
|
||||
|
@ -8,34 +8,34 @@
|
||||
|
||||
#define IS_LE_MACHINE // only draft
|
||||
|
||||
template<typename T, std::size_t N, std::size_t M> class masked_array_t // array type accessed as (index ^ M)
|
||||
{
|
||||
T m_data[N];
|
||||
|
||||
public:
|
||||
T& operator [](std::size_t index)
|
||||
{
|
||||
return m_data[index ^ M];
|
||||
}
|
||||
|
||||
const T& operator [](std::size_t index) const
|
||||
{
|
||||
return m_data[index ^ M];
|
||||
}
|
||||
|
||||
T& at(std::size_t index)
|
||||
{
|
||||
return (index ^ M) < N ? m_data[index ^ M] : throw std::out_of_range("Masked array");
|
||||
}
|
||||
|
||||
const T& at(std::size_t index) const
|
||||
{
|
||||
return (index ^ M) < N ? m_data[index ^ M] : throw std::out_of_range("Masked array");
|
||||
}
|
||||
};
|
||||
|
||||
union v128
|
||||
{
|
||||
template<typename T, std::size_t N, std::size_t M> class masked_array_t // array type accessed as (index ^ M)
|
||||
{
|
||||
T m_data[N];
|
||||
|
||||
public:
|
||||
T& operator [](std::size_t index)
|
||||
{
|
||||
return m_data[index ^ M];
|
||||
}
|
||||
|
||||
const T& operator [](std::size_t index) const
|
||||
{
|
||||
return m_data[index ^ M];
|
||||
}
|
||||
|
||||
T& at(std::size_t index)
|
||||
{
|
||||
return (index ^ M) < N ? m_data[index ^ M] : throw std::out_of_range(__FUNCTION__);
|
||||
}
|
||||
|
||||
const T& at(std::size_t index) const
|
||||
{
|
||||
return (index ^ M) < N ? m_data[index ^ M] : throw std::out_of_range(__FUNCTION__);
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef IS_LE_MACHINE
|
||||
template<typename T, std::size_t N = 16 / sizeof(T)> using normal_array_t = masked_array_t<T, N, 0>;
|
||||
template<typename T, std::size_t N = 16 / sizeof(T)> using reversed_array_t = masked_array_t<T, N, N - 1>;
|
||||
@ -90,12 +90,12 @@ union v128
|
||||
{
|
||||
}
|
||||
|
||||
inline operator bool() const
|
||||
operator bool() const
|
||||
{
|
||||
return (data & mask) != 0;
|
||||
}
|
||||
|
||||
inline bit_element& operator =(const bool right)
|
||||
bit_element& operator =(const bool right)
|
||||
{
|
||||
if (right)
|
||||
{
|
||||
@ -108,7 +108,7 @@ union v128
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline bit_element& operator =(const bit_element& right)
|
||||
bit_element& operator =(const bit_element& right)
|
||||
{
|
||||
if (right)
|
||||
{
|
||||
@ -144,14 +144,14 @@ union v128
|
||||
|
||||
bit_element at(u32 index)
|
||||
{
|
||||
if (index >= 128) throw std::out_of_range("Bit element");
|
||||
if (index >= 128) throw std::out_of_range(__FUNCTION__);
|
||||
|
||||
return operator[](index);
|
||||
}
|
||||
|
||||
bool at(u32 index) const
|
||||
{
|
||||
if (index >= 128) throw std::out_of_range("Bit element");
|
||||
if (index >= 128) throw std::out_of_range(__FUNCTION__);
|
||||
|
||||
return operator[](index);
|
||||
}
|
||||
@ -320,12 +320,12 @@ union v128
|
||||
return _u64[0] != right._u64[0] || _u64[1] != right._u64[1];
|
||||
}
|
||||
|
||||
inline bool is_any_1() const // check if any bit is 1
|
||||
bool is_any_1() const // check if any bit is 1
|
||||
{
|
||||
return _u64[0] || _u64[1];
|
||||
}
|
||||
|
||||
inline bool is_any_0() const // check if any bit is 0
|
||||
bool is_any_0() const // check if any bit is 0
|
||||
{
|
||||
return ~_u64[0] || ~_u64[1];
|
||||
}
|
||||
@ -486,14 +486,14 @@ template<typename T1, typename T2> struct se_convert
|
||||
}
|
||||
};
|
||||
|
||||
static struct se_raw_tag_t {} const se_raw{};
|
||||
static struct se_raw_tag_t {} constexpr se_raw{};
|
||||
|
||||
template<typename T, bool Se = true> class se_t;
|
||||
|
||||
// se_t with switched endianness
|
||||
template<typename T> class se_t<T, true>
|
||||
{
|
||||
using type = std::remove_cv_t<T>;
|
||||
using type = typename std::remove_cv<T>::type;
|
||||
using stype = se_storage_t<type>;
|
||||
using storage = se_storage<type>;
|
||||
|
||||
@ -506,7 +506,7 @@ template<typename T> class se_t<T, true>
|
||||
static_assert(!std::is_enum<type>::value, "se_t<> error: invalid type (enumeration), use integral type instead");
|
||||
static_assert(alignof(type) == alignof(stype), "se_t<> error: unexpected alignment");
|
||||
|
||||
template<typename T2, bool = std::is_integral<T2>::value> struct bool_converter
|
||||
template<typename T2, typename = void> struct bool_converter
|
||||
{
|
||||
static inline bool to_bool(const se_t<T2>& value)
|
||||
{
|
||||
@ -514,7 +514,7 @@ template<typename T> class se_t<T, true>
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T2> struct bool_converter<T2, true>
|
||||
template<typename T2> struct bool_converter<T2, std::enable_if_t<std::is_integral<T2>::value>>
|
||||
{
|
||||
static inline bool to_bool(const se_t<T2>& value)
|
||||
{
|
||||
@ -527,78 +527,78 @@ public:
|
||||
|
||||
se_t(const se_t& right) = default;
|
||||
|
||||
inline se_t(type value)
|
||||
se_t(type value)
|
||||
: m_data(storage::to(value))
|
||||
{
|
||||
}
|
||||
|
||||
// construct directly from raw data (don't use)
|
||||
inline se_t(const stype& raw_value, const se_raw_tag_t&)
|
||||
constexpr se_t(const stype& raw_value, const se_raw_tag_t&)
|
||||
: m_data(raw_value)
|
||||
{
|
||||
}
|
||||
|
||||
inline type value() const
|
||||
type value() const
|
||||
{
|
||||
return storage::from(m_data);
|
||||
}
|
||||
|
||||
// access underlying raw data (don't use)
|
||||
inline const stype& raw_data() const noexcept
|
||||
constexpr const stype& raw_data() const noexcept
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
se_t& operator =(const se_t&) = default;
|
||||
|
||||
inline se_t& operator =(type value)
|
||||
se_t& operator =(type value)
|
||||
{
|
||||
return m_data = storage::to(value), *this;
|
||||
}
|
||||
|
||||
inline operator type() const
|
||||
operator type() const
|
||||
{
|
||||
return storage::from(m_data);
|
||||
}
|
||||
|
||||
// optimization
|
||||
explicit inline operator bool() const
|
||||
explicit operator bool() const
|
||||
{
|
||||
return bool_converter<type>::to_bool(*this);
|
||||
}
|
||||
|
||||
// optimization
|
||||
template<typename T2> inline std::enable_if_t<IS_BINARY_COMPARABLE(T, T2), se_t&> operator &=(const se_t<T2>& right)
|
||||
template<typename T2> std::enable_if_t<IS_BINARY_COMPARABLE(T, T2), se_t&> operator &=(const se_t<T2>& right)
|
||||
{
|
||||
return m_data &= right.raw_data(), *this;
|
||||
}
|
||||
|
||||
// optimization
|
||||
template<typename CT> inline std::enable_if_t<IS_INTEGRAL(T) && std::is_convertible<CT, T>::value, se_t&> operator &=(CT right)
|
||||
template<typename CT> std::enable_if_t<IS_INTEGRAL(T) && std::is_convertible<CT, T>::value, se_t&> operator &=(CT right)
|
||||
{
|
||||
return m_data &= storage::to(right), *this;
|
||||
}
|
||||
|
||||
// optimization
|
||||
template<typename T2> inline std::enable_if_t<IS_BINARY_COMPARABLE(T, T2), se_t&> operator |=(const se_t<T2>& right)
|
||||
template<typename T2> std::enable_if_t<IS_BINARY_COMPARABLE(T, T2), se_t&> operator |=(const se_t<T2>& right)
|
||||
{
|
||||
return m_data |= right.raw_data(), *this;
|
||||
}
|
||||
|
||||
// optimization
|
||||
template<typename CT> inline std::enable_if_t<IS_INTEGRAL(T) && std::is_convertible<CT, T>::value, se_t&> operator |=(CT right)
|
||||
template<typename CT> std::enable_if_t<IS_INTEGRAL(T) && std::is_convertible<CT, T>::value, se_t&> operator |=(CT right)
|
||||
{
|
||||
return m_data |= storage::to(right), *this;
|
||||
}
|
||||
|
||||
// optimization
|
||||
template<typename T2> inline std::enable_if_t<IS_BINARY_COMPARABLE(T, T2), se_t&> operator ^=(const se_t<T2>& right)
|
||||
template<typename T2> std::enable_if_t<IS_BINARY_COMPARABLE(T, T2), se_t&> operator ^=(const se_t<T2>& right)
|
||||
{
|
||||
return m_data ^= right.raw_data(), *this;
|
||||
}
|
||||
|
||||
// optimization
|
||||
template<typename CT> inline std::enable_if_t<IS_INTEGRAL(T) && std::is_convertible<CT, T>::value, se_t&> operator ^=(CT right)
|
||||
template<typename CT> std::enable_if_t<IS_INTEGRAL(T) && std::is_convertible<CT, T>::value, se_t&> operator ^=(CT right)
|
||||
{
|
||||
return m_data ^= storage::to(right), *this;
|
||||
}
|
||||
@ -607,7 +607,7 @@ public:
|
||||
// se_t with native endianness
|
||||
template<typename T> class se_t<T, false>
|
||||
{
|
||||
using type = std::remove_cv_t<T>;
|
||||
using type = typename std::remove_cv<T>::type;
|
||||
|
||||
type m_data;
|
||||
|
||||
@ -622,39 +622,39 @@ public:
|
||||
|
||||
se_t(const se_t&) = default;
|
||||
|
||||
inline se_t(type value)
|
||||
constexpr se_t(type value)
|
||||
: m_data(value)
|
||||
{
|
||||
}
|
||||
|
||||
inline type value() const
|
||||
type value() const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
se_t& operator =(const se_t& value) = default;
|
||||
|
||||
inline se_t& operator =(type value)
|
||||
se_t& operator =(type value)
|
||||
{
|
||||
return m_data = value, *this;
|
||||
}
|
||||
|
||||
inline operator type() const
|
||||
operator type() const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
template<typename CT> inline std::enable_if_t<IS_INTEGRAL(T) && std::is_convertible<CT, T>::value, se_t&> operator &=(const CT& right)
|
||||
template<typename CT> std::enable_if_t<IS_INTEGRAL(T) && std::is_convertible<CT, T>::value, se_t&> operator &=(const CT& right)
|
||||
{
|
||||
return m_data &= right, *this;
|
||||
}
|
||||
|
||||
template<typename CT> inline std::enable_if_t<IS_INTEGRAL(T) && std::is_convertible<CT, T>::value, se_t&> operator |=(const CT& right)
|
||||
template<typename CT> std::enable_if_t<IS_INTEGRAL(T) && std::is_convertible<CT, T>::value, se_t&> operator |=(const CT& right)
|
||||
{
|
||||
return m_data |= right, *this;
|
||||
}
|
||||
|
||||
template<typename CT> inline std::enable_if_t<IS_INTEGRAL(T) && std::is_convertible<CT, T>::value, se_t&> operator ^=(const CT& right)
|
||||
template<typename CT> std::enable_if_t<IS_INTEGRAL(T) && std::is_convertible<CT, T>::value, se_t&> operator ^=(const CT& right)
|
||||
{
|
||||
return m_data ^= right, *this;
|
||||
}
|
||||
@ -837,107 +837,77 @@ template<typename T> using be_t = se_t<T, false>;
|
||||
template<typename T> using le_t = se_t<T, true>;
|
||||
#endif
|
||||
|
||||
template<typename T> struct is_be_t : public std::integral_constant<bool, false>
|
||||
|
||||
template<typename T, bool Se, typename = void> struct to_se
|
||||
{
|
||||
using type = typename std::conditional<std::is_arithmetic<T>::value || std::is_enum<T>::value, se_t<T, Se>, T>::type;
|
||||
};
|
||||
|
||||
template<typename T> struct is_be_t<be_t<T>> : public std::integral_constant<bool, true>
|
||||
template<typename T, bool Se> struct to_se<const T, Se, std::enable_if_t<!std::is_array<T>::value>> // move const qualifier
|
||||
{
|
||||
using type = const typename to_se<T, Se>::type;
|
||||
};
|
||||
|
||||
template<typename T> struct is_be_t<const T> : public std::integral_constant<bool, is_be_t<T>::value>
|
||||
template<typename T, bool Se> struct to_se<volatile T, Se, std::enable_if_t<!std::is_array<T>::value && !std::is_const<T>::value>> // move volatile qualifier
|
||||
{
|
||||
using type = volatile typename to_se<T, Se>::type;
|
||||
};
|
||||
|
||||
template<typename T> struct is_be_t<volatile T> : public std::integral_constant<bool, is_be_t<T>::value>
|
||||
template<typename T, bool Se> struct to_se<T[], Se>
|
||||
{
|
||||
using type = typename to_se<T, Se>::type[];
|
||||
};
|
||||
|
||||
// to_be_t helper struct
|
||||
template<typename T> struct to_be
|
||||
template<typename T, bool Se, std::size_t N> struct to_se<T[N], Se>
|
||||
{
|
||||
using type = std::conditional_t<std::is_arithmetic<T>::value || std::is_enum<T>::value || std::is_same<T, v128>::value || std::is_same<T, u128>::value, be_t<T>, T>;
|
||||
using type = typename to_se<T, Se>::type[N];
|
||||
};
|
||||
|
||||
// be_t<T> if possible, T otherwise
|
||||
template<typename T> using to_be_t = typename to_be<T>::type;
|
||||
template<bool Se> struct to_se<u128, Se> { using type = se_t<u128, Se>; };
|
||||
template<bool Se> struct to_se<v128, Se> { using type = se_t<v128, Se>; };
|
||||
template<bool Se> struct to_se<bool, Se> { using type = bool; };
|
||||
template<bool Se> struct to_se<char, Se> { using type = char; };
|
||||
template<bool Se> struct to_se<u8, Se> { using type = u8; };
|
||||
template<bool Se> struct to_se<s8, Se> { using type = s8; };
|
||||
|
||||
template<typename T> struct to_be<const T> // move const qualifier
|
||||
{
|
||||
using type = const to_be_t<T>;
|
||||
};
|
||||
#ifdef IS_LE_MACHINE
|
||||
template<typename T> using to_be_t = typename to_se<T, true>::type;
|
||||
template<typename T> using to_le_t = typename to_se<T, false>::type;
|
||||
#else
|
||||
template<typename T> using to_be_t = typename to_se<T, false>::type;
|
||||
template<typename T> using to_le_t = typename to_se<T, true>::type;
|
||||
#endif
|
||||
|
||||
template<typename T> struct to_be<volatile T> // move volatile qualifier
|
||||
{
|
||||
using type = volatile to_be_t<T>;
|
||||
};
|
||||
|
||||
template<> struct to_be<void> { using type = void; };
|
||||
template<> struct to_be<bool> { using type = bool; };
|
||||
template<> struct to_be<char> { using type = char; };
|
||||
template<> struct to_be<u8> { using type = u8; };
|
||||
template<> struct to_be<s8> { using type = s8; };
|
||||
|
||||
template<typename T> struct is_le_t : public std::integral_constant<bool, false>
|
||||
{
|
||||
};
|
||||
|
||||
template<typename T> struct is_le_t<le_t<T>> : public std::integral_constant<bool, true>
|
||||
{
|
||||
};
|
||||
|
||||
template<typename T> struct is_le_t<const T> : public std::integral_constant<bool, is_le_t<T>::value>
|
||||
{
|
||||
};
|
||||
|
||||
template<typename T> struct is_le_t<volatile T> : public std::integral_constant<bool, is_le_t<T>::value>
|
||||
{
|
||||
};
|
||||
|
||||
template<typename T> struct to_le
|
||||
{
|
||||
using type = std::conditional_t<std::is_arithmetic<T>::value || std::is_enum<T>::value || std::is_same<T, v128>::value || std::is_same<T, u128>::value, le_t<T>, T>;
|
||||
};
|
||||
|
||||
// le_t<T> if possible, T otherwise
|
||||
template<typename T> using to_le_t = typename to_le<T>::type;
|
||||
|
||||
template<typename T> struct to_le<const T> // move const qualifier
|
||||
{
|
||||
using type = const to_le_t<T>;
|
||||
};
|
||||
|
||||
template<typename T> struct to_le<volatile T> // move volatile qualifier
|
||||
{
|
||||
using type = volatile to_le_t<T>;
|
||||
};
|
||||
|
||||
template<> struct to_le<void> { using type = void; };
|
||||
template<> struct to_le<bool> { using type = bool; };
|
||||
template<> struct to_le<char> { using type = char; };
|
||||
template<> struct to_le<u8> { using type = u8; };
|
||||
template<> struct to_le<s8> { using type = s8; };
|
||||
|
||||
// to_ne_t helper struct
|
||||
template<typename T> struct to_ne
|
||||
template<typename T, typename = void> struct to_ne
|
||||
{
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template<typename T, bool Se> struct to_ne<se_t<T, Se>>
|
||||
{
|
||||
using type = T;
|
||||
using type = typename std::remove_cv<T>::type;
|
||||
};
|
||||
|
||||
template<typename T> struct to_ne<const T, std::enable_if_t<!std::is_array<T>::value>> // move const qualifier
|
||||
{
|
||||
using type = const typename to_ne<T>::type;
|
||||
};
|
||||
|
||||
template<typename T> struct to_ne<volatile T, std::enable_if_t<!std::is_array<T>::value && !std::is_const<T>::value>> // move volatile qualifier
|
||||
{
|
||||
using type = volatile typename to_ne<T>::type;
|
||||
};
|
||||
|
||||
template<typename T> struct to_ne<T[]>
|
||||
{
|
||||
using type = typename to_ne<T>::type[];
|
||||
};
|
||||
|
||||
template<typename T, std::size_t N> struct to_ne<T[N]>
|
||||
{
|
||||
using type = typename to_ne<T>::type[N];
|
||||
};
|
||||
|
||||
// restore native endianness for T: returns T for be_t<T> or le_t<T>, T otherwise
|
||||
template<typename T> using to_ne_t = typename to_ne<T>::type;
|
||||
|
||||
template<typename T> struct to_ne<const T> // move const qualifier
|
||||
{
|
||||
using type = const to_ne_t<T>;
|
||||
};
|
||||
|
||||
template<typename T> struct to_ne<volatile T> // move volatile qualifier
|
||||
{
|
||||
using type = volatile to_ne_t<T>;
|
||||
};
|
||||
|
140
Utilities/BitField.h
Normal file
140
Utilities/BitField.h
Normal file
@ -0,0 +1,140 @@
|
||||
#pragma once
|
||||
|
||||
// BitField access helper class (N bits from I position), intended to be put in union
|
||||
template<typename T, u32 I, u32 N> class bf_t
|
||||
{
|
||||
// Checks
|
||||
static_assert(I < sizeof(T) * 8, "bf_t<> error: I out of bounds");
|
||||
static_assert(N < sizeof(T) * 8, "bf_t<> error: N out of bounds");
|
||||
static_assert(I + N <= sizeof(T) * 8, "bf_t<> error: values out of bounds");
|
||||
|
||||
// Underlying data type
|
||||
using type = typename std::remove_cv<T>::type;
|
||||
|
||||
// Underlying value type (native endianness)
|
||||
using vtype = typename to_ne<type>::type;
|
||||
|
||||
// Mask of size N
|
||||
constexpr static vtype s_mask = (static_cast<vtype>(1) << N) - 1;
|
||||
|
||||
// Underlying data member
|
||||
type m_data;
|
||||
|
||||
// Conversion operator helper (uses SFINAE)
|
||||
template<typename T2, typename = void> struct converter {};
|
||||
|
||||
template<typename T2> struct converter<T2, std::enable_if_t<std::is_unsigned<T2>::value>>
|
||||
{
|
||||
// Load unsigned value
|
||||
static inline T2 convert(const type& data)
|
||||
{
|
||||
return (data >> I) & s_mask;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T2> struct converter<T2, std::enable_if_t<std::is_signed<T2>::value>>
|
||||
{
|
||||
// Load signed value (sign-extended)
|
||||
static inline T2 convert(const type& data)
|
||||
{
|
||||
return data << (sizeof(T) * 8 - I - N) >> (sizeof(T) * 8 - N);
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
// Assignment operator (store bitfield value)
|
||||
bf_t& operator =(vtype value)
|
||||
{
|
||||
m_data = (m_data & ~(s_mask << I)) | (value & s_mask) << I;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Conversion operator (load bitfield value)
|
||||
operator vtype() const
|
||||
{
|
||||
return converter<vtype>::convert(m_data);
|
||||
}
|
||||
|
||||
// Get raw data with mask applied
|
||||
type unshifted() const
|
||||
{
|
||||
return (m_data & (s_mask << I));
|
||||
}
|
||||
|
||||
// Optimized bool conversion
|
||||
explicit operator bool() const
|
||||
{
|
||||
return unshifted() != 0;
|
||||
}
|
||||
|
||||
// Postfix increment operator
|
||||
vtype operator ++(int)
|
||||
{
|
||||
vtype result = *this;
|
||||
*this = result + 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Prefix increment operator
|
||||
bf_t& operator ++()
|
||||
{
|
||||
return *this = *this + 1;
|
||||
}
|
||||
|
||||
// Postfix decrement operator
|
||||
vtype operator --(int)
|
||||
{
|
||||
vtype result = *this;
|
||||
*this = result - 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Prefix decrement operator
|
||||
bf_t& operator --()
|
||||
{
|
||||
return *this = *this - 1;
|
||||
}
|
||||
|
||||
// Addition assignment operator
|
||||
bf_t& operator +=(vtype right)
|
||||
{
|
||||
return *this = *this + right;
|
||||
}
|
||||
|
||||
// Subtraction assignment operator
|
||||
bf_t& operator -=(vtype right)
|
||||
{
|
||||
return *this = *this - right;
|
||||
}
|
||||
|
||||
// Multiplication assignment operator
|
||||
bf_t& operator *=(vtype right)
|
||||
{
|
||||
return *this = *this * right;
|
||||
}
|
||||
|
||||
// Bitwise AND assignment operator
|
||||
bf_t& operator &=(vtype right)
|
||||
{
|
||||
m_data &= (right & s_mask) << I;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Bitwise OR assignment operator
|
||||
bf_t& operator |=(vtype right)
|
||||
{
|
||||
m_data |= (right & s_mask) << I;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Bitwise XOR assignment operator
|
||||
bf_t& operator ^=(vtype right)
|
||||
{
|
||||
m_data ^= (right & s_mask) << I;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, u32 I, u32 N> using bf_be_t = bf_t<be_t<T>, I, N>;
|
||||
|
||||
template<typename T, u32 I, u32 N> using bf_le_t = bf_t<le_t<T>, I, N>;
|
@ -7,8 +7,6 @@
|
||||
|
||||
#define GET_API_ERROR static_cast<u64>(GetLastError())
|
||||
|
||||
static_assert(fs::file::null == intptr_t(INVALID_HANDLE_VALUE) && fs::dir::null == fs::file::null, "Check fs::file::null definition");
|
||||
|
||||
std::unique_ptr<wchar_t[]> to_wchar(const std::string& source)
|
||||
{
|
||||
const auto length = source.size() + 1; // size + null terminator
|
||||
@ -443,7 +441,7 @@ bool fs::file::open(const std::string& filename, u32 mode)
|
||||
return false;
|
||||
}
|
||||
|
||||
m_fd = (intptr_t)CreateFileW(to_wchar(filename).get(), access, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, disp, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
m_fd = (std::intptr_t)CreateFileW(to_wchar(filename).get(), access, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, disp, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
#else
|
||||
int flags = 0;
|
||||
|
||||
@ -598,11 +596,6 @@ u64 fs::file::write(const void* buffer, u64 count) const
|
||||
#endif
|
||||
}
|
||||
|
||||
u64 fs::file::write(const std::string &string) const
|
||||
{
|
||||
return write(string.data(), string.size());
|
||||
}
|
||||
|
||||
u64 fs::file::seek(s64 offset, fsm seek_mode) const
|
||||
{
|
||||
g_tls_error = fse::ok;
|
||||
@ -659,66 +652,34 @@ u64 fs::file::size() const
|
||||
|
||||
fs::dir::~dir()
|
||||
{
|
||||
if (m_dd != null)
|
||||
if (m_path)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
FindClose((HANDLE)m_dd);
|
||||
if (m_dd != -1) FindClose((HANDLE)m_dd);
|
||||
#else
|
||||
::closedir((DIR*)m_dd);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void fs::dir::import(handle_type dd, const std::string& path)
|
||||
{
|
||||
if (m_dd != null)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
FindClose((HANDLE)m_dd);
|
||||
#else
|
||||
::closedir((DIR*)m_dd);
|
||||
#endif
|
||||
}
|
||||
|
||||
g_tls_error = fse::ok;
|
||||
|
||||
m_dd = dd;
|
||||
|
||||
#ifdef _WIN32
|
||||
m_path = to_wchar(path);
|
||||
#else
|
||||
m_path.reset(new char[path.size() + 1]);
|
||||
memcpy(m_path.get(), path.c_str(), path.size() + 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool fs::dir::open(const std::string& dirname)
|
||||
{
|
||||
if (m_dd != null)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
FindClose((HANDLE)m_dd);
|
||||
#else
|
||||
::closedir((DIR*)m_dd);
|
||||
#endif
|
||||
}
|
||||
this->close();
|
||||
|
||||
g_tls_error = fse::ok;
|
||||
|
||||
m_dd = null;
|
||||
|
||||
m_path.reset();
|
||||
|
||||
if (!is_dir(dirname))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
m_path = to_wchar(dirname + "/*");
|
||||
#else
|
||||
m_path.reset(new char[dirname.size() + 1]);
|
||||
memcpy(m_path.get(), dirname.c_str(), dirname.size() + 1);
|
||||
std::memcpy(m_path.get(), dirname.c_str(), dirname.size() + 1);
|
||||
|
||||
#ifdef _WIN32
|
||||
m_dd = -1;
|
||||
#else
|
||||
m_dd = (std::intptr_t)::opendir(m_path.get());
|
||||
#endif
|
||||
|
||||
return true;
|
||||
@ -728,46 +689,26 @@ bool fs::dir::close()
|
||||
{
|
||||
g_tls_error = fse::ok;
|
||||
|
||||
if (m_dd == null)
|
||||
if (!m_path)
|
||||
{
|
||||
if (m_path)
|
||||
{
|
||||
m_path.reset();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
auto dd = m_dd;
|
||||
m_dd = null;
|
||||
|
||||
m_path.reset();
|
||||
|
||||
#ifdef _WIN32
|
||||
return FindClose((HANDLE)dd);
|
||||
CHECK_ASSERTION(m_dd == -1 || FindClose((HANDLE)m_dd));
|
||||
#else
|
||||
return !::closedir((DIR*)dd);
|
||||
CHECK_ASSERTION(!::closedir((DIR*)m_dd));
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fs::dir::get_first(std::string& name, stat_t& info)
|
||||
bool fs::dir::read(std::string& name, stat_t& info)
|
||||
{
|
||||
if (m_dd != null) // close previous handle
|
||||
{
|
||||
#ifdef _WIN32
|
||||
FindClose((HANDLE)m_dd);
|
||||
#else
|
||||
::closedir((DIR*)m_dd);
|
||||
#endif
|
||||
}
|
||||
|
||||
g_tls_error = fse::ok;
|
||||
|
||||
m_dd = null;
|
||||
|
||||
if (!m_path)
|
||||
{
|
||||
return false;
|
||||
@ -776,43 +717,16 @@ bool fs::dir::get_first(std::string& name, stat_t& info)
|
||||
#ifdef _WIN32
|
||||
WIN32_FIND_DATAW found;
|
||||
|
||||
m_dd = (intptr_t)FindFirstFileW(m_path.get(), &found);
|
||||
|
||||
if (m_dd == null)
|
||||
if (m_dd == -1)
|
||||
{
|
||||
return false;
|
||||
m_dd = (std::intptr_t)FindFirstFileW(to_wchar(m_path.get() + "/*"s).get(), &found);
|
||||
|
||||
if (m_dd == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
to_utf8(name, found.cFileName);
|
||||
|
||||
info.is_directory = (found.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
info.is_writable = (found.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0;
|
||||
info.size = ((u64)found.nFileSizeHigh << 32) | (u64)found.nFileSizeLow;
|
||||
info.atime = to_time_t(found.ftLastAccessTime);
|
||||
info.mtime = to_time_t(found.ftLastWriteTime);
|
||||
info.ctime = to_time_t(found.ftCreationTime);
|
||||
|
||||
return true;
|
||||
#else
|
||||
m_dd = (intptr_t)::opendir(m_path.get());
|
||||
|
||||
return get_next(name, info);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool fs::dir::get_next(std::string& name, stat_t& info)
|
||||
{
|
||||
g_tls_error = fse::ok;
|
||||
|
||||
if (m_dd == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
WIN32_FIND_DATAW found;
|
||||
|
||||
if (!FindNextFileW((HANDLE)m_dd, &found))
|
||||
else if (!FindNextFileW((HANDLE)m_dd, &found))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
163
Utilities/File.h
163
Utilities/File.h
@ -26,16 +26,6 @@ enum class fse : u32 // filesystem (file or dir) error
|
||||
invalid_arguments,
|
||||
};
|
||||
|
||||
enum : u32 // obsolete flags
|
||||
{
|
||||
o_read = fom::read,
|
||||
o_write = fom::write,
|
||||
o_append = fom::append,
|
||||
o_create = fom::create,
|
||||
o_trunc = fom::trunc,
|
||||
o_excl = fom::excl,
|
||||
};
|
||||
|
||||
namespace fs
|
||||
{
|
||||
thread_local extern fse g_tls_error;
|
||||
@ -50,95 +40,156 @@ namespace fs
|
||||
s64 ctime;
|
||||
};
|
||||
|
||||
// Get file information
|
||||
bool stat(const std::string& path, stat_t& info);
|
||||
|
||||
// Check whether a file or a directory exists (not recommended, use is_file() or is_dir() instead)
|
||||
bool exists(const std::string& path);
|
||||
|
||||
// Check whether the file exists and is NOT a directory
|
||||
bool is_file(const std::string& file);
|
||||
|
||||
// Check whether the directory exists and is NOT a file
|
||||
bool is_dir(const std::string& dir);
|
||||
|
||||
// Delete empty directory
|
||||
bool remove_dir(const std::string& dir);
|
||||
|
||||
// Create directory
|
||||
bool create_dir(const std::string& dir);
|
||||
|
||||
// Create directories
|
||||
bool create_path(const std::string& path);
|
||||
|
||||
// Rename (move) file or directory
|
||||
bool rename(const std::string& from, const std::string& to);
|
||||
|
||||
// Copy file contents
|
||||
bool copy_file(const std::string& from, const std::string& to, bool overwrite);
|
||||
|
||||
// Delete file
|
||||
bool remove_file(const std::string& file);
|
||||
|
||||
// Change file size (possibly appending zeros)
|
||||
bool truncate_file(const std::string& file, u64 length);
|
||||
|
||||
struct file final
|
||||
class file final
|
||||
{
|
||||
using handle_type = std::intptr_t;
|
||||
|
||||
static const handle_type null = -1;
|
||||
constexpr static handle_type null = -1;
|
||||
|
||||
private:
|
||||
handle_type m_fd = null;
|
||||
|
||||
public:
|
||||
file() = default;
|
||||
|
||||
explicit file(const std::string& filename, u32 mode = fom::read)
|
||||
{
|
||||
open(filename, mode);
|
||||
}
|
||||
|
||||
file(file&& other)
|
||||
: m_fd(other.m_fd)
|
||||
{
|
||||
other.m_fd = null;
|
||||
}
|
||||
|
||||
file& operator =(file&& right)
|
||||
{
|
||||
std::swap(m_fd, right.m_fd);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~file();
|
||||
explicit file(const std::string& filename, u32 mode = fom::read) { open(filename, mode); }
|
||||
|
||||
file(const file&) = delete;
|
||||
file(file&&) = delete; // possibly TODO
|
||||
// Check whether the handle is valid (opened file)
|
||||
bool is_opened() const
|
||||
{
|
||||
return m_fd != null;
|
||||
}
|
||||
|
||||
file& operator =(const file&) = delete;
|
||||
file& operator =(file&&) = delete; // possibly TODO
|
||||
|
||||
operator bool() const { return m_fd != null; }
|
||||
|
||||
void import(handle_type fd) { this->~file(); m_fd = fd; }
|
||||
// Check whether the handle is valid (opened file)
|
||||
explicit operator bool() const
|
||||
{
|
||||
return is_opened();
|
||||
}
|
||||
|
||||
// Open specified file with specified mode
|
||||
bool open(const std::string& filename, u32 mode = fom::read);
|
||||
bool is_opened() const { return m_fd != null; }
|
||||
bool trunc(u64 size) const; // change file size (possibly appending zero bytes)
|
||||
bool stat(stat_t& info) const; // get file info
|
||||
|
||||
// Change file size (possibly appending zero bytes)
|
||||
bool trunc(u64 size) const;
|
||||
|
||||
// Get file information
|
||||
bool stat(stat_t& info) const;
|
||||
|
||||
// Close the file explicitly (destructor automatically closes the file)
|
||||
bool close();
|
||||
|
||||
// Read the data from the file and return the amount of data written in buffer
|
||||
u64 read(void* buffer, u64 count) const;
|
||||
|
||||
// Write the data to the file and return the amount of data actually written
|
||||
u64 write(const void* buffer, u64 count) const;
|
||||
u64 write(const std::string &string) const;
|
||||
|
||||
// Write std::string
|
||||
u64 write(const std::string& string) const { return write(string.data(), string.size()); }
|
||||
|
||||
// Move file pointer
|
||||
u64 seek(s64 offset, fsm seek_mode = fsm::begin) const;
|
||||
|
||||
// Get file size
|
||||
u64 size() const;
|
||||
};
|
||||
|
||||
struct dir final
|
||||
class dir final
|
||||
{
|
||||
#ifdef _WIN32
|
||||
using handle_type = intptr_t;
|
||||
using name_type = std::unique_ptr<wchar_t[]>;
|
||||
|
||||
static const handle_type null = -1;
|
||||
#else
|
||||
using handle_type = intptr_t;
|
||||
using name_type = std::unique_ptr<char[]>;
|
||||
|
||||
static const handle_type null = 0;
|
||||
#endif
|
||||
|
||||
private:
|
||||
handle_type m_dd = null;
|
||||
name_type m_path;
|
||||
std::unique_ptr<char[]> m_path;
|
||||
std::intptr_t m_dd; // handle (aux)
|
||||
|
||||
public:
|
||||
dir() = default;
|
||||
|
||||
explicit dir(const std::string& dirname)
|
||||
{
|
||||
open(dirname);
|
||||
}
|
||||
|
||||
dir(dir&& other)
|
||||
: m_dd(other.m_dd)
|
||||
, m_path(std::move(other.m_path))
|
||||
{
|
||||
}
|
||||
|
||||
dir& operator =(dir&& right)
|
||||
{
|
||||
m_dd = right.m_dd;
|
||||
m_path = std::move(right.m_path);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~dir();
|
||||
explicit dir(const std::string& dirname) { open(dirname); }
|
||||
|
||||
dir(const dir&) = delete;
|
||||
dir(dir&&) = delete; // possibly TODO
|
||||
// Check whether the handle is valid (opened directory)
|
||||
bool is_opened() const
|
||||
{
|
||||
return m_path.operator bool();
|
||||
}
|
||||
|
||||
dir& operator =(const dir&) = delete;
|
||||
dir& operator =(dir&&) = delete; // possibly TODO
|
||||
|
||||
operator bool() const { return m_path.operator bool(); }
|
||||
|
||||
void import(handle_type dd, const std::string& path);
|
||||
// Check whether the handle is valid (opened directory)
|
||||
explicit operator bool() const
|
||||
{
|
||||
return is_opened();
|
||||
}
|
||||
|
||||
// Open specified directory
|
||||
bool open(const std::string& dirname);
|
||||
bool is_opened() const { return *this; }
|
||||
|
||||
// Close the directory explicitly (destructor automatically closes the directory)
|
||||
bool close();
|
||||
|
||||
bool get_first(std::string& name, stat_t& info);
|
||||
//bool get_first(std::string& name);
|
||||
bool get_next(std::string& name, stat_t& info);
|
||||
//bool get_next(std::string& name);
|
||||
// Get next directory entry (UTF-8 name and file stat)
|
||||
bool read(std::string& name, stat_t& info);
|
||||
};
|
||||
}
|
||||
|
176
Utilities/GNU.h
176
Utilities/GNU.h
@ -45,16 +45,16 @@
|
||||
#define _byteswap_uint64(x) __builtin_bswap64(x)
|
||||
#define INFINITE 0xFFFFFFFF
|
||||
|
||||
inline uint64_t __umulh(uint64_t a, uint64_t b)
|
||||
inline std::uint64_t __umulh(std::uint64_t a, std::uint64_t b)
|
||||
{
|
||||
uint64_t result;
|
||||
std::uint64_t result;
|
||||
__asm__("mulq %[b]" : "=d" (result) : [a] "a" (a), [b] "rm" (b));
|
||||
return result;
|
||||
}
|
||||
|
||||
inline int64_t __mulh(int64_t a, int64_t b)
|
||||
inline std::int64_t __mulh(std::int64_t a, std::int64_t b)
|
||||
{
|
||||
int64_t result;
|
||||
std::int64_t result;
|
||||
__asm__("imulq %[b]" : "=d" (result) : [a] "a" (a), [b] "rm" (b));
|
||||
return result;
|
||||
}
|
||||
@ -81,202 +81,186 @@ int clock_gettime(clockid_t clk_id, struct timespec *tp);
|
||||
#endif /* __GNUG__ */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
// Unsigned 128-bit integer implementation
|
||||
struct alignas(16) uint128_t
|
||||
struct alignas(16) u128
|
||||
{
|
||||
uint64_t lo, hi;
|
||||
std::uint64_t lo, hi;
|
||||
|
||||
uint128_t() = default;
|
||||
u128() = default;
|
||||
|
||||
uint128_t(uint64_t l)
|
||||
u128(const u128&) = default;
|
||||
|
||||
u128(std::uint64_t l)
|
||||
: lo(l)
|
||||
, hi(0)
|
||||
{
|
||||
}
|
||||
|
||||
[[deprecated("Not implemented")]] inline uint128_t operator +(const uint128_t& r) const
|
||||
u128 operator +(const u128& 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;
|
||||
u128 value;
|
||||
_addcarry_u64(_addcarry_u64(0, r.lo, lo, &value.lo), r.hi, hi, &value.hi);
|
||||
return value;
|
||||
}
|
||||
|
||||
[[deprecated("Not implemented")]] inline uint128_t operator -(const uint128_t& r) const
|
||||
friend u128 operator +(const u128& l, std::uint64_t r)
|
||||
{
|
||||
return{};
|
||||
}
|
||||
|
||||
inline uint128_t operator -(uint64_t r) const
|
||||
{
|
||||
uint128_t value;
|
||||
value.lo = lo - r;
|
||||
value.hi = lo < r ? hi - 1 : hi;
|
||||
u128 value;
|
||||
_addcarry_u64(_addcarry_u64(0, r, l.lo, &value.lo), l.hi, 0, &value.hi);
|
||||
return value;
|
||||
}
|
||||
|
||||
inline uint128_t operator +() const
|
||||
friend u128 operator +(std::uint64_t l, const u128& r)
|
||||
{
|
||||
u128 value;
|
||||
_addcarry_u64(_addcarry_u64(0, r.lo, l, &value.lo), 0, r.hi, &value.hi);
|
||||
return value;
|
||||
}
|
||||
|
||||
u128 operator -(const u128& r) const
|
||||
{
|
||||
u128 value;
|
||||
_subborrow_u64(_subborrow_u64(0, r.lo, lo, &value.lo), r.hi, hi, &value.hi);
|
||||
return value;
|
||||
}
|
||||
|
||||
friend u128 operator -(const u128& l, std::uint64_t r)
|
||||
{
|
||||
u128 value;
|
||||
_subborrow_u64(_subborrow_u64(0, r, l.lo, &value.lo), 0, l.hi, &value.hi);
|
||||
return value;
|
||||
}
|
||||
|
||||
friend u128 operator -(std::uint64_t l, const u128& r)
|
||||
{
|
||||
u128 value;
|
||||
_subborrow_u64(_subborrow_u64(0, r.lo, l, &value.lo), r.hi, 0, &value.hi);
|
||||
return value;
|
||||
}
|
||||
|
||||
u128 operator +() const
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline uint128_t operator -() const
|
||||
u128 operator -() const
|
||||
{
|
||||
uint128_t value;
|
||||
value.lo = ~lo + 1;
|
||||
value.hi = lo ? ~hi : ~hi + 1;
|
||||
u128 value;
|
||||
_subborrow_u64(_subborrow_u64(0, lo, 0, &value.lo), hi, 0, &value.hi);
|
||||
return value;
|
||||
}
|
||||
|
||||
inline uint128_t& operator ++()
|
||||
u128& operator ++()
|
||||
{
|
||||
if (!++lo) ++hi;
|
||||
_addcarry_u64(_addcarry_u64(0, 1, lo, &lo), 0, hi, &hi);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline uint128_t operator ++(int)
|
||||
u128 operator ++(int)
|
||||
{
|
||||
uint128_t value = *this;
|
||||
if (!++lo) ++hi;
|
||||
u128 value = *this;
|
||||
_addcarry_u64(_addcarry_u64(0, 1, lo, &lo), 0, hi, &hi);
|
||||
return value;
|
||||
}
|
||||
|
||||
inline uint128_t& operator --()
|
||||
u128& operator --()
|
||||
{
|
||||
if (!lo--) hi--;
|
||||
_subborrow_u64(_subborrow_u64(0, 1, lo, &lo), 0, hi, &hi);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline uint128_t operator --(int)
|
||||
u128 operator --(int)
|
||||
{
|
||||
uint128_t value = *this;
|
||||
if (!lo--) hi--;
|
||||
u128 value = *this;
|
||||
_subborrow_u64(_subborrow_u64(0, 1, lo, &lo), 0, hi, &hi);
|
||||
return value;
|
||||
}
|
||||
|
||||
inline uint128_t operator ~() const
|
||||
u128 operator ~() const
|
||||
{
|
||||
uint128_t value;
|
||||
u128 value;
|
||||
value.lo = ~lo;
|
||||
value.hi = ~hi;
|
||||
return value;
|
||||
}
|
||||
|
||||
inline uint128_t operator &(const uint128_t& r) const
|
||||
u128 operator &(const u128& r) const
|
||||
{
|
||||
uint128_t value;
|
||||
u128 value;
|
||||
value.lo = lo & r.lo;
|
||||
value.hi = hi & r.hi;
|
||||
return value;
|
||||
}
|
||||
|
||||
inline uint128_t operator |(const uint128_t& r) const
|
||||
u128 operator |(const u128& r) const
|
||||
{
|
||||
uint128_t value;
|
||||
u128 value;
|
||||
value.lo = lo | r.lo;
|
||||
value.hi = hi | r.hi;
|
||||
return value;
|
||||
}
|
||||
|
||||
inline uint128_t operator ^(const uint128_t& r) const
|
||||
u128 operator ^(const u128& r) const
|
||||
{
|
||||
uint128_t value;
|
||||
u128 value;
|
||||
value.lo = lo ^ r.lo;
|
||||
value.hi = hi ^ r.hi;
|
||||
return value;
|
||||
}
|
||||
|
||||
[[deprecated("Not implemented")]] inline uint128_t& operator +=(const uint128_t& r)
|
||||
u128& operator +=(const u128& r)
|
||||
{
|
||||
_addcarry_u64(_addcarry_u64(0, r.lo, lo, &lo), r.hi, hi, &hi);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline uint128_t& operator +=(uint64_t r)
|
||||
u128& operator +=(uint64_t r)
|
||||
{
|
||||
hi = (lo += r) < r ? hi + 1 : hi;
|
||||
_addcarry_u64(_addcarry_u64(0, r, lo, &lo), 0, hi, &hi);
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[deprecated("Not implemented")]] inline uint128_t& operator -=(const uint128_t& r)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline uint128_t& operator &=(const uint128_t& r)
|
||||
u128& operator &=(const u128& r)
|
||||
{
|
||||
lo &= r.lo;
|
||||
hi &= r.hi;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline uint128_t& operator |=(const uint128_t& r)
|
||||
u128& operator |=(const u128& r)
|
||||
{
|
||||
lo |= r.lo;
|
||||
hi |= r.hi;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline uint128_t& operator ^=(const uint128_t& r)
|
||||
u128& operator ^=(const u128& r)
|
||||
{
|
||||
lo ^= r.lo;
|
||||
hi ^= r.hi;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
using __uint128_t = uint128_t;
|
||||
#endif
|
||||
|
||||
inline uint32_t cntlz32(uint32_t arg)
|
||||
inline std::uint32_t cntlz32(std::uint32_t arg)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
unsigned long res;
|
||||
if (!_BitScanReverse(&res, arg))
|
||||
{
|
||||
return 32;
|
||||
}
|
||||
else
|
||||
{
|
||||
return res ^ 31;
|
||||
}
|
||||
return _BitScanReverse(&res, arg) ? res ^ 31 : 32;
|
||||
#else
|
||||
if (arg)
|
||||
{
|
||||
return __builtin_clzll((uint64_t)arg) - 32;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 32;
|
||||
}
|
||||
return arg ? __builtin_clzll(arg) - 32 : 32;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline uint64_t cntlz64(uint64_t arg)
|
||||
inline std::uint64_t cntlz64(std::uint64_t arg)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
unsigned long res;
|
||||
if (!_BitScanReverse64(&res, arg))
|
||||
{
|
||||
return 64;
|
||||
}
|
||||
else
|
||||
{
|
||||
return res ^ 63;
|
||||
}
|
||||
return _BitScanReverse64(&res, arg) ? res ^ 63 : 64;
|
||||
#else
|
||||
if (arg)
|
||||
{
|
||||
return __builtin_clzll(arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 64;
|
||||
}
|
||||
return arg ? __builtin_clzll(arg) : 64;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -79,7 +79,6 @@ namespace Log
|
||||
LogChannel();
|
||||
LogChannel(const std::string& name);
|
||||
LogChannel(LogChannel& other) = delete;
|
||||
LogChannel& operator = (LogChannel& other) = delete;
|
||||
void log(const LogMessage &msg);
|
||||
void addListener(std::shared_ptr<LogListener> listener);
|
||||
void removeListener(std::shared_ptr<LogListener> listener);
|
||||
|
@ -27,19 +27,19 @@ public:
|
||||
~sleep_queue_entry_t();
|
||||
|
||||
// add thread to the sleep queue
|
||||
inline void enter()
|
||||
void enter()
|
||||
{
|
||||
add_entry();
|
||||
}
|
||||
|
||||
// remove thread from the sleep queue
|
||||
inline void leave()
|
||||
void leave()
|
||||
{
|
||||
remove_entry();
|
||||
}
|
||||
|
||||
// check whether the thread exists in the sleep queue
|
||||
inline explicit operator bool() const
|
||||
explicit operator bool() const
|
||||
{
|
||||
return find();
|
||||
}
|
||||
|
@ -15,9 +15,13 @@ std::string v128::to_xyzw() const
|
||||
return fmt::format("x: %g y: %g z: %g w: %g", _f[3], _f[2], _f[1], _f[0]);
|
||||
}
|
||||
|
||||
std::string fmt::to_hex(u64 value, size_t count)
|
||||
std::string fmt::to_hex(u64 value, u64 count)
|
||||
{
|
||||
assert(count - 1 < 16);
|
||||
if (count - 1 >= 16)
|
||||
{
|
||||
throw EXCEPTION("Invalid count: 0x%llx", count);
|
||||
}
|
||||
|
||||
count = std::max<u64>(count, 16 - cntlz64(value) / 4);
|
||||
|
||||
char res[16] = {};
|
||||
|
@ -141,7 +141,7 @@ namespace fmt
|
||||
return src;
|
||||
}
|
||||
|
||||
std::string to_hex(u64 value, size_t count = 1);
|
||||
std::string to_hex(u64 value, u64 count = 1);
|
||||
std::string to_udec(u64 value);
|
||||
std::string to_sdec(s64 value);
|
||||
|
||||
|
@ -901,7 +901,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(vm::priv_ptr(addr), XMMREG(context, reg - X64R_XMM0), 16);
|
||||
std::memcpy(vm::base_priv(addr), XMMREG(context, reg - X64R_XMM0), 16);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -911,7 +911,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(vm::priv_ptr(addr), ®_value, d_size);
|
||||
std::memcpy(vm::base_priv(addr), ®_value, d_size);
|
||||
break;
|
||||
}
|
||||
case X64OP_MOVS:
|
||||
@ -922,7 +922,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (vm::get_ptr(addr) != (void*)RDI(context))
|
||||
if (vm::base(addr) != (void*)RDI(context))
|
||||
{
|
||||
LOG_ERROR(MEMORY, "X64OP_MOVS: rdi=0x%llx, rsi=0x%llx, addr=0x%x", (u64)RDI(context), (u64)RSI(context), addr);
|
||||
return false;
|
||||
@ -935,8 +935,8 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
|
||||
u64 value;
|
||||
|
||||
// copy data
|
||||
memcpy(&value, (void*)RSI(context), d_size);
|
||||
memcpy(vm::priv_ptr(a_addr), &value, d_size);
|
||||
std::memcpy(&value, (void*)RSI(context), d_size);
|
||||
std::memcpy(vm::base_priv(a_addr), &value, d_size);
|
||||
|
||||
// shift pointers
|
||||
if (EFLAGS(context) & 0x400 /* direction flag */)
|
||||
@ -977,7 +977,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (vm::get_ptr(addr) != (void*)RDI(context))
|
||||
if (vm::base(addr) != (void*)RDI(context))
|
||||
{
|
||||
LOG_ERROR(MEMORY, "X64OP_STOS: rdi=0x%llx, addr=0x%x", (u64)RDI(context), addr);
|
||||
return false;
|
||||
@ -994,7 +994,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
|
||||
while (a_addr >> 12 == addr >> 12)
|
||||
{
|
||||
// fill data with value
|
||||
memcpy(vm::priv_ptr(a_addr), &value, d_size);
|
||||
std::memcpy(vm::base_priv(a_addr), &value, d_size);
|
||||
|
||||
// shift pointers
|
||||
if (EFLAGS(context) & 0x400 /* direction flag */)
|
||||
@ -1035,10 +1035,10 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
|
||||
|
||||
switch (d_size)
|
||||
{
|
||||
case 1: reg_value = vm::priv_ref<atomic_t<u8>>(addr).exchange((u8)reg_value); break;
|
||||
case 2: reg_value = vm::priv_ref<atomic_t<u16>>(addr).exchange((u16)reg_value); break;
|
||||
case 4: reg_value = vm::priv_ref<atomic_t<u32>>(addr).exchange((u32)reg_value); break;
|
||||
case 8: reg_value = vm::priv_ref<atomic_t<u64>>(addr).exchange((u64)reg_value); break;
|
||||
case 1: reg_value = sync_lock_test_and_set((u8*)vm::base_priv(addr), (u8)reg_value); break;
|
||||
case 2: reg_value = sync_lock_test_and_set((u16*)vm::base_priv(addr), (u16)reg_value); break;
|
||||
case 4: reg_value = sync_lock_test_and_set((u32*)vm::base_priv(addr), (u32)reg_value); break;
|
||||
case 8: reg_value = sync_lock_test_and_set((u64*)vm::base_priv(addr), (u64)reg_value); break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
@ -1058,10 +1058,10 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
|
||||
|
||||
switch (d_size)
|
||||
{
|
||||
case 1: old_value = vm::priv_ref<atomic_t<u8>>(addr).compare_and_swap((u8)cmp_value, (u8)reg_value); break;
|
||||
case 2: old_value = vm::priv_ref<atomic_t<u16>>(addr).compare_and_swap((u16)cmp_value, (u16)reg_value); break;
|
||||
case 4: old_value = vm::priv_ref<atomic_t<u32>>(addr).compare_and_swap((u32)cmp_value, (u32)reg_value); break;
|
||||
case 8: old_value = vm::priv_ref<atomic_t<u64>>(addr).compare_and_swap((u64)cmp_value, (u64)reg_value); break;
|
||||
case 1: old_value = sync_val_compare_and_swap((u8*)vm::base_priv(addr), (u8)cmp_value, (u8)reg_value); break;
|
||||
case 2: old_value = sync_val_compare_and_swap((u16*)vm::base_priv(addr), (u16)cmp_value, (u16)reg_value); break;
|
||||
case 4: old_value = sync_val_compare_and_swap((u32*)vm::base_priv(addr), (u32)cmp_value, (u32)reg_value); break;
|
||||
case 8: old_value = sync_val_compare_and_swap((u64*)vm::base_priv(addr), (u64)cmp_value, (u64)reg_value); break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
@ -1081,10 +1081,10 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
|
||||
|
||||
switch (d_size)
|
||||
{
|
||||
case 1: value = vm::priv_ref<atomic_t<u8>>(addr) &= (u8)value; break;
|
||||
case 2: value = vm::priv_ref<atomic_t<u16>>(addr) &= (u16)value; break;
|
||||
case 4: value = vm::priv_ref<atomic_t<u32>>(addr) &= (u32)value; break;
|
||||
case 8: value = vm::priv_ref<atomic_t<u64>>(addr) &= value; break;
|
||||
case 1: value &= sync_fetch_and_and((u8*)vm::base_priv(addr), (u8)value); break;
|
||||
case 2: value &= sync_fetch_and_and((u16*)vm::base_priv(addr), (u16)value); break;
|
||||
case 4: value &= sync_fetch_and_and((u32*)vm::base_priv(addr), (u32)value); break;
|
||||
case 8: value &= sync_fetch_and_and((u64*)vm::base_priv(addr), (u64)value); break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
@ -1114,7 +1114,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
|
||||
|
||||
void _se_translator(unsigned int u, EXCEPTION_POINTERS* pExp)
|
||||
{
|
||||
const u64 addr64 = (u64)pExp->ExceptionRecord->ExceptionInformation[1] - (u64)vm::g_base_addr;
|
||||
const u64 addr64 = (u64)pExp->ExceptionRecord->ExceptionInformation[1] - (u64)vm::base(0);
|
||||
const bool is_writing = pExp->ExceptionRecord->ExceptionInformation[0] != 0;
|
||||
|
||||
if (u == EXCEPTION_ACCESS_VIOLATION && (u32)addr64 == addr64)
|
||||
@ -1122,12 +1122,14 @@ 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
|
||||
__debugbreak(); // if it reached there, there should probably be a possibility to check the callstack
|
||||
|
||||
throw EXCEPTION("Fatal error occured %s location %p at %p", is_writing ? "writing" : "reading", pExp->ExceptionRecord->ExceptionInformation[1], pExp->ExceptionRecord->ExceptionAddress);
|
||||
}
|
||||
|
||||
const PVOID exception_handler = (atexit([]{ RemoveVectoredExceptionHandler(exception_handler); }), AddVectoredExceptionHandler(1, [](PEXCEPTION_POINTERS pExp) -> LONG
|
||||
{
|
||||
const u64 addr64 = (u64)pExp->ExceptionRecord->ExceptionInformation[1] - (u64)vm::g_base_addr;
|
||||
const u64 addr64 = (u64)pExp->ExceptionRecord->ExceptionInformation[1] - (u64)vm::base(0);
|
||||
const bool is_writing = pExp->ExceptionRecord->ExceptionInformation[0] != 0;
|
||||
|
||||
if (pExp->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION &&
|
||||
@ -1154,7 +1156,7 @@ const auto exception_filter = SetUnhandledExceptionFilter([](PEXCEPTION_POINTERS
|
||||
|
||||
void signal_handler(int sig, siginfo_t* info, void* uct)
|
||||
{
|
||||
const u64 addr64 = (u64)info->si_addr - (u64)vm::g_base_addr;
|
||||
const u64 addr64 = (u64)info->si_addr - (u64)vm::base(0);
|
||||
|
||||
#ifdef __APPLE__
|
||||
const bool is_writing = ((ucontext_t*)uct)->uc_mcontext->__es.__err & 0x2;
|
||||
@ -1203,14 +1205,14 @@ std::string thread_ctrl_t::get_name() const
|
||||
|
||||
named_thread_t::named_thread_t(std::function<std::string()> name, std::function<void()> func)
|
||||
{
|
||||
start(std::move(name), func);
|
||||
start(std::move(name), std::move(func));
|
||||
}
|
||||
|
||||
named_thread_t::~named_thread_t()
|
||||
{
|
||||
if (m_thread)
|
||||
{
|
||||
std::printf("Fatal: thread '%s' is neither joined nor detached\n", this->get_name().c_str());
|
||||
std::printf("Fatal: thread neither joined nor detached\n");
|
||||
std::terminate();
|
||||
}
|
||||
}
|
||||
|
@ -2,20 +2,20 @@
|
||||
|
||||
const class thread_ctrl_t* get_current_thread_ctrl();
|
||||
|
||||
// named thread control class
|
||||
// Named thread control class
|
||||
class thread_ctrl_t final
|
||||
{
|
||||
friend class named_thread_t;
|
||||
|
||||
template<typename T> friend void current_thread_register_atexit(T);
|
||||
|
||||
// thread handler
|
||||
// Thread handler
|
||||
std::thread m_thread;
|
||||
|
||||
// name getter
|
||||
// Name getter
|
||||
const std::function<std::string()> m_name;
|
||||
|
||||
// functions executed at thread exit (temporarily)
|
||||
// Functions executed at thread exit (temporarily)
|
||||
std::vector<std::function<void()>> m_atexit;
|
||||
|
||||
public:
|
||||
@ -24,11 +24,13 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
// get thread name
|
||||
thread_ctrl_t(const thread_ctrl_t&) = delete;
|
||||
|
||||
// Get thread name
|
||||
std::string get_name() const;
|
||||
};
|
||||
|
||||
// register function at thread exit (temporarily)
|
||||
// Register function at thread exit (temporarily)
|
||||
template<typename T> void current_thread_register_atexit(T func)
|
||||
{
|
||||
extern thread_local thread_ctrl_t* g_tls_this_thread;
|
||||
@ -38,73 +40,69 @@ template<typename T> void current_thread_register_atexit(T func)
|
||||
|
||||
class named_thread_t
|
||||
{
|
||||
// pointer to managed resource (shared with actual thread)
|
||||
// Pointer to managed resource (shared with actual thread)
|
||||
std::shared_ptr<thread_ctrl_t> m_thread;
|
||||
|
||||
public:
|
||||
// thread mutex for external use
|
||||
// Thread mutex for external use
|
||||
std::mutex mutex;
|
||||
|
||||
// thread condition variable for external use
|
||||
// Thread condition variable for external use
|
||||
std::condition_variable cv;
|
||||
|
||||
public:
|
||||
// initialize in empty state
|
||||
// Initialize in empty state
|
||||
named_thread_t() = default;
|
||||
|
||||
// create named thread
|
||||
// Create named thread
|
||||
named_thread_t(std::function<std::string()> name, std::function<void()> func);
|
||||
|
||||
// destructor, will terminate if thread is neither joined nor detached
|
||||
virtual ~named_thread_t();
|
||||
|
||||
// Deleted copy/move constructors + copy/move operators
|
||||
named_thread_t(const named_thread_t&) = delete;
|
||||
|
||||
named_thread_t& operator =(const named_thread_t&) = delete;
|
||||
// Destructor, calls std::terminate if the thread is neither joined nor detached
|
||||
virtual ~named_thread_t();
|
||||
|
||||
public:
|
||||
// get thread name
|
||||
// Get thread name
|
||||
std::string get_name() const;
|
||||
|
||||
// create named thread (current state must be empty)
|
||||
// Create named thread (current state must be empty)
|
||||
void start(std::function<std::string()> name, std::function<void()> func);
|
||||
|
||||
// detach thread -> empty state
|
||||
// Detach thread -> empty state
|
||||
void detach();
|
||||
|
||||
// join thread -> empty state
|
||||
// Join thread -> empty state
|
||||
void join();
|
||||
|
||||
// check if not empty
|
||||
// Check whether the thread is not in "empty state"
|
||||
bool joinable() const { return m_thread.operator bool(); }
|
||||
|
||||
// check whether it is the current running thread
|
||||
// Check whether it is the currently running thread
|
||||
bool is_current() const;
|
||||
|
||||
// get internal thread pointer
|
||||
// Get internal thread pointer
|
||||
const thread_ctrl_t* get_thread_ctrl() const { return m_thread.get(); }
|
||||
};
|
||||
|
||||
class autojoin_thread_t final : private named_thread_t
|
||||
// Wrapper for named_thread_t, joins automatically in the destructor
|
||||
class autojoin_thread_t final
|
||||
{
|
||||
public:
|
||||
using named_thread_t::mutex;
|
||||
using named_thread_t::cv;
|
||||
named_thread_t m_thread;
|
||||
|
||||
public:
|
||||
autojoin_thread_t() = delete;
|
||||
|
||||
autojoin_thread_t(std::function<std::string()> name, std::function<void()> func)
|
||||
: m_thread(std::move(name), std::move(func))
|
||||
{
|
||||
start(std::move(name), std::move(func));
|
||||
}
|
||||
|
||||
virtual ~autojoin_thread_t() override
|
||||
{
|
||||
join();
|
||||
}
|
||||
autojoin_thread_t(const autojoin_thread_t&) = delete;
|
||||
|
||||
using named_thread_t::is_current;
|
||||
~autojoin_thread_t() noexcept(false) // Allow exceptions
|
||||
{
|
||||
m_thread.join();
|
||||
}
|
||||
};
|
||||
|
||||
extern const std::function<bool()> SQUEUE_ALWAYS_EXIT;
|
||||
|
@ -38,4 +38,4 @@ namespace memory_helper
|
||||
munmap(pointer, size);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -61,6 +61,8 @@ static bool CheckHeader(const fs::file& pkg_f, PKGHeader& header)
|
||||
// PKG Decryption
|
||||
bool UnpackPKG(const fs::file& pkg_f, const std::string& dir, volatile f64& progress)
|
||||
{
|
||||
const std::size_t BUF_SIZE = 8192 * 1024; // 8 MB
|
||||
|
||||
// Save current file offset (probably zero)
|
||||
const u64 start_offset = pkg_f.seek(0, fsm::cur);
|
||||
|
||||
@ -108,13 +110,9 @@ bool UnpackPKG(const fs::file& pkg_f, const std::string& dir, volatile f64& prog
|
||||
// Initialize "debug key" for current position
|
||||
input[7] = offset / 16 + i;
|
||||
|
||||
union
|
||||
{
|
||||
u8 _key[0x14];
|
||||
u128 key;
|
||||
};
|
||||
u128 key;
|
||||
|
||||
sha1(reinterpret_cast<u8*>(input), sizeof(input), _key);
|
||||
sha1(reinterpret_cast<const u8*>(input), sizeof(input), reinterpret_cast<u8*>(&key));
|
||||
|
||||
buf[i] ^= key;
|
||||
}
|
||||
@ -133,13 +131,9 @@ bool UnpackPKG(const fs::file& pkg_f, const std::string& dir, volatile f64& prog
|
||||
// Increment "release key" for every block
|
||||
for (u64 i = 0; i < blocks; i++, input++)
|
||||
{
|
||||
union
|
||||
{
|
||||
u8 _key[16];
|
||||
u128 key;
|
||||
};
|
||||
u128 key;
|
||||
|
||||
aes_crypt_ecb(&ctx, AES_ENCRYPT, reinterpret_cast<u8*>(&input), _key);
|
||||
aes_crypt_ecb(&ctx, AES_ENCRYPT, reinterpret_cast<const u8*>(&input), reinterpret_cast<u8*>(&key));
|
||||
|
||||
buf[i] ^= key;
|
||||
}
|
||||
|
@ -3,7 +3,6 @@
|
||||
// Constants
|
||||
enum
|
||||
{
|
||||
BUF_SIZE = 8192 * 1024, // 8 MB
|
||||
PKG_HEADER_SIZE = 0xC0, //sizeof(pkg_header) + sizeof(pkg_unk_checksum)
|
||||
PKG_HEADER_SIZE2 = 0x280,
|
||||
};
|
||||
@ -58,4 +57,4 @@ struct PKGEntry
|
||||
be_t<u32> pad; // Padding (zeros)
|
||||
};
|
||||
|
||||
bool UnpackPKG(const struct fs::file& pkg_f, const std::string& dir, volatile f64& progress);
|
||||
bool UnpackPKG(const class fs::file& pkg_f, const std::string& dir, volatile f64& progress);
|
||||
|
@ -1963,7 +1963,7 @@ void ARMv7_instrs::LDM(ARMv7Context& context, const ARMv7Code code, const ARMv7_
|
||||
|
||||
if (ConditionPassed(context, cond))
|
||||
{
|
||||
auto memory = vm::ptr<u32>::make(context.read_gpr(n));
|
||||
vm::ptr<u32> memory{ context.read_gpr(n), vm::addr };
|
||||
|
||||
for (u32 i = 0; i < 16; i++)
|
||||
{
|
||||
@ -3540,7 +3540,7 @@ void ARMv7_instrs::PUSH(ARMv7Context& context, const ARMv7Code code, const ARMv7
|
||||
|
||||
if (ConditionPassed(context, cond))
|
||||
{
|
||||
auto memory = vm::ptr<u32>::make(context.SP);
|
||||
vm::ptr<u32> memory{ context.SP, vm::addr };
|
||||
|
||||
for (u32 i = 15; ~i; i--)
|
||||
{
|
||||
|
@ -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
|
||||
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
|
||||
std::memcpy(vm::base(addr), vm::base(Emu.GetTLSAddr()), Emu.GetTLSFilesz()); // initialize from TLS image
|
||||
std::memset(vm::base(addr + Emu.GetTLSFilesz()), 0, Emu.GetTLSMemsz() - Emu.GetTLSFilesz()); // fill the rest with zeros
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
@ -290,7 +290,7 @@ cpu_thread& armv7_thread::args(std::initializer_list<std::string> values)
|
||||
}
|
||||
|
||||
argv = vm::alloc(argv_size, vm::main); // allocate arg list
|
||||
memcpy(vm::get_ptr(argv), argv_data.data(), argv_size); // copy arg list
|
||||
std::memcpy(vm::base(argv), argv_data.data(), argv_size); // copy arg list
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ s32 sceKernelStartThread(s32 threadId, u32 argSize, vm::cptr<void> pArgBlock)
|
||||
|
||||
// push arg block onto the stack
|
||||
const u32 pos = (thread->SP -= argSize);
|
||||
memcpy(vm::get_ptr<void>(pos), pArgBlock.get_ptr(), argSize);
|
||||
std::memcpy(vm::base(pos), pArgBlock.get_ptr(), argSize);
|
||||
|
||||
// set SceKernelThreadEntry function arguments
|
||||
thread->GPR[0] = argSize;
|
||||
|
@ -128,7 +128,7 @@ std::string armv7_fmt(ARMv7Context& context, vm::cptr<char> fmt, u32 g_count, u3
|
||||
case 's':
|
||||
{
|
||||
// string
|
||||
auto string = vm::cptr<char>::make(context.get_next_gpr_arg(g_count, f_count, v_count));
|
||||
const vm::cptr<char> string{ context.get_next_gpr_arg(g_count, f_count, v_count), vm::addr };
|
||||
|
||||
if (plus_sign || minus_sign || space_sign || number_sign || zero_padding || width || prec) break;
|
||||
|
||||
|
@ -35,7 +35,7 @@ public:
|
||||
}
|
||||
|
||||
// check if UID is potentially valid (will return true even if the object doesn't exist)
|
||||
inline static bool check(s32 uid)
|
||||
static inline bool check(s32 uid)
|
||||
{
|
||||
const psv_uid_t id = psv_uid_t::make(uid);
|
||||
|
||||
@ -44,7 +44,7 @@ public:
|
||||
}
|
||||
|
||||
// share object with UID specified
|
||||
inline std::shared_ptr<T> get(s32 uid)
|
||||
std::shared_ptr<T> get(s32 uid)
|
||||
{
|
||||
if (!check(uid))
|
||||
{
|
||||
@ -56,7 +56,7 @@ public:
|
||||
return m_data[psv_uid_t::make(uid).number];
|
||||
}
|
||||
|
||||
inline std::shared_ptr<T> operator [](s32 uid)
|
||||
std::shared_ptr<T> operator [](s32 uid)
|
||||
{
|
||||
return this->get(uid);
|
||||
}
|
||||
|
@ -8,6 +8,8 @@
|
||||
#include "CPUDecoder.h"
|
||||
#include "CPUThread.h"
|
||||
|
||||
thread_local CPUThread* g_tls_current_cpu_thread = nullptr;
|
||||
|
||||
CPUThread::CPUThread(CPUThreadType type, const std::string& name, std::function<std::string()> thread_name)
|
||||
: m_id(idm::get_last_id())
|
||||
, m_type(type)
|
||||
@ -15,6 +17,8 @@ CPUThread::CPUThread(CPUThreadType type, const std::string& name, std::function<
|
||||
{
|
||||
start(std::move(thread_name), [this]
|
||||
{
|
||||
g_tls_current_cpu_thread = this;
|
||||
|
||||
Emu.SendDbgCommand(DID_CREATE_THREAD, this);
|
||||
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
@ -197,13 +201,13 @@ void CPUThread::sleep()
|
||||
|
||||
void CPUThread::awake()
|
||||
{
|
||||
// must be called after the balanced Sleep() call
|
||||
// must be called after the balanced sleep() call
|
||||
|
||||
if (m_state.atomic_op([](u64& state) -> bool
|
||||
{
|
||||
if (state < CPU_STATE_MAX)
|
||||
{
|
||||
throw EXCEPTION("Sleep()/Awake() inconsistency");
|
||||
throw EXCEPTION("sleep()/awake() inconsistency");
|
||||
}
|
||||
|
||||
if ((state -= CPU_STATE_MAX) < CPU_STATE_MAX)
|
||||
|
@ -165,6 +165,13 @@ public:
|
||||
virtual bool WriteRegString(const std::string& reg, std::string value) = 0;
|
||||
};
|
||||
|
||||
inline CPUThread* get_current_cpu_thread()
|
||||
{
|
||||
extern thread_local CPUThread* g_tls_current_cpu_thread;
|
||||
|
||||
return g_tls_current_cpu_thread;
|
||||
}
|
||||
|
||||
class cpu_thread
|
||||
{
|
||||
protected:
|
||||
|
@ -1968,7 +1968,7 @@ void ppu_interpreter::LBZX(PPUThread& CPU, ppu_opcode_t op)
|
||||
void ppu_interpreter::LVX(PPUThread& CPU, ppu_opcode_t op)
|
||||
{
|
||||
const u64 addr = (op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]) & ~0xfull;
|
||||
CPU.VPR[op.vd] = vm::read128(VM_CAST(addr));
|
||||
CPU.VPR[op.vd] = vm::_ref<v128>(VM_CAST(addr));
|
||||
}
|
||||
|
||||
void ppu_interpreter::NEG(PPUThread& CPU, ppu_opcode_t op)
|
||||
@ -2152,7 +2152,7 @@ void ppu_interpreter::STBX(PPUThread& CPU, ppu_opcode_t op)
|
||||
void ppu_interpreter::STVX(PPUThread& CPU, ppu_opcode_t op)
|
||||
{
|
||||
const u64 addr = (op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]) & ~0xfull;
|
||||
vm::write128(VM_CAST(addr), CPU.VPR[op.vs]);
|
||||
vm::_ref<v128>(VM_CAST(addr)) = CPU.VPR[op.vs];
|
||||
}
|
||||
|
||||
void ppu_interpreter::MULLD(PPUThread& CPU, ppu_opcode_t op)
|
||||
@ -2295,7 +2295,7 @@ void ppu_interpreter::LHAX(PPUThread& CPU, ppu_opcode_t op)
|
||||
void ppu_interpreter::LVXL(PPUThread& CPU, ppu_opcode_t op)
|
||||
{
|
||||
const u64 addr = (op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]) & ~0xfull;
|
||||
CPU.VPR[op.vd] = vm::read128(VM_CAST(addr));
|
||||
CPU.VPR[op.vd] = vm::_ref<v128>(VM_CAST(addr));
|
||||
}
|
||||
|
||||
void ppu_interpreter::MFTB(PPUThread& CPU, ppu_opcode_t op)
|
||||
@ -2435,7 +2435,7 @@ void ppu_interpreter::NAND(PPUThread& CPU, ppu_opcode_t op)
|
||||
void ppu_interpreter::STVXL(PPUThread& CPU, ppu_opcode_t op)
|
||||
{
|
||||
const u64 addr = (op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]) & ~0xfull;
|
||||
vm::write128(VM_CAST(addr), CPU.VPR[op.vs]);
|
||||
vm::_ref<v128>(VM_CAST(addr)) = CPU.VPR[op.vs];
|
||||
}
|
||||
|
||||
void ppu_interpreter::DIVD(PPUThread& CPU, ppu_opcode_t op)
|
||||
@ -2488,7 +2488,7 @@ void ppu_interpreter::LVLX(PPUThread& CPU, ppu_opcode_t op)
|
||||
void ppu_interpreter::LDBRX(PPUThread& CPU, ppu_opcode_t op)
|
||||
{
|
||||
const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb];
|
||||
CPU.GPR[op.rd] = vm::get_ref<le_t<u64>>(VM_CAST(addr));
|
||||
CPU.GPR[op.rd] = vm::_ref<le_t<u64>>(VM_CAST(addr));
|
||||
}
|
||||
|
||||
void ppu_interpreter::LSWX(PPUThread& CPU, ppu_opcode_t op)
|
||||
@ -2497,14 +2497,14 @@ void ppu_interpreter::LSWX(PPUThread& CPU, ppu_opcode_t op)
|
||||
u32 count = CPU.XER.XER & 0x7F;
|
||||
for (; count >= 4; count -= 4, addr += 4, op.rd = (op.rd + 1) & 31)
|
||||
{
|
||||
CPU.GPR[op.rd] = vm::get_ref<be_t<u32>>(VM_CAST(addr));
|
||||
CPU.GPR[op.rd] = vm::_ref<u32>(VM_CAST(addr));
|
||||
}
|
||||
if (count)
|
||||
{
|
||||
u32 value = 0;
|
||||
for (u32 byte = 0; byte < count; byte++)
|
||||
{
|
||||
u32 byte_value = vm::get_ref<u8>(VM_CAST(addr + byte));
|
||||
u32 byte_value = vm::_ref<u8>(VM_CAST(addr + byte));
|
||||
value |= byte_value << ((3 ^ byte) * 8);
|
||||
}
|
||||
CPU.GPR[op.rd] = value;
|
||||
@ -2514,13 +2514,13 @@ void ppu_interpreter::LSWX(PPUThread& CPU, ppu_opcode_t op)
|
||||
void ppu_interpreter::LWBRX(PPUThread& CPU, ppu_opcode_t op)
|
||||
{
|
||||
const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb];
|
||||
CPU.GPR[op.rd] = vm::get_ref<le_t<u32>>(VM_CAST(addr));
|
||||
CPU.GPR[op.rd] = vm::_ref<le_t<u32>>(VM_CAST(addr));
|
||||
}
|
||||
|
||||
void ppu_interpreter::LFSX(PPUThread& CPU, ppu_opcode_t op)
|
||||
{
|
||||
const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb];
|
||||
CPU.FPR[op.frd]._double = vm::get_ref<be_t<float>>(VM_CAST(addr)).value();
|
||||
CPU.FPR[op.frd]._double = vm::_ref<f32>(VM_CAST(addr));
|
||||
}
|
||||
|
||||
void ppu_interpreter::SRW(PPUThread& CPU, ppu_opcode_t op)
|
||||
@ -2586,7 +2586,7 @@ void ppu_interpreter::LSWI(PPUThread& CPU, ppu_opcode_t op)
|
||||
void ppu_interpreter::LFSUX(PPUThread& CPU, ppu_opcode_t op)
|
||||
{
|
||||
const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb];
|
||||
CPU.FPR[op.frd]._double = vm::get_ref<be_t<float>>(VM_CAST(addr)).value();
|
||||
CPU.FPR[op.frd]._double = vm::_ref<f32>(VM_CAST(addr));
|
||||
CPU.GPR[op.ra] = addr;
|
||||
}
|
||||
|
||||
@ -2598,13 +2598,13 @@ void ppu_interpreter::SYNC(PPUThread& CPU, ppu_opcode_t op)
|
||||
void ppu_interpreter::LFDX(PPUThread& CPU, ppu_opcode_t op)
|
||||
{
|
||||
const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb];
|
||||
CPU.FPR[op.frd]._double = vm::get_ref<be_t<double>>(VM_CAST(addr)).value();
|
||||
CPU.FPR[op.frd]._double = vm::_ref<f64>(VM_CAST(addr));
|
||||
}
|
||||
|
||||
void ppu_interpreter::LFDUX(PPUThread& CPU, ppu_opcode_t op)
|
||||
{
|
||||
const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb];
|
||||
CPU.FPR[op.frd]._double = vm::get_ref<be_t<double>>(VM_CAST(addr)).value();
|
||||
CPU.FPR[op.frd]._double = vm::_ref<f64>(VM_CAST(addr));
|
||||
CPU.GPR[op.ra] = addr;
|
||||
}
|
||||
|
||||
@ -2619,7 +2619,7 @@ void ppu_interpreter::STVLX(PPUThread& CPU, ppu_opcode_t op)
|
||||
void ppu_interpreter::STDBRX(PPUThread& CPU, ppu_opcode_t op)
|
||||
{
|
||||
const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb];
|
||||
vm::get_ref<le_t<u64>>(VM_CAST(addr)) = CPU.GPR[op.rs];
|
||||
vm::_ref<le_t<u64>>(VM_CAST(addr)) = CPU.GPR[op.rs];
|
||||
}
|
||||
|
||||
void ppu_interpreter::STSWX(PPUThread& CPU, ppu_opcode_t op)
|
||||
@ -2644,13 +2644,13 @@ void ppu_interpreter::STSWX(PPUThread& CPU, ppu_opcode_t op)
|
||||
void ppu_interpreter::STWBRX(PPUThread& CPU, ppu_opcode_t op)
|
||||
{
|
||||
const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb];
|
||||
vm::get_ref<le_t<u32>>(VM_CAST(addr)) = (u32)CPU.GPR[op.rs];
|
||||
vm::_ref<le_t<u32>>(VM_CAST(addr)) = (u32)CPU.GPR[op.rs];
|
||||
}
|
||||
|
||||
void ppu_interpreter::STFSX(PPUThread& CPU, ppu_opcode_t op)
|
||||
{
|
||||
const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb];
|
||||
vm::get_ref<be_t<float>>(VM_CAST(addr)) = static_cast<float>(CPU.FPR[op.frs]);
|
||||
vm::_ref<f32>(VM_CAST(addr)) = static_cast<float>(CPU.FPR[op.frs]);
|
||||
}
|
||||
|
||||
void ppu_interpreter::STVRX(PPUThread& CPU, ppu_opcode_t op)
|
||||
@ -2664,7 +2664,7 @@ void ppu_interpreter::STVRX(PPUThread& CPU, ppu_opcode_t op)
|
||||
void ppu_interpreter::STFSUX(PPUThread& CPU, ppu_opcode_t op)
|
||||
{
|
||||
const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb];
|
||||
vm::get_ref<be_t<float>>(VM_CAST(addr)) = static_cast<float>(CPU.FPR[op.frs]);
|
||||
vm::_ref<f32>(VM_CAST(addr)) = static_cast<float>(CPU.FPR[op.frs]);
|
||||
CPU.GPR[op.ra] = addr;
|
||||
}
|
||||
|
||||
@ -2700,13 +2700,13 @@ void ppu_interpreter::STSWI(PPUThread& CPU, ppu_opcode_t op)
|
||||
void ppu_interpreter::STFDX(PPUThread& CPU, ppu_opcode_t op)
|
||||
{
|
||||
const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb];
|
||||
vm::get_ref<be_t<double>>(VM_CAST(addr)) = CPU.FPR[op.frs];
|
||||
vm::_ref<f64>(VM_CAST(addr)) = CPU.FPR[op.frs];
|
||||
}
|
||||
|
||||
void ppu_interpreter::STFDUX(PPUThread& CPU, ppu_opcode_t op)
|
||||
{
|
||||
const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb];
|
||||
vm::get_ref<be_t<double>>(VM_CAST(addr)) = CPU.FPR[op.frs];
|
||||
vm::_ref<f64>(VM_CAST(addr)) = CPU.FPR[op.frs];
|
||||
CPU.GPR[op.ra] = addr;
|
||||
}
|
||||
|
||||
@ -2722,7 +2722,7 @@ void ppu_interpreter::LVLXL(PPUThread& CPU, ppu_opcode_t op)
|
||||
void ppu_interpreter::LHBRX(PPUThread& CPU, ppu_opcode_t op)
|
||||
{
|
||||
const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb];
|
||||
CPU.GPR[op.rd] = vm::get_ref<le_t<u16>>(VM_CAST(addr));
|
||||
CPU.GPR[op.rd] = vm::_ref<le_t<u16>>(VM_CAST(addr));
|
||||
}
|
||||
|
||||
void ppu_interpreter::SRAW(PPUThread& CPU, ppu_opcode_t op)
|
||||
@ -2809,7 +2809,7 @@ void ppu_interpreter::STVLXL(PPUThread& CPU, ppu_opcode_t op)
|
||||
void ppu_interpreter::STHBRX(PPUThread& CPU, ppu_opcode_t op)
|
||||
{
|
||||
const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb];
|
||||
vm::get_ref<le_t<u16>>(VM_CAST(addr)) = (u16)CPU.GPR[op.rs];
|
||||
vm::_ref<le_t<u16>>(VM_CAST(addr)) = (u16)CPU.GPR[op.rs];
|
||||
}
|
||||
|
||||
void ppu_interpreter::EXTSH(PPUThread& CPU, ppu_opcode_t op)
|
||||
@ -2852,7 +2852,7 @@ void ppu_interpreter::DCBZ(PPUThread& CPU, ppu_opcode_t op)
|
||||
{
|
||||
const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb];
|
||||
|
||||
memset(vm::get_ptr<u8>(VM_CAST(addr) & ~127), 0, 128);
|
||||
std::memset(vm::base(VM_CAST(addr) & ~127), 0, 128);
|
||||
}
|
||||
|
||||
void ppu_interpreter::LWZ(PPUThread& CPU, ppu_opcode_t op)
|
||||
@ -2967,52 +2967,52 @@ void ppu_interpreter::STMW(PPUThread& CPU, ppu_opcode_t op)
|
||||
void ppu_interpreter::LFS(PPUThread& CPU, ppu_opcode_t op)
|
||||
{
|
||||
const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16;
|
||||
CPU.FPR[op.frd]._double = vm::get_ref<be_t<float>>(VM_CAST(addr)).value();
|
||||
CPU.FPR[op.frd]._double = vm::_ref<f32>(VM_CAST(addr));
|
||||
}
|
||||
|
||||
void ppu_interpreter::LFSU(PPUThread& CPU, ppu_opcode_t op)
|
||||
{
|
||||
const u64 addr = CPU.GPR[op.ra] + op.simm16;
|
||||
CPU.FPR[op.frd]._double = vm::get_ref<be_t<float>>(VM_CAST(addr)).value();
|
||||
CPU.FPR[op.frd]._double = vm::_ref<f32>(VM_CAST(addr));
|
||||
CPU.GPR[op.ra] = addr;
|
||||
}
|
||||
|
||||
void ppu_interpreter::LFD(PPUThread& CPU, ppu_opcode_t op)
|
||||
{
|
||||
const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16;
|
||||
CPU.FPR[op.frd]._double = vm::get_ref<be_t<double>>(VM_CAST(addr)).value();
|
||||
CPU.FPR[op.frd]._double = vm::_ref<f64>(VM_CAST(addr));
|
||||
}
|
||||
|
||||
void ppu_interpreter::LFDU(PPUThread& CPU, ppu_opcode_t op)
|
||||
{
|
||||
const u64 addr = CPU.GPR[op.ra] + op.simm16;
|
||||
CPU.FPR[op.frd]._double = vm::get_ref<be_t<double>>(VM_CAST(addr)).value();
|
||||
CPU.FPR[op.frd]._double = vm::_ref<f64>(VM_CAST(addr));
|
||||
CPU.GPR[op.ra] = addr;
|
||||
}
|
||||
|
||||
void ppu_interpreter::STFS(PPUThread& CPU, ppu_opcode_t op)
|
||||
{
|
||||
const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16;
|
||||
vm::get_ref<be_t<float>>(VM_CAST(addr)) = static_cast<float>(CPU.FPR[op.frs]);
|
||||
vm::_ref<f32>(VM_CAST(addr)) = static_cast<float>(CPU.FPR[op.frs]);
|
||||
}
|
||||
|
||||
void ppu_interpreter::STFSU(PPUThread& CPU, ppu_opcode_t op)
|
||||
{
|
||||
const u64 addr = CPU.GPR[op.ra] + op.simm16;
|
||||
vm::get_ref<be_t<float>>(VM_CAST(addr)) = static_cast<float>(CPU.FPR[op.frs]);
|
||||
vm::_ref<f32>(VM_CAST(addr)) = static_cast<float>(CPU.FPR[op.frs]);
|
||||
CPU.GPR[op.ra] = addr;
|
||||
}
|
||||
|
||||
void ppu_interpreter::STFD(PPUThread& CPU, ppu_opcode_t op)
|
||||
{
|
||||
const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16;
|
||||
vm::get_ref<be_t<double>>(VM_CAST(addr)) = CPU.FPR[op.frs];
|
||||
vm::_ref<f64>(VM_CAST(addr)) = CPU.FPR[op.frs];
|
||||
}
|
||||
|
||||
void ppu_interpreter::STFDU(PPUThread& CPU, ppu_opcode_t op)
|
||||
{
|
||||
const u64 addr = CPU.GPR[op.ra] + op.simm16;
|
||||
vm::get_ref<be_t<double>>(VM_CAST(addr)) = CPU.FPR[op.frs];
|
||||
vm::_ref<f64>(VM_CAST(addr)) = CPU.FPR[op.frs];
|
||||
CPU.GPR[op.ra] = addr;
|
||||
}
|
||||
|
||||
|
@ -2440,7 +2440,7 @@ private:
|
||||
{
|
||||
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
|
||||
CPU.VPR[vd]._u8[15 - (addr & 0xf)] = vm::read8(VM_CAST(addr));
|
||||
// check LVEWX comments
|
||||
// It's bad idea to read 128 bit there
|
||||
}
|
||||
void SUBFC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc)
|
||||
{
|
||||
@ -2566,7 +2566,7 @@ private:
|
||||
{
|
||||
const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~1ULL;
|
||||
CPU.VPR[vd]._u16[7 - ((addr >> 1) & 0x7)] = vm::ps3::read16(VM_CAST(addr));
|
||||
// check LVEWX comments
|
||||
// It's bad idea to read 128 bit there
|
||||
}
|
||||
void SUBF(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc)
|
||||
{
|
||||
@ -2615,9 +2615,7 @@ private:
|
||||
{
|
||||
const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~3ULL;
|
||||
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);
|
||||
// It's bad idea to read 128 bit there
|
||||
}
|
||||
void MULHD(u32 rd, u32 ra, u32 rb, u32 rc)
|
||||
{
|
||||
@ -2651,7 +2649,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::ps3::read128(VM_CAST(addr));
|
||||
CPU.VPR[vd] = vm::ps3::_ref<v128>(VM_CAST(addr));
|
||||
}
|
||||
void NEG(u32 rd, u32 ra, u32 oe, u32 rc)
|
||||
{
|
||||
@ -2816,7 +2814,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::ps3::write128(VM_CAST(addr), CPU.VPR[vs]);
|
||||
vm::ps3::_ref<v128>(VM_CAST(addr)) = CPU.VPR[vs];
|
||||
}
|
||||
void MULLD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc)
|
||||
{
|
||||
@ -2918,7 +2916,7 @@ private:
|
||||
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::ps3::read128(VM_CAST(addr));
|
||||
CPU.VPR[vd] = vm::ps3::_ref<v128>(VM_CAST(addr));
|
||||
}
|
||||
void MFTB(u32 rd, u32 spr)
|
||||
{
|
||||
@ -3024,7 +3022,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::ps3::write128(VM_CAST(addr), CPU.VPR[vs]);
|
||||
vm::ps3::_ref<v128>(VM_CAST(addr)) = CPU.VPR[vs];
|
||||
}
|
||||
void DIVD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc)
|
||||
{
|
||||
@ -3073,7 +3071,7 @@ private:
|
||||
void LDBRX(u32 rd, u32 ra, u32 rb)
|
||||
{
|
||||
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
|
||||
CPU.GPR[rd] = vm::get_ref<le_t<u64>>(VM_CAST(addr));
|
||||
CPU.GPR[rd] = vm::ps3::_ref<le_t<u64>>(VM_CAST(addr));
|
||||
}
|
||||
void LSWX(u32 rd, u32 ra, u32 rb)
|
||||
{
|
||||
@ -3081,14 +3079,14 @@ private:
|
||||
u32 count = CPU.XER.XER & 0x7F;
|
||||
for (; count >= 4; count -= 4, addr += 4, rd = (rd+1) & 31)
|
||||
{
|
||||
CPU.GPR[rd] = vm::get_ref<be_t<u32>>(VM_CAST(addr));
|
||||
CPU.GPR[rd] = vm::ps3::_ref<u32>(VM_CAST(addr));
|
||||
}
|
||||
if (count)
|
||||
{
|
||||
u32 value = 0;
|
||||
for (u32 byte = 0; byte < count; byte++)
|
||||
{
|
||||
u32 byte_value = vm::get_ref<u8>(VM_CAST(addr+byte));
|
||||
u32 byte_value = vm::ps3::_ref<u8>(VM_CAST(addr+byte));
|
||||
value |= byte_value << ((3^byte)*8);
|
||||
}
|
||||
CPU.GPR[rd] = value;
|
||||
@ -3097,12 +3095,12 @@ private:
|
||||
void LWBRX(u32 rd, u32 ra, u32 rb)
|
||||
{
|
||||
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
|
||||
CPU.GPR[rd] = vm::get_ref<le_t<u32>>(VM_CAST(addr));
|
||||
CPU.GPR[rd] = vm::ps3::_ref<le_t<u32>>(VM_CAST(addr));
|
||||
}
|
||||
void LFSX(u32 frd, u32 ra, u32 rb)
|
||||
{
|
||||
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
|
||||
float val = vm::get_ref<be_t<float>>(VM_CAST(addr)).value();
|
||||
const f32 val = vm::ps3::_ref<f32>(VM_CAST(addr));
|
||||
if (!FPRdouble::IsNaN(val))
|
||||
{
|
||||
CPU.FPR[frd] = val;
|
||||
@ -3172,7 +3170,7 @@ private:
|
||||
void LFSUX(u32 frd, u32 ra, u32 rb)
|
||||
{
|
||||
const u64 addr = CPU.GPR[ra] + CPU.GPR[rb];
|
||||
float val = vm::get_ref<be_t<float>>(VM_CAST(addr)).value();
|
||||
const f32 val = vm::ps3::_ref<f32>(VM_CAST(addr));
|
||||
if (!FPRdouble::IsNaN(val))
|
||||
{
|
||||
CPU.FPR[frd] = val;
|
||||
@ -3191,12 +3189,12 @@ private:
|
||||
void LFDX(u32 frd, u32 ra, u32 rb)
|
||||
{
|
||||
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
|
||||
CPU.FPR[frd] = vm::get_ref<be_t<double>>(VM_CAST(addr)).value();
|
||||
CPU.FPR[frd]._double = vm::ps3::_ref<f64>(VM_CAST(addr));
|
||||
}
|
||||
void LFDUX(u32 frd, u32 ra, u32 rb)
|
||||
{
|
||||
const u64 addr = CPU.GPR[ra] + CPU.GPR[rb];
|
||||
CPU.FPR[frd] = vm::get_ref<be_t<double>>(VM_CAST(addr)).value();
|
||||
CPU.FPR[frd]._double = vm::ps3::_ref<f64>(VM_CAST(addr));
|
||||
CPU.GPR[ra] = addr;
|
||||
}
|
||||
void STVLX(u32 vs, u32 ra, u32 rb)
|
||||
@ -3209,7 +3207,7 @@ private:
|
||||
void STDBRX(u32 rs, u32 ra, u32 rb)
|
||||
{
|
||||
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
|
||||
vm::get_ref<le_t<u64>>(VM_CAST(addr)) = CPU.GPR[rs];
|
||||
vm::ps3::_ref<le_t<u64>>(VM_CAST(addr)) = CPU.GPR[rs];
|
||||
}
|
||||
void STSWX(u32 rs, u32 ra, u32 rb)
|
||||
{
|
||||
@ -3232,7 +3230,7 @@ private:
|
||||
void STWBRX(u32 rs, u32 ra, u32 rb)
|
||||
{
|
||||
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
|
||||
vm::get_ref<le_t<u32>>(VM_CAST(addr)) = (u32)CPU.GPR[rs];
|
||||
vm::ps3::_ref<le_t<u32>>(VM_CAST(addr)) = (u32)CPU.GPR[rs];
|
||||
}
|
||||
void STFSX(u32 frs, u32 ra, u32 rb)
|
||||
{
|
||||
@ -3240,13 +3238,13 @@ private:
|
||||
double val = CPU.FPR[frs];
|
||||
if (!FPRdouble::IsNaN(val))
|
||||
{
|
||||
vm::get_ref<be_t<float>>(VM_CAST(addr)) = (float)val;
|
||||
vm::ps3::_ref<f32>(VM_CAST(addr)) = (float)val;
|
||||
}
|
||||
else
|
||||
{
|
||||
u64 bits = (u64&)val;
|
||||
u32 bits32 = (bits>>32 & 0x80000000) | (bits>>29 & 0x7fffffff);
|
||||
vm::get_ref<be_t<u32>>(VM_CAST(addr)) = bits32;
|
||||
vm::ps3::_ref<u32>(VM_CAST(addr)) = bits32;
|
||||
}
|
||||
}
|
||||
void STVRX(u32 vs, u32 ra, u32 rb)
|
||||
@ -3262,13 +3260,13 @@ private:
|
||||
double val = CPU.FPR[frs];
|
||||
if (!FPRdouble::IsNaN(val))
|
||||
{
|
||||
vm::get_ref<be_t<float>>(VM_CAST(addr)) = (float)val;
|
||||
vm::ps3::_ref<f32>(VM_CAST(addr)) = (float)val;
|
||||
}
|
||||
else
|
||||
{
|
||||
u64 bits = (u64&)val;
|
||||
u32 bits32 = (bits>>32 & 0x80000000) | (bits>>29 & 0x7fffffff);
|
||||
vm::get_ref<be_t<u32>>(VM_CAST(addr)) = bits32;
|
||||
vm::ps3::_ref<u32>(VM_CAST(addr)) = bits32;
|
||||
}
|
||||
CPU.GPR[ra] = addr;
|
||||
}
|
||||
@ -3303,12 +3301,12 @@ private:
|
||||
void STFDX(u32 frs, u32 ra, u32 rb)
|
||||
{
|
||||
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
|
||||
vm::get_ref<be_t<double>>(VM_CAST(addr)) = CPU.FPR[frs];
|
||||
vm::ps3::_ref<f64>(VM_CAST(addr)) = CPU.FPR[frs];
|
||||
}
|
||||
void STFDUX(u32 frs, u32 ra, u32 rb)
|
||||
{
|
||||
const u64 addr = CPU.GPR[ra] + CPU.GPR[rb];
|
||||
vm::get_ref<be_t<double>>(VM_CAST(addr)) = CPU.FPR[frs];
|
||||
vm::ps3::_ref<f64>(VM_CAST(addr)) = CPU.FPR[frs];
|
||||
CPU.GPR[ra] = addr;
|
||||
}
|
||||
void LVLXL(u32 vd, u32 ra, u32 rb)
|
||||
@ -3322,7 +3320,7 @@ private:
|
||||
void LHBRX(u32 rd, u32 ra, u32 rb)
|
||||
{
|
||||
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
|
||||
CPU.GPR[rd] = vm::get_ref<le_t<u16>>(VM_CAST(addr));
|
||||
CPU.GPR[rd] = vm::ps3::_ref<le_t<u16>>(VM_CAST(addr));
|
||||
}
|
||||
void SRAW(u32 ra, u32 rs, u32 rb, u32 rc)
|
||||
{
|
||||
@ -3403,7 +3401,7 @@ private:
|
||||
void STHBRX(u32 rs, u32 ra, u32 rb)
|
||||
{
|
||||
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
|
||||
vm::get_ref<le_t<u16>>(VM_CAST(addr)) = (u16)CPU.GPR[rs];
|
||||
vm::ps3::_ref<le_t<u16>>(VM_CAST(addr)) = (u16)CPU.GPR[rs];
|
||||
}
|
||||
void EXTSH(u32 ra, u32 rs, u32 rc)
|
||||
{
|
||||
@ -3440,7 +3438,7 @@ private:
|
||||
{
|
||||
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
|
||||
|
||||
memset(vm::get_ptr<u8>(VM_CAST(addr) & ~127), 0, 128);
|
||||
std::memset(vm::base(VM_CAST(addr) & ~127), 0, 128);
|
||||
}
|
||||
void LWZ(u32 rd, u32 ra, s32 d)
|
||||
{
|
||||
@ -3538,7 +3536,7 @@ private:
|
||||
void LFS(u32 frd, u32 ra, s32 d)
|
||||
{
|
||||
const u64 addr = ra ? CPU.GPR[ra] + d : d;
|
||||
float val = vm::get_ref<be_t<float>>(VM_CAST(addr)).value();
|
||||
const f32 val = vm::ps3::_ref<f32>(VM_CAST(addr));
|
||||
if (!FPRdouble::IsNaN(val))
|
||||
{
|
||||
CPU.FPR[frd] = val;
|
||||
@ -3552,7 +3550,7 @@ private:
|
||||
void LFSU(u32 frd, u32 ra, s32 ds)
|
||||
{
|
||||
const u64 addr = CPU.GPR[ra] + ds;
|
||||
float val = vm::get_ref<be_t<float>>(VM_CAST(addr)).value();
|
||||
const f32 val = vm::ps3::_ref<f32>(VM_CAST(addr));
|
||||
if (!FPRdouble::IsNaN(val))
|
||||
{
|
||||
CPU.FPR[frd] = val;
|
||||
@ -3567,12 +3565,12 @@ private:
|
||||
void LFD(u32 frd, u32 ra, s32 d)
|
||||
{
|
||||
const u64 addr = ra ? CPU.GPR[ra] + d : d;
|
||||
CPU.FPR[frd] = vm::get_ref<be_t<double>>(VM_CAST(addr)).value();
|
||||
CPU.FPR[frd]._double = vm::ps3::_ref<f64>(VM_CAST(addr));
|
||||
}
|
||||
void LFDU(u32 frd, u32 ra, s32 ds)
|
||||
{
|
||||
const u64 addr = CPU.GPR[ra] + ds;
|
||||
CPU.FPR[frd] = vm::get_ref<be_t<double>>(VM_CAST(addr)).value();
|
||||
CPU.FPR[frd]._double = vm::ps3::_ref<f64>(VM_CAST(addr));
|
||||
CPU.GPR[ra] = addr;
|
||||
}
|
||||
void STFS(u32 frs, u32 ra, s32 d)
|
||||
@ -3581,13 +3579,13 @@ private:
|
||||
double val = CPU.FPR[frs];
|
||||
if (!FPRdouble::IsNaN(val))
|
||||
{
|
||||
vm::get_ref<be_t<float>>(VM_CAST(addr)) = (float)val;
|
||||
vm::ps3::_ref<f32>(VM_CAST(addr)) = (float)val;
|
||||
}
|
||||
else
|
||||
{
|
||||
u64 bits = (u64&)val;
|
||||
u32 bits32 = (bits>>32 & 0x80000000) | (bits>>29 & 0x7fffffff);
|
||||
vm::get_ref<be_t<u32>>(VM_CAST(addr)) = bits32;
|
||||
vm::ps3::_ref<u32>(VM_CAST(addr)) = bits32;
|
||||
}
|
||||
}
|
||||
void STFSU(u32 frs, u32 ra, s32 d)
|
||||
@ -3596,25 +3594,25 @@ private:
|
||||
double val = CPU.FPR[frs];
|
||||
if (!FPRdouble::IsNaN(val))
|
||||
{
|
||||
vm::get_ref<be_t<float>>(VM_CAST(addr)) = (float)val;
|
||||
vm::ps3::_ref<f32>(VM_CAST(addr)) = (float)val;
|
||||
}
|
||||
else
|
||||
{
|
||||
u64 bits = (u64&)val;
|
||||
u32 bits32 = (bits>>32 & 0x80000000) | (bits>>29 & 0x7fffffff);
|
||||
vm::get_ref<be_t<u32>>(VM_CAST(addr)) = bits32;
|
||||
vm::ps3::_ref<u32>(VM_CAST(addr)) = bits32;
|
||||
}
|
||||
CPU.GPR[ra] = addr;
|
||||
}
|
||||
void STFD(u32 frs, u32 ra, s32 d)
|
||||
{
|
||||
const u64 addr = ra ? CPU.GPR[ra] + d : d;
|
||||
vm::get_ref<be_t<double>>(VM_CAST(addr)) = CPU.FPR[frs];
|
||||
vm::ps3::_ref<f64>(VM_CAST(addr)) = CPU.FPR[frs];
|
||||
}
|
||||
void STFDU(u32 frs, u32 ra, s32 d)
|
||||
{
|
||||
const u64 addr = CPU.GPR[ra] + d;
|
||||
vm::get_ref<be_t<double>>(VM_CAST(addr)) = CPU.FPR[frs];
|
||||
vm::ps3::_ref<f64>(VM_CAST(addr)) = CPU.FPR[frs];
|
||||
CPU.GPR[ra] = addr;
|
||||
}
|
||||
void LD(u32 rd, u32 ra, s32 ds)
|
||||
|
@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "PPUOpcodes.h"
|
||||
|
||||
class PPUThread;
|
||||
@ -7,133 +8,51 @@ union ppu_opcode_t
|
||||
{
|
||||
u32 opcode;
|
||||
|
||||
struct
|
||||
{
|
||||
u32 : 1; // 31
|
||||
u32 shh : 1; // 30
|
||||
u32 : 3; // 27..29
|
||||
u32 mbmeh : 1; // 26
|
||||
u32 mbmel : 5; // 21..25
|
||||
u32 shl : 5; // 16..20
|
||||
u32 vuimm : 5; // 11..15
|
||||
u32 vs : 5; // 6..10
|
||||
u32 : 6;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
u32 : 6; // 26..31
|
||||
u32 vsh : 4; // 22..25
|
||||
u32 oe : 1; // 21
|
||||
u32 spr : 10; // 11..20
|
||||
u32 : 11;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
u32 : 6; // 26..31
|
||||
u32 vc : 5; // 21..25
|
||||
u32 vb : 5; // 16..20
|
||||
u32 va : 5; // 11..15
|
||||
u32 vd : 5; // 6..10
|
||||
u32 : 6;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
u32 lk : 1; // 31
|
||||
u32 aa : 1; // 30
|
||||
u32 : 4; // 26..29
|
||||
u32 : 5; // 21..25
|
||||
u32 rb : 5; // 16..20
|
||||
u32 ra : 5; // 11..15
|
||||
u32 rd : 5; // 6..10
|
||||
u32 : 6;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
u32 uimm16 : 16; // 16..31
|
||||
u32 : 4; // 12..15
|
||||
u32 l11 : 1; // 11
|
||||
u32 rs : 5; // 6..10
|
||||
u32 : 6;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
s32 simm16 : 16; // 16..31
|
||||
s32 vsimm : 5; // 11..15
|
||||
s32 : 11;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
s32 ll : 26; // 6..31
|
||||
s32 : 6;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
u32 : 5; // 27..31
|
||||
u32 lev : 7; // 20..26
|
||||
u32 i : 4; // 16..19
|
||||
u32 : 2; // 14..15
|
||||
u32 crfs : 3; // 11..13
|
||||
u32 l10 : 1; // 10
|
||||
u32 : 1; // 9
|
||||
u32 crfd : 3; // 6..8
|
||||
u32 : 6;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
u32 : 1; // 31
|
||||
u32 : 1; // 30
|
||||
u32 : 4; // 26..29
|
||||
u32 : 5; // 21..25
|
||||
u32 crbb : 5; // 16..20
|
||||
u32 crba : 5; // 11..15
|
||||
u32 crbd : 5; // 6..10
|
||||
u32 : 6;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
u32 rc : 1; // 31
|
||||
u32 me : 5; // 26..30
|
||||
u32 mb : 5; // 21..25
|
||||
u32 sh : 5; // 16..20
|
||||
u32 bi : 5; // 11..15
|
||||
u32 bo : 5; // 6..10
|
||||
u32 : 6;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
u32 : 6; // 26..31
|
||||
u32 frc : 5; // 21..25
|
||||
u32 frb : 5; // 16..20
|
||||
u32 fra : 5; // 11..15
|
||||
u32 frd : 5; // 6..10
|
||||
u32 : 6;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
u32 : 12; // 20..31
|
||||
u32 crm : 8; // 12..19
|
||||
u32 : 1; // 11
|
||||
u32 frs : 5; // 6..10
|
||||
u32 : 6;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
u32 : 17; // 15..31
|
||||
u32 flm : 8; // 7..14
|
||||
u32 : 7;
|
||||
};
|
||||
bf_t<u32, 32 - 1 - 30, 1> shh; // 30
|
||||
bf_t<u32, 32 - 1 - 26, 1> mbmeh; // 26
|
||||
bf_t<u32, 32 - 5 - 21, 5> mbmel; // 21..25
|
||||
bf_t<u32, 32 - 5 - 16, 5> shl; // 16..20
|
||||
bf_t<u32, 32 - 5 - 11, 5> vuimm; // 11..15
|
||||
bf_t<u32, 32 - 5 - 6, 5> vs; // 6..10
|
||||
bf_t<u32, 32 - 4 - 22, 4> vsh; // 22..25
|
||||
bf_t<u32, 32 - 1 - 21, 1> oe; // 21
|
||||
bf_t<u32, 32 - 10 - 11, 10> spr; // 11..20
|
||||
bf_t<u32, 32 - 5 - 21, 5> vc; // 21..25
|
||||
bf_t<u32, 32 - 5 - 16, 5> vb; // 16..20
|
||||
bf_t<u32, 32 - 5 - 11, 5> va; // 11..15
|
||||
bf_t<u32, 32 - 5 - 6, 5> vd; // 6..10
|
||||
bf_t<u32, 32 - 1 - 31, 1> lk; // 31
|
||||
bf_t<u32, 32 - 1 - 30, 1> aa; // 30
|
||||
bf_t<u32, 32 - 5 - 16, 5> rb; // 16..20
|
||||
bf_t<u32, 32 - 5 - 11, 5> ra; // 11..15
|
||||
bf_t<u32, 32 - 5 - 6, 5> rd; // 6..10
|
||||
bf_t<u32, 32 - 16 - 16, 16> uimm16; // 16..31
|
||||
bf_t<u32, 32 - 1 - 11, 1> l11; // 11
|
||||
bf_t<u32, 32 - 5 - 6, 5> rs; // 6..10
|
||||
bf_t<s32, 32 - 16 - 16, 16> simm16; // 16..31, signed
|
||||
bf_t<s32, 32 - 5 - 11, 5> vsimm; // 11..15, signed
|
||||
bf_t<s32, 32 - 26 - 6, 26> ll; // 6..31, signed
|
||||
bf_t<u32, 32 - 7 - 20, 7> lev; // 20..26
|
||||
bf_t<u32, 32 - 4 - 16, 4> i; // 16..19
|
||||
bf_t<u32, 32 - 3 - 11, 3> crfs; // 11..13
|
||||
bf_t<u32, 32 - 1 - 10, 1> l10; // 10
|
||||
bf_t<u32, 32 - 3 - 6, 3> crfd; // 6..8
|
||||
bf_t<u32, 32 - 5 - 16, 5> crbb; // 16..20
|
||||
bf_t<u32, 32 - 5 - 11, 5> crba; // 11..15
|
||||
bf_t<u32, 32 - 5 - 6, 5> crbd; // 6..10
|
||||
bf_t<u32, 32 - 1 - 31, 1> rc; // 31
|
||||
bf_t<u32, 32 - 5 - 26, 5> me; // 26..30
|
||||
bf_t<u32, 32 - 5 - 21, 5> mb; // 21..25
|
||||
bf_t<u32, 32 - 5 - 16, 5> sh; // 16..20
|
||||
bf_t<u32, 32 - 5 - 11, 5> bi; // 11..15
|
||||
bf_t<u32, 32 - 5 - 6, 5> bo; // 6..10
|
||||
bf_t<u32, 32 - 5 - 21, 5> frc; // 21..25
|
||||
bf_t<u32, 32 - 5 - 16, 5> frb; // 16..20
|
||||
bf_t<u32, 32 - 5 - 11, 5> fra; // 11..15
|
||||
bf_t<u32, 32 - 5 - 6, 5> frd; // 6..10
|
||||
bf_t<u32, 32 - 8 - 12, 8> crm; // 12..19
|
||||
bf_t<u32, 32 - 5 - 6, 5> frs; // 6..10
|
||||
bf_t<u32, 32 - 8 - 7, 8> flm; // 7..14
|
||||
};
|
||||
|
||||
namespace ppu_interpreter
|
||||
|
@ -133,7 +133,7 @@ std::pair<Executable, llvm::ExecutionEngine *> Compiler::Compile(const std::stri
|
||||
|
||||
// Used to decode instructions
|
||||
PPUDisAsm dis_asm(CPUDisAsm_DumpMode);
|
||||
dis_asm.offset = vm::get_ptr<u8>(start_address);
|
||||
dis_asm.offset = vm::ps3::_ptr<u8>(start_address);
|
||||
|
||||
m_recompilation_engine.Log() << "Recompiling block :\n\n";
|
||||
|
||||
|
@ -66,14 +66,10 @@ namespace ppu_recompiler_llvm {
|
||||
Compiler(RecompilationEngine & recompilation_engine, const Executable execute_unknown_function,
|
||||
const Executable execute_unknown_block, bool(*poll_status_function)(PPUThread * ppu_state));
|
||||
|
||||
Compiler(const Compiler & other) = delete;
|
||||
Compiler(Compiler && other) = delete;
|
||||
Compiler(const Compiler&) = delete; // Delete copy/move constructors and copy/move operators
|
||||
|
||||
virtual ~Compiler();
|
||||
|
||||
Compiler & operator = (const Compiler & other) = delete;
|
||||
Compiler & operator = (Compiler && other) = delete;
|
||||
|
||||
/**
|
||||
* Compile a code fragment described by a cfg and return an executable and the ExecutionEngine storing it
|
||||
* Pointer to function can be retrieved with getPointerToFunction
|
||||
@ -883,11 +879,7 @@ namespace ppu_recompiler_llvm {
|
||||
|
||||
RecompilationEngine();
|
||||
|
||||
RecompilationEngine(const RecompilationEngine & other) = delete;
|
||||
RecompilationEngine(RecompilationEngine && other) = delete;
|
||||
|
||||
RecompilationEngine & operator = (const RecompilationEngine & other) = delete;
|
||||
RecompilationEngine & operator = (RecompilationEngine && other) = delete;
|
||||
RecompilationEngine(const RecompilationEngine&) = delete; // Delete copy/move constructors and copy/move operators
|
||||
|
||||
/// Increase usage counter for block starting at addr and compile it if threshold was reached.
|
||||
/// Returns true if block was compiled
|
||||
@ -921,16 +913,11 @@ namespace ppu_recompiler_llvm {
|
||||
friend class Compiler;
|
||||
public:
|
||||
CPUHybridDecoderRecompiler(PPUThread & ppu);
|
||||
CPUHybridDecoderRecompiler() = delete;
|
||||
|
||||
CPUHybridDecoderRecompiler(const CPUHybridDecoderRecompiler & other) = delete;
|
||||
CPUHybridDecoderRecompiler(CPUHybridDecoderRecompiler && other) = delete;
|
||||
CPUHybridDecoderRecompiler(const CPUHybridDecoderRecompiler&) = delete; // Delete copy/move constructors and copy/move operators
|
||||
|
||||
virtual ~CPUHybridDecoderRecompiler();
|
||||
|
||||
CPUHybridDecoderRecompiler & operator = (const ExecutionEngine & other) = delete;
|
||||
CPUHybridDecoderRecompiler & operator = (ExecutionEngine && other) = delete;
|
||||
|
||||
u32 DecodeMemory(const u32 address) override;
|
||||
|
||||
private:
|
||||
|
@ -3502,7 +3502,7 @@ void Compiler::STVLX(u32 vs, u32 ra, u32 rb) {
|
||||
auto index_i64 = m_ir_builder->CreateAnd(addr_i64, 0xf);
|
||||
auto size_i64 = m_ir_builder->CreateSub(m_ir_builder->getInt64(16), index_i64);
|
||||
addr_i64 = m_ir_builder->CreateAnd(addr_i64, 0xFFFFFFFF);
|
||||
addr_i64 = m_ir_builder->CreateAdd(addr_i64, m_ir_builder->getInt64((u64)vm::get_ptr<u8>(0)));
|
||||
addr_i64 = m_ir_builder->CreateAdd(addr_i64, m_ir_builder->getInt64((u64)vm::base(0)));
|
||||
auto addr_i8_ptr = m_ir_builder->CreateIntToPtr(addr_i64, m_ir_builder->getInt8PtrTy());
|
||||
|
||||
auto vs_i128 = GetVr(vs);
|
||||
@ -3562,7 +3562,7 @@ void Compiler::STVRX(u32 vs, u32 ra, u32 rb) {
|
||||
auto size_i64 = m_ir_builder->CreateAnd(addr_i64, 0xf);
|
||||
auto index_i64 = m_ir_builder->CreateSub(m_ir_builder->getInt64(16), size_i64);
|
||||
addr_i64 = m_ir_builder->CreateAnd(addr_i64, 0xFFFFFFF0);
|
||||
addr_i64 = m_ir_builder->CreateAdd(addr_i64, m_ir_builder->getInt64((u64)vm::get_ptr<u8>(0)));
|
||||
addr_i64 = m_ir_builder->CreateAdd(addr_i64, m_ir_builder->getInt64((u64)vm::base(0)));
|
||||
auto addr_i8_ptr = m_ir_builder->CreateIntToPtr(addr_i64, m_ir_builder->getInt8PtrTy());
|
||||
|
||||
auto vs_i128 = GetVr(vs);
|
||||
@ -3834,7 +3834,7 @@ void Compiler::DCBZ(u32 ra, u32 rb) {
|
||||
}
|
||||
|
||||
addr_i64 = m_ir_builder->CreateAnd(addr_i64, ~(127ULL));
|
||||
addr_i64 = m_ir_builder->CreateAdd(addr_i64, m_ir_builder->getInt64((u64)vm::get_ptr<u8>(0)));
|
||||
addr_i64 = m_ir_builder->CreateAdd(addr_i64, m_ir_builder->getInt64((u64)vm::base(0)));
|
||||
auto addr_i8_ptr = m_ir_builder->CreateIntToPtr(addr_i64, m_ir_builder->getInt8PtrTy());
|
||||
|
||||
std::vector<Type *> types = { (Type *)m_ir_builder->getInt8PtrTy(), (Type *)m_ir_builder->getInt32Ty() };
|
||||
@ -5312,7 +5312,7 @@ void Compiler::CreateBranch(llvm::Value * cmp_i1, llvm::Value * target_i32, bool
|
||||
|
||||
Value * Compiler::ReadMemory(Value * addr_i64, u32 bits, u32 alignment, bool bswap, bool could_be_mmio) {
|
||||
addr_i64 = m_ir_builder->CreateAnd(addr_i64, 0xFFFFFFFF);
|
||||
auto eaddr_i64 = m_ir_builder->CreateAdd(addr_i64, m_ir_builder->getInt64((u64)vm::get_ptr<u8>(0)));
|
||||
auto eaddr_i64 = m_ir_builder->CreateAdd(addr_i64, m_ir_builder->getInt64((u64)vm::base(0)));
|
||||
auto eaddr_ix_ptr = m_ir_builder->CreateIntToPtr(eaddr_i64, m_ir_builder->getIntNTy(bits)->getPointerTo());
|
||||
auto val_ix = (Value *)m_ir_builder->CreateLoad(eaddr_ix_ptr, alignment);
|
||||
if (bits > 8 && bswap) {
|
||||
@ -5328,7 +5328,7 @@ void Compiler::WriteMemory(Value * addr_i64, Value * val_ix, u32 alignment, bool
|
||||
}
|
||||
|
||||
addr_i64 = m_ir_builder->CreateAnd(addr_i64, 0xFFFFFFFF);
|
||||
auto eaddr_i64 = m_ir_builder->CreateAdd(addr_i64, m_ir_builder->getInt64((u64)vm::get_ptr<u8>(0)));
|
||||
auto eaddr_i64 = m_ir_builder->CreateAdd(addr_i64, m_ir_builder->getInt64((u64)vm::base(0)));
|
||||
auto eaddr_ix_ptr = m_ir_builder->CreateIntToPtr(eaddr_i64, val_ix->getType()->getPointerTo());
|
||||
m_ir_builder->CreateAlignedStore(val_ix, eaddr_ix_ptr, alignment);
|
||||
}
|
||||
|
@ -363,7 +363,7 @@ cpu_thread& ppu_thread::args(std::initializer_list<std::string> values)
|
||||
const u32 arg_size = align(u32(arg.size() + 1), stack_align);
|
||||
const u32 arg_addr = vm::alloc(arg_size, vm::main);
|
||||
|
||||
std::memcpy(vm::get_ptr(arg_addr), arg.c_str(), arg.size() + 1);
|
||||
std::memcpy(vm::base(arg_addr), arg.c_str(), arg.size() + 1);
|
||||
|
||||
argv[argc++] = arg_addr;
|
||||
}
|
||||
|
@ -536,9 +536,7 @@ public:
|
||||
|
||||
std::function<void(PPUThread& CPU)> custom_task;
|
||||
|
||||
/// When a thread has met an exception, this variable is used to retro propagate it through stack call.
|
||||
/// Note that exception_ptr is similar to shared_ptr and doesn't need to be freed, but need a nullptr
|
||||
/// to be assigned.
|
||||
// When a thread has met an exception, this variable is used to retro propagate it through stack call.
|
||||
std::exception_ptr pending_exception;
|
||||
|
||||
public:
|
||||
@ -557,7 +555,7 @@ public:
|
||||
|
||||
virtual bool handle_interrupt() override;
|
||||
|
||||
inline u8 GetCR(const u8 n) const
|
||||
u8 GetCR(const u8 n) const
|
||||
{
|
||||
switch(n)
|
||||
{
|
||||
@ -574,7 +572,7 @@ public:
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void SetCR(const u8 n, const u32 value)
|
||||
void SetCR(const u8 n, const u32 value)
|
||||
{
|
||||
switch(n)
|
||||
{
|
||||
@ -589,7 +587,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
inline void SetCRBit(const u8 n, const u32 bit, const bool value)
|
||||
void SetCRBit(const u8 n, const u32 bit, const bool value)
|
||||
{
|
||||
switch(n)
|
||||
{
|
||||
@ -604,14 +602,14 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
inline void SetCR_EQ(const u8 n, const bool value) { SetCRBit(n, CR_EQ, value); }
|
||||
inline void SetCR_GT(const u8 n, const bool value) { SetCRBit(n, CR_GT, value); }
|
||||
inline void SetCR_LT(const u8 n, const bool value) { SetCRBit(n, CR_LT, value); }
|
||||
inline void SetCR_SO(const u8 n, const bool value) { SetCRBit(n, CR_SO, value); }
|
||||
void SetCR_EQ(const u8 n, const bool value) { SetCRBit(n, CR_EQ, value); }
|
||||
void SetCR_GT(const u8 n, const bool value) { SetCRBit(n, CR_GT, value); }
|
||||
void SetCR_LT(const u8 n, const bool value) { SetCRBit(n, CR_LT, value); }
|
||||
void SetCR_SO(const u8 n, const bool value) { SetCRBit(n, CR_SO, value); }
|
||||
|
||||
inline bool IsCR_EQ(const u8 n) const { return (GetCR(n) & CR_EQ) ? 1 : 0; }
|
||||
inline bool IsCR_GT(const u8 n) const { return (GetCR(n) & CR_GT) ? 1 : 0; }
|
||||
inline bool IsCR_LT(const u8 n) const { return (GetCR(n) & CR_LT) ? 1 : 0; }
|
||||
bool IsCR_EQ(const u8 n) const { return (GetCR(n) & CR_EQ) ? 1 : 0; }
|
||||
bool IsCR_GT(const u8 n) const { return (GetCR(n) & CR_GT) ? 1 : 0; }
|
||||
bool IsCR_LT(const u8 n) const { return (GetCR(n) & CR_LT) ? 1 : 0; }
|
||||
|
||||
template<typename T> void UpdateCRn(const u8 n, const T a, const T b)
|
||||
{
|
||||
|
@ -223,10 +223,7 @@ spu_recompiler::XmmLink spu_recompiler::XmmAlloc() // get empty xmm register
|
||||
{
|
||||
for (auto& v : vec)
|
||||
{
|
||||
if (v)
|
||||
{
|
||||
return XmmLink{ v };
|
||||
}
|
||||
if (v) return{ v };
|
||||
}
|
||||
|
||||
throw EXCEPTION("Out of Xmm Vars");
|
||||
@ -699,7 +696,7 @@ void spu_recompiler::SHLH(spu_opcode_t op)
|
||||
void spu_recompiler::ROTI(spu_opcode_t op)
|
||||
{
|
||||
// rotate left
|
||||
const int s = op.si7 & 0x1f;
|
||||
const int s = op.i7 & 0x1f;
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Int);
|
||||
const XmmLink& v1 = XmmAlloc();
|
||||
c->movdqa(v1, va);
|
||||
@ -712,7 +709,7 @@ void spu_recompiler::ROTI(spu_opcode_t op)
|
||||
void spu_recompiler::ROTMI(spu_opcode_t op)
|
||||
{
|
||||
// shift right logical
|
||||
const int s = (0 - op.si7) & 0x3f;
|
||||
const int s = 0-op.i7 & 0x3f;
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Int);
|
||||
c->psrld(va, s);
|
||||
c->movdqa(SPU_OFF_128(gpr[op.rt]), va);
|
||||
@ -721,7 +718,7 @@ void spu_recompiler::ROTMI(spu_opcode_t op)
|
||||
void spu_recompiler::ROTMAI(spu_opcode_t op)
|
||||
{
|
||||
// shift right arithmetical
|
||||
const int s = (0 - op.si7) & 0x3f;
|
||||
const int s = 0-op.i7 & 0x3f;
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Int);
|
||||
c->psrad(va, s);
|
||||
c->movdqa(SPU_OFF_128(gpr[op.rt]), va);
|
||||
@ -730,7 +727,7 @@ void spu_recompiler::ROTMAI(spu_opcode_t op)
|
||||
void spu_recompiler::SHLI(spu_opcode_t op)
|
||||
{
|
||||
// shift left
|
||||
const int s = op.si7 & 0x3f;
|
||||
const int s = op.i7 & 0x3f;
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Int);
|
||||
c->pslld(va, s);
|
||||
c->movdqa(SPU_OFF_128(gpr[op.rt]), va);
|
||||
@ -739,7 +736,7 @@ void spu_recompiler::SHLI(spu_opcode_t op)
|
||||
void spu_recompiler::ROTHI(spu_opcode_t op)
|
||||
{
|
||||
// rotate left (halfword)
|
||||
const int s = op.si7 & 0xf;
|
||||
const int s = op.i7 & 0xf;
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Int);
|
||||
const XmmLink& v1 = XmmAlloc();
|
||||
c->movdqa(v1, va);
|
||||
@ -752,7 +749,7 @@ void spu_recompiler::ROTHI(spu_opcode_t op)
|
||||
void spu_recompiler::ROTHMI(spu_opcode_t op)
|
||||
{
|
||||
// shift right logical
|
||||
const int s = (0 - op.si7) & 0x1f;
|
||||
const int s = 0-op.i7 & 0x1f;
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Int);
|
||||
c->psrlw(va, s);
|
||||
c->movdqa(SPU_OFF_128(gpr[op.rt]), va);
|
||||
@ -761,7 +758,7 @@ void spu_recompiler::ROTHMI(spu_opcode_t op)
|
||||
void spu_recompiler::ROTMAHI(spu_opcode_t op)
|
||||
{
|
||||
// shift right arithmetical (halfword)
|
||||
const int s = (0 - op.si7) & 0x1f;
|
||||
const int s = 0-op.i7 & 0x1f;
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Int);
|
||||
c->psraw(va, s);
|
||||
c->movdqa(SPU_OFF_128(gpr[op.rt]), va);
|
||||
@ -770,7 +767,7 @@ void spu_recompiler::ROTMAHI(spu_opcode_t op)
|
||||
void spu_recompiler::SHLHI(spu_opcode_t op)
|
||||
{
|
||||
// shift left (halfword)
|
||||
const int s = op.si7 & 0x1f;
|
||||
const int s = op.i7 & 0x1f;
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Int);
|
||||
c->psllw(va, s);
|
||||
c->movdqa(SPU_OFF_128(gpr[op.rt]), va);
|
||||
@ -914,7 +911,7 @@ void spu_recompiler::BISL(spu_opcode_t op)
|
||||
const XmmLink& vr = XmmAlloc();
|
||||
c->movdqa(vr, XmmConst(_mm_set_epi32(spu_branch_target(m_pos + 4), 0, 0, 0)));
|
||||
c->movdqa(SPU_OFF_128(gpr[op.rt]), vr);
|
||||
c->unuse(*vr.m_var);
|
||||
c->unuse(vr);
|
||||
|
||||
FunctionCall();
|
||||
}
|
||||
@ -1243,14 +1240,14 @@ void spu_recompiler::CBD(spu_opcode_t op)
|
||||
// // assuming that SP % 16 is always zero
|
||||
// const XmmLink& vr = XmmAlloc();
|
||||
// v128 value = v128::fromV(_mm_set_epi32(0x10111213, 0x14151617, 0x18191a1b, 0x1c1d1e1f));
|
||||
// value.u8r[op.si7 & 0xf] = 0x03;
|
||||
// value.u8r[op.i7 & 0xf] = 0x03;
|
||||
// c->movdqa(vr, XmmConst(value));
|
||||
// c->movdqa(SPU_OFF_128(gpr[op.rt]), vr);
|
||||
// return;
|
||||
//}
|
||||
|
||||
c->mov(*addr, SPU_OFF_32(gpr[op.ra]._u32[3]));
|
||||
if (op.si7) c->add(*addr, op.si7);
|
||||
if (op.i7) c->add(*addr, op.i7);
|
||||
c->not_(*addr);
|
||||
c->and_(*addr, 0xf);
|
||||
|
||||
@ -1268,14 +1265,14 @@ void spu_recompiler::CHD(spu_opcode_t op)
|
||||
// // assuming that SP % 16 is always zero
|
||||
// const XmmLink& vr = XmmAlloc();
|
||||
// v128 value = v128::fromV(_mm_set_epi32(0x10111213, 0x14151617, 0x18191a1b, 0x1c1d1e1f));
|
||||
// value.u16r[(op.si7 >> 1) & 0x7] = 0x0203;
|
||||
// value.u16r[(op.i7 >> 1) & 0x7] = 0x0203;
|
||||
// c->movdqa(vr, XmmConst(value));
|
||||
// c->movdqa(SPU_OFF_128(gpr[op.rt]), vr);
|
||||
// return;
|
||||
//}
|
||||
|
||||
c->mov(*addr, SPU_OFF_32(gpr[op.ra]._u32[3]));
|
||||
if (op.si7) c->add(*addr, op.si7);
|
||||
if (op.i7) c->add(*addr, op.i7);
|
||||
c->not_(*addr);
|
||||
c->and_(*addr, 0xe);
|
||||
|
||||
@ -1293,14 +1290,14 @@ void spu_recompiler::CWD(spu_opcode_t op)
|
||||
// // assuming that SP % 16 is always zero
|
||||
// const XmmLink& vr = XmmAlloc();
|
||||
// v128 value = v128::fromV(_mm_set_epi32(0x10111213, 0x14151617, 0x18191a1b, 0x1c1d1e1f));
|
||||
// value.u32r[(op.si7 >> 2) & 0x3] = 0x00010203;
|
||||
// value.u32r[(op.i7 >> 2) & 0x3] = 0x00010203;
|
||||
// c->movdqa(vr, XmmConst(value));
|
||||
// c->movdqa(SPU_OFF_128(gpr[op.rt]), vr);
|
||||
// return;
|
||||
//}
|
||||
|
||||
c->mov(*addr, SPU_OFF_32(gpr[op.ra]._u32[3]));
|
||||
if (op.si7) c->add(*addr, op.si7);
|
||||
if (op.i7) c->add(*addr, op.i7);
|
||||
c->not_(*addr);
|
||||
c->and_(*addr, 0xc);
|
||||
|
||||
@ -1318,14 +1315,14 @@ void spu_recompiler::CDD(spu_opcode_t op)
|
||||
// // assuming that SP % 16 is always zero
|
||||
// const XmmLink& vr = XmmAlloc();
|
||||
// v128 value = v128::fromV(_mm_set_epi32(0x10111213, 0x14151617, 0x18191a1b, 0x1c1d1e1f));
|
||||
// value.u64r[(op.si7 >> 3) & 0x1] = 0x0001020304050607ull;
|
||||
// value.u64r[(op.i7 >> 3) & 0x1] = 0x0001020304050607ull;
|
||||
// c->movdqa(vr, XmmConst(value));
|
||||
// c->movdqa(SPU_OFF_128(gpr[op.rt]), vr);
|
||||
// return;
|
||||
//}
|
||||
|
||||
c->mov(*addr, SPU_OFF_32(gpr[op.ra]._u32[3]));
|
||||
if (op.si7) c->add(*addr, op.si7);
|
||||
if (op.i7) c->add(*addr, op.i7);
|
||||
c->not_(*addr);
|
||||
c->and_(*addr, 0x8);
|
||||
|
||||
@ -1343,8 +1340,8 @@ void spu_recompiler::ROTQBII(spu_opcode_t op)
|
||||
c->mov(*qw0, SPU_OFF_64(gpr[op.ra]._u64[0]));
|
||||
c->mov(*qw1, SPU_OFF_64(gpr[op.ra]._u64[1]));
|
||||
c->mov(*qw2, *qw0);
|
||||
c->shld(*qw0, *qw1, op.si7 & 0x7);
|
||||
c->shld(*qw1, *qw2, op.si7 & 0x7);
|
||||
c->shld(*qw0, *qw1, op.i7 & 0x7);
|
||||
c->shld(*qw1, *qw2, op.i7 & 0x7);
|
||||
c->mov(SPU_OFF_64(gpr[op.rt]._u64[0]), *qw0);
|
||||
c->mov(SPU_OFF_64(gpr[op.rt]._u64[1]), *qw1);
|
||||
c->unuse(*qw0);
|
||||
@ -1356,8 +1353,8 @@ void spu_recompiler::ROTQMBII(spu_opcode_t op)
|
||||
{
|
||||
c->mov(*qw0, SPU_OFF_64(gpr[op.ra]._u64[0]));
|
||||
c->mov(*qw1, SPU_OFF_64(gpr[op.ra]._u64[1]));
|
||||
c->shrd(*qw0, *qw1, (0 - op.si7) & 0x7);
|
||||
c->shr(*qw1, (0 - op.si7) & 0x7);
|
||||
c->shrd(*qw0, *qw1, 0-op.i7 & 0x7);
|
||||
c->shr(*qw1, 0-op.i7 & 0x7);
|
||||
c->mov(SPU_OFF_64(gpr[op.rt]._u64[0]), *qw0);
|
||||
c->mov(SPU_OFF_64(gpr[op.rt]._u64[1]), *qw1);
|
||||
c->unuse(*qw0);
|
||||
@ -1368,8 +1365,8 @@ void spu_recompiler::SHLQBII(spu_opcode_t op)
|
||||
{
|
||||
c->mov(*qw0, SPU_OFF_64(gpr[op.ra]._u64[0]));
|
||||
c->mov(*qw1, SPU_OFF_64(gpr[op.ra]._u64[1]));
|
||||
c->shld(*qw1, *qw0, op.si7 & 0x7);
|
||||
c->shl(*qw0, op.si7 & 0x7);
|
||||
c->shld(*qw1, *qw0, op.i7 & 0x7);
|
||||
c->shl(*qw0, op.i7 & 0x7);
|
||||
c->mov(SPU_OFF_64(gpr[op.rt]._u64[0]), *qw0);
|
||||
c->mov(SPU_OFF_64(gpr[op.rt]._u64[1]), *qw1);
|
||||
c->unuse(*qw0);
|
||||
@ -1378,7 +1375,7 @@ void spu_recompiler::SHLQBII(spu_opcode_t op)
|
||||
|
||||
void spu_recompiler::ROTQBYI(spu_opcode_t op)
|
||||
{
|
||||
const int s = op.si7 & 0xf;
|
||||
const int s = op.i7 & 0xf;
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Int);
|
||||
c->palignr(va, va, 16 - s);
|
||||
c->movdqa(SPU_OFF_128(gpr[op.rt]), va);
|
||||
@ -1386,7 +1383,7 @@ void spu_recompiler::ROTQBYI(spu_opcode_t op)
|
||||
|
||||
void spu_recompiler::ROTQMBYI(spu_opcode_t op)
|
||||
{
|
||||
const int s = (0 - op.si7) & 0x1f;
|
||||
const int s = 0-op.i7 & 0x1f;
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Int);
|
||||
c->psrldq(va, s);
|
||||
c->movdqa(SPU_OFF_128(gpr[op.rt]), va);
|
||||
@ -1394,7 +1391,7 @@ void spu_recompiler::ROTQMBYI(spu_opcode_t op)
|
||||
|
||||
void spu_recompiler::SHLQBYI(spu_opcode_t op)
|
||||
{
|
||||
const int s = op.si7 & 0x1f;
|
||||
const int s = op.i7 & 0x1f;
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Int);
|
||||
c->pslldq(va, s);
|
||||
c->movdqa(SPU_OFF_128(gpr[op.rt]), va);
|
||||
@ -1968,7 +1965,7 @@ void spu_recompiler::CFLTS(spu_opcode_t op)
|
||||
{
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Float);
|
||||
const XmmLink& vi = XmmAlloc();
|
||||
if (op.si8 != 173) c->mulps(va, XmmConst(_mm_set1_ps(exp2f(static_cast<float>(173 - (op.si8 & 0xff)))))); // scale
|
||||
if (op.i8 != 173) c->mulps(va, XmmConst(_mm_set1_ps(exp2f(static_cast<s16>(173 - op.i8))))); // scale
|
||||
c->movaps(vi, XmmConst(_mm_set1_ps(exp2f(31))));
|
||||
c->cmpps(vi, va, 2);
|
||||
c->cvttps2dq(va, va); // convert to ints with truncation
|
||||
@ -1982,7 +1979,7 @@ void spu_recompiler::CFLTU(spu_opcode_t op)
|
||||
const XmmLink& vs = XmmAlloc();
|
||||
const XmmLink& vs2 = XmmAlloc();
|
||||
const XmmLink& vs3 = XmmAlloc();
|
||||
if (op.si8 != 173) c->mulps(va, XmmConst(_mm_set1_ps(exp2f(static_cast<float>(173 - (op.si8 & 0xff)))))); // scale
|
||||
if (op.i8 != 173) c->mulps(va, XmmConst(_mm_set1_ps(exp2f(static_cast<s16>(173 - op.i8))))); // scale
|
||||
c->maxps(va, XmmConst(_mm_set1_ps(0.0f))); // saturate
|
||||
c->movaps(vs, va); // copy scaled value
|
||||
c->movaps(vs2, va);
|
||||
@ -2002,7 +1999,7 @@ void spu_recompiler::CSFLT(spu_opcode_t op)
|
||||
{
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Int);
|
||||
c->cvtdq2ps(va, va); // convert to floats
|
||||
if (op.si8 != 155) c->mulps(va, XmmConst(_mm_set1_ps(exp2f(static_cast<float>((op.si8 & 0xff) - 155))))); // scale
|
||||
if (op.i8 != 155) c->mulps(va, XmmConst(_mm_set1_ps(exp2f(static_cast<s16>(op.i8 - 155))))); // scale
|
||||
c->movaps(SPU_OFF_128(gpr[op.rt]), va);
|
||||
}
|
||||
|
||||
@ -2016,13 +2013,15 @@ void spu_recompiler::CUFLT(spu_opcode_t op)
|
||||
c->psrad(v1, 31); // generate mask from sign bit
|
||||
c->andps(v1, XmmConst(_mm_set1_ps(exp2f(31)))); // generate correction component
|
||||
c->addps(va, v1); // add correction component
|
||||
if (op.si8 != 155) c->mulps(va, XmmConst(_mm_set1_ps(exp2f(static_cast<float>((op.si8 & 0xff) - 155))))); // scale
|
||||
if (op.i8 != 155) c->mulps(va, XmmConst(_mm_set1_ps(exp2f(static_cast<s16>(op.i8 - 155))))); // scale
|
||||
c->movaps(SPU_OFF_128(gpr[op.rt]), va);
|
||||
}
|
||||
|
||||
void spu_recompiler::BRZ(spu_opcode_t op)
|
||||
{
|
||||
const u32 target = spu_branch_target(m_pos, op.si16);
|
||||
const u32 target = spu_branch_target(m_pos, op.i16);
|
||||
|
||||
if (target == m_pos) throw EXCEPTION("Branch-to-self (0x%05x)", target);
|
||||
|
||||
c->cmp(SPU_OFF_32(gpr[op.rt]._u32[3]), 0);
|
||||
|
||||
@ -2045,16 +2044,16 @@ void spu_recompiler::BRZ(spu_opcode_t op)
|
||||
|
||||
void spu_recompiler::STQA(spu_opcode_t op)
|
||||
{
|
||||
const u32 lsa = (op.si16 << 2) & 0x3fff0;
|
||||
|
||||
const XmmLink& vt = XmmGet(op.rt, XmmType::Int);
|
||||
c->pshufb(vt, XmmConst(_mm_set_epi32(0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f)));
|
||||
c->movdqa(asmjit::host::oword_ptr(*ls, lsa), vt);
|
||||
c->movdqa(asmjit::host::oword_ptr(*ls, spu_ls_target(0, op.i16)), vt);
|
||||
}
|
||||
|
||||
void spu_recompiler::BRNZ(spu_opcode_t op)
|
||||
{
|
||||
const u32 target = spu_branch_target(m_pos, op.si16);
|
||||
const u32 target = spu_branch_target(m_pos, op.i16);
|
||||
|
||||
if (target == m_pos) throw EXCEPTION("Branch-to-self (0x%05x)", target);
|
||||
|
||||
c->cmp(SPU_OFF_32(gpr[op.rt]._u32[3]), 0);
|
||||
|
||||
@ -2077,7 +2076,9 @@ void spu_recompiler::BRNZ(spu_opcode_t op)
|
||||
|
||||
void spu_recompiler::BRHZ(spu_opcode_t op)
|
||||
{
|
||||
const u32 target = spu_branch_target(m_pos, op.si16);
|
||||
const u32 target = spu_branch_target(m_pos, op.i16);
|
||||
|
||||
if (target == m_pos) throw EXCEPTION("Branch-to-self (0x%05x)", target);
|
||||
|
||||
c->cmp(SPU_OFF_16(gpr[op.rt]._u16[6]), 0);
|
||||
|
||||
@ -2100,7 +2101,9 @@ void spu_recompiler::BRHZ(spu_opcode_t op)
|
||||
|
||||
void spu_recompiler::BRHNZ(spu_opcode_t op)
|
||||
{
|
||||
const u32 target = spu_branch_target(m_pos, op.si16);
|
||||
const u32 target = spu_branch_target(m_pos, op.i16);
|
||||
|
||||
if (target == m_pos) throw EXCEPTION("Branch-to-self (0x%05x)", target);
|
||||
|
||||
c->cmp(SPU_OFF_16(gpr[op.rt]._u16[6]), 0);
|
||||
|
||||
@ -2123,16 +2126,16 @@ void spu_recompiler::BRHNZ(spu_opcode_t op)
|
||||
|
||||
void spu_recompiler::STQR(spu_opcode_t op)
|
||||
{
|
||||
const u32 lsa = spu_branch_target(m_pos, op.si16) & 0x3fff0;
|
||||
|
||||
const XmmLink& vt = XmmGet(op.rt, XmmType::Int);
|
||||
c->pshufb(vt, XmmConst(_mm_set_epi32(0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f)));
|
||||
c->movdqa(asmjit::host::oword_ptr(*ls, lsa), vt);
|
||||
c->movdqa(asmjit::host::oword_ptr(*ls, spu_ls_target(m_pos, op.i16)), vt);
|
||||
}
|
||||
|
||||
void spu_recompiler::BRA(spu_opcode_t op)
|
||||
{
|
||||
const u32 target = spu_branch_target(0, op.si16);
|
||||
const u32 target = spu_branch_target(0, op.i16);
|
||||
|
||||
if (target == m_pos) throw EXCEPTION("Branch-to-self (0x%05x)", target);
|
||||
|
||||
if (labels[target / 4].isInitialized())
|
||||
{
|
||||
@ -2153,22 +2156,22 @@ void spu_recompiler::BRA(spu_opcode_t op)
|
||||
|
||||
void spu_recompiler::LQA(spu_opcode_t op)
|
||||
{
|
||||
const u32 lsa = (op.si16 << 2) & 0x3fff0;
|
||||
|
||||
const XmmLink& vt = XmmAlloc();
|
||||
c->movdqa(vt, asmjit::host::oword_ptr(*ls, lsa));
|
||||
c->movdqa(vt, asmjit::host::oword_ptr(*ls, spu_ls_target(0, op.i16)));
|
||||
c->pshufb(vt, XmmConst(_mm_set_epi32(0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f)));
|
||||
c->movdqa(SPU_OFF_128(gpr[op.rt]), vt);
|
||||
}
|
||||
|
||||
void spu_recompiler::BRASL(spu_opcode_t op)
|
||||
{
|
||||
const u32 target = spu_branch_target(0, op.si16);
|
||||
const u32 target = spu_branch_target(0, op.i16);
|
||||
|
||||
if (target == m_pos) throw EXCEPTION("Branch-to-self (0x%05x)", target);
|
||||
|
||||
const XmmLink& vr = XmmAlloc();
|
||||
c->movdqa(vr, XmmConst(_mm_set_epi32(spu_branch_target(m_pos + 4), 0, 0, 0)));
|
||||
c->movdqa(SPU_OFF_128(gpr[op.rt]), vr);
|
||||
c->unuse(*vr.m_var);
|
||||
c->unuse(vr);
|
||||
|
||||
c->mov(SPU_OFF_32(pc), target);
|
||||
|
||||
@ -2177,7 +2180,18 @@ void spu_recompiler::BRASL(spu_opcode_t op)
|
||||
|
||||
void spu_recompiler::BR(spu_opcode_t op)
|
||||
{
|
||||
const u32 target = spu_branch_target(m_pos, op.si16);
|
||||
const u32 target = spu_branch_target(m_pos, op.i16);
|
||||
|
||||
if (target == m_pos)
|
||||
{
|
||||
c->mov(*addr, target | 0x2000000);
|
||||
//c->cmp(asmjit::host::dword_ptr(*ls, m_pos), 0x32); // compare instruction opcode with BR-to-self
|
||||
//c->je(labels[target / 4]);
|
||||
c->lock().or_(SPU_OFF_64(m_state), CPU_STATE_RETURN | CPU_STATE_STOPPED);
|
||||
c->jmp(*end);
|
||||
c->unuse(*addr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (labels[target / 4].isInitialized())
|
||||
{
|
||||
@ -2199,18 +2213,20 @@ void spu_recompiler::BR(spu_opcode_t op)
|
||||
void spu_recompiler::FSMBI(spu_opcode_t op)
|
||||
{
|
||||
const XmmLink& vr = XmmAlloc();
|
||||
c->movdqa(vr, XmmConst(g_spu_imm.fsmb[op.si16 & 0xffff]));
|
||||
c->movdqa(vr, XmmConst(g_spu_imm.fsmb[op.i16]));
|
||||
c->movdqa(SPU_OFF_128(gpr[op.rt]), vr);
|
||||
}
|
||||
|
||||
void spu_recompiler::BRSL(spu_opcode_t op)
|
||||
{
|
||||
const u32 target = spu_branch_target(m_pos, op.si16);
|
||||
const u32 target = spu_branch_target(m_pos, op.i16);
|
||||
|
||||
if (target == m_pos) throw EXCEPTION("Branch-to-self (0x%05x)", target);
|
||||
|
||||
const XmmLink& vr = XmmAlloc();
|
||||
c->movdqa(vr, XmmConst(_mm_set_epi32(spu_branch_target(m_pos + 4), 0, 0, 0)));
|
||||
c->movdqa(SPU_OFF_128(gpr[op.rt]), vr);
|
||||
c->unuse(*vr.m_var);
|
||||
c->unuse(vr);
|
||||
|
||||
if (target == spu_branch_target(m_pos + 4))
|
||||
{
|
||||
@ -2225,10 +2241,8 @@ void spu_recompiler::BRSL(spu_opcode_t op)
|
||||
|
||||
void spu_recompiler::LQR(spu_opcode_t op)
|
||||
{
|
||||
const u32 lsa = spu_branch_target(m_pos, op.si16) & 0x3fff0;
|
||||
|
||||
const XmmLink& vt = XmmAlloc();
|
||||
c->movdqa(vt, asmjit::host::oword_ptr(*ls, lsa));
|
||||
c->movdqa(vt, asmjit::host::oword_ptr(*ls, spu_ls_target(m_pos, op.i16)));
|
||||
c->pshufb(vt, XmmConst(_mm_set_epi32(0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f)));
|
||||
c->movdqa(SPU_OFF_128(gpr[op.rt]), vt);
|
||||
}
|
||||
@ -2243,14 +2257,14 @@ void spu_recompiler::IL(spu_opcode_t op)
|
||||
void spu_recompiler::ILHU(spu_opcode_t op)
|
||||
{
|
||||
const XmmLink& vr = XmmAlloc();
|
||||
c->movdqa(vr, XmmConst(_mm_set1_epi32(op.si16 << 16)));
|
||||
c->movdqa(vr, XmmConst(_mm_set1_epi32(op.i16 << 16)));
|
||||
c->movdqa(SPU_OFF_128(gpr[op.rt]), vr);
|
||||
}
|
||||
|
||||
void spu_recompiler::ILH(spu_opcode_t op)
|
||||
{
|
||||
const XmmLink& vr = XmmAlloc();
|
||||
c->movdqa(vr, XmmConst(_mm_set1_epi16(op.si16)));
|
||||
c->movdqa(vr, XmmConst(_mm_set1_epi16(op.i16)));
|
||||
c->movdqa(SPU_OFF_128(gpr[op.rt]), vr);
|
||||
}
|
||||
|
||||
@ -2516,16 +2530,16 @@ void spu_recompiler::ILA(spu_opcode_t op)
|
||||
void spu_recompiler::SELB(spu_opcode_t op)
|
||||
{
|
||||
const XmmLink& vb = XmmGet(op.rb, XmmType::Int);
|
||||
const XmmLink& vc = XmmGet(op.rt, XmmType::Int);
|
||||
const XmmLink& vc = XmmGet(op.rc, XmmType::Int);
|
||||
c->pand(vb, vc);
|
||||
c->pandn(vc, SPU_OFF_128(gpr[op.ra]));
|
||||
c->por(vb, vc);
|
||||
c->movdqa(SPU_OFF_128(gpr[op.rc]), vb);
|
||||
c->movdqa(SPU_OFF_128(gpr[op.rt4]), vb);
|
||||
}
|
||||
|
||||
void spu_recompiler::SHUFB(spu_opcode_t op)
|
||||
{
|
||||
const XmmLink& v0 = XmmGet(op.rt, XmmType::Int); // v0 = mask
|
||||
const XmmLink& v0 = XmmGet(op.rc, XmmType::Int); // v0 = mask
|
||||
const XmmLink& v1 = XmmAlloc();
|
||||
const XmmLink& v2 = XmmAlloc();
|
||||
const XmmLink& v3 = XmmAlloc();
|
||||
@ -2559,7 +2573,7 @@ void spu_recompiler::SHUFB(spu_opcode_t op)
|
||||
c->por(v1, v3); // v1 = select(op.rb, 00001111 - ((mask & 00011111) ^ 00010000)) | (v3)
|
||||
c->pandn(v4, v1); // filter result v4 = v1 & ((mask & 10000000 == 10000000) ? 0 : 0xff)
|
||||
c->por(vFF, v4); // final merge vFF = (mask & 10000000 == 10000000) ? ((mask & 11100000 == 11000000) ? 0xff : (mask & 11100000 == 11100000) ? 0x80 : 0) : (v1)
|
||||
c->movdqa(SPU_OFF_128(gpr[op.rc]), vFF);
|
||||
c->movdqa(SPU_OFF_128(gpr[op.rt4]), vFF);
|
||||
}
|
||||
|
||||
void spu_recompiler::MPYA(spu_opcode_t op)
|
||||
@ -2571,33 +2585,33 @@ void spu_recompiler::MPYA(spu_opcode_t op)
|
||||
c->pand(va, vi);
|
||||
c->pand(vb, vi);
|
||||
c->pmaddwd(va, vb);
|
||||
c->paddd(va, SPU_OFF_128(gpr[op.rt]));
|
||||
c->movdqa(SPU_OFF_128(gpr[op.rc]), va);
|
||||
c->paddd(va, SPU_OFF_128(gpr[op.rc]));
|
||||
c->movdqa(SPU_OFF_128(gpr[op.rt4]), va);
|
||||
}
|
||||
|
||||
void spu_recompiler::FNMS(spu_opcode_t op)
|
||||
{
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Float);
|
||||
const XmmLink& vc = XmmGet(op.rt, XmmType::Float);
|
||||
const XmmLink& vc = XmmGet(op.rc, XmmType::Float);
|
||||
c->mulps(va, SPU_OFF_128(gpr[op.rb]));
|
||||
c->subps(vc, va);
|
||||
c->movaps(SPU_OFF_128(gpr[op.rc]), vc);
|
||||
c->movaps(SPU_OFF_128(gpr[op.rt4]), vc);
|
||||
}
|
||||
|
||||
void spu_recompiler::FMA(spu_opcode_t op)
|
||||
{
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Float);
|
||||
c->mulps(va, SPU_OFF_128(gpr[op.rb]));
|
||||
c->addps(va, SPU_OFF_128(gpr[op.rt]));
|
||||
c->movaps(SPU_OFF_128(gpr[op.rc]), va);
|
||||
c->addps(va, SPU_OFF_128(gpr[op.rc]));
|
||||
c->movaps(SPU_OFF_128(gpr[op.rt4]), va);
|
||||
}
|
||||
|
||||
void spu_recompiler::FMS(spu_opcode_t op)
|
||||
{
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Float);
|
||||
c->mulps(va, SPU_OFF_128(gpr[op.rb]));
|
||||
c->subps(va, SPU_OFF_128(gpr[op.rt]));
|
||||
c->movaps(SPU_OFF_128(gpr[op.rc]), va);
|
||||
c->subps(va, SPU_OFF_128(gpr[op.rc]));
|
||||
c->movaps(SPU_OFF_128(gpr[op.rt4]), va);
|
||||
}
|
||||
|
||||
void spu_recompiler::UNK(spu_opcode_t op)
|
||||
|
@ -44,27 +44,18 @@ private:
|
||||
|
||||
class XmmLink
|
||||
{
|
||||
friend class spu_recompiler;
|
||||
|
||||
asmjit::X86XmmVar* const m_var;
|
||||
asmjit::X86XmmVar* m_var;
|
||||
|
||||
public:
|
||||
XmmLink(asmjit::X86XmmVar*& xmm_var)
|
||||
: m_var(xmm_var)
|
||||
{
|
||||
xmm_var = nullptr;
|
||||
}
|
||||
|
||||
public:
|
||||
XmmLink() = delete;
|
||||
XmmLink(XmmLink&&) = default; // MoveConstructible + delete copy constructor and copy/move operators
|
||||
|
||||
XmmLink(const XmmLink&) = delete;
|
||||
|
||||
XmmLink(XmmLink&& right)
|
||||
: m_var(right.m_var)
|
||||
{
|
||||
}
|
||||
|
||||
inline operator const asmjit::X86XmmVar&() const
|
||||
operator asmjit::X86XmmVar&() const
|
||||
{
|
||||
return *m_var;
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ const spu_opcode_table_t<spu_itype_t> g_spu_itype{ DEFINE_SPU_OPCODES(spu_itype:
|
||||
|
||||
std::shared_ptr<spu_function_t> SPUDatabase::find(const be_t<u32>* data, u64 key, u32 max_size)
|
||||
{
|
||||
for (auto found = m_db.find(key); found != m_db.end(); found++)
|
||||
for (auto found = m_db.find(key); found != m_db.end() && found->first == key; found++)
|
||||
{
|
||||
if (found->second->size > max_size)
|
||||
{
|
||||
@ -249,7 +249,7 @@ std::shared_ptr<spu_function_t> SPUDatabase::analyse(const be_t<u32>* ls, u32 en
|
||||
}
|
||||
else // Other instructions (writing rt reg)
|
||||
{
|
||||
const u32 rt = type == SELB || type == SHUFB || type == MPYA || type == FNMS || type == FMA || type == FMS ? op.rc : op.rt;
|
||||
const u32 rt = type == SELB || type == SHUFB || type == MPYA || type == FNMS || type == FMA || type == FMS ? +op.rc : +op.rt;
|
||||
|
||||
// Analyse link register access
|
||||
if (rt == 0)
|
||||
|
@ -300,7 +300,7 @@ private:
|
||||
}
|
||||
void STOPD(spu_opcode_t op)
|
||||
{
|
||||
DisAsm("bihnz", spu_reg_name[op.rc], spu_reg_name[op.ra], spu_reg_name[op.rb]);
|
||||
DisAsm("stopd", spu_reg_name[op.rc], spu_reg_name[op.ra], spu_reg_name[op.rb]);
|
||||
}
|
||||
void STQX(spu_opcode_t op)
|
||||
{
|
||||
@ -698,73 +698,73 @@ private:
|
||||
//0 - 9
|
||||
void CFLTS(spu_opcode_t op)
|
||||
{
|
||||
DisAsm("cflts", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si8);
|
||||
DisAsm("cflts", spu_reg_name[op.rt], spu_reg_name[op.ra], op.i8);
|
||||
}
|
||||
void CFLTU(spu_opcode_t op)
|
||||
{
|
||||
DisAsm("cfltu", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si8);
|
||||
DisAsm("cfltu", spu_reg_name[op.rt], spu_reg_name[op.ra], op.i8);
|
||||
}
|
||||
void CSFLT(spu_opcode_t op)
|
||||
{
|
||||
DisAsm("csflt", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si8);
|
||||
DisAsm("csflt", spu_reg_name[op.rt], spu_reg_name[op.ra], op.i8);
|
||||
}
|
||||
void CUFLT(spu_opcode_t op)
|
||||
{
|
||||
DisAsm("cuflt", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si8);
|
||||
DisAsm("cuflt", spu_reg_name[op.rt], spu_reg_name[op.ra], op.i8);
|
||||
}
|
||||
|
||||
//0 - 8
|
||||
void BRZ(spu_opcode_t op)
|
||||
{
|
||||
DisAsm("brz", spu_reg_name[op.rt], DisAsmBranchTarget(op.si16));
|
||||
DisAsm("brz", spu_reg_name[op.rt], DisAsmBranchTarget(op.i16));
|
||||
}
|
||||
void STQA(spu_opcode_t op)
|
||||
{
|
||||
DisAsm("stqa", spu_reg_name[op.rt], DisAsmBranchTarget(op.si16));
|
||||
DisAsm("stqa", spu_reg_name[op.rt], DisAsmBranchTarget(op.i16));
|
||||
}
|
||||
void BRNZ(spu_opcode_t op)
|
||||
{
|
||||
DisAsm("brnz", spu_reg_name[op.rt], DisAsmBranchTarget(op.si16));
|
||||
DisAsm("brnz", spu_reg_name[op.rt], DisAsmBranchTarget(op.i16));
|
||||
}
|
||||
void BRHZ(spu_opcode_t op)
|
||||
{
|
||||
DisAsm("brhz", spu_reg_name[op.rt], DisAsmBranchTarget(op.si16));
|
||||
DisAsm("brhz", spu_reg_name[op.rt], DisAsmBranchTarget(op.i16));
|
||||
}
|
||||
void BRHNZ(spu_opcode_t op)
|
||||
{
|
||||
DisAsm("brhnz", spu_reg_name[op.rt], DisAsmBranchTarget(op.si16));
|
||||
DisAsm("brhnz", spu_reg_name[op.rt], DisAsmBranchTarget(op.i16));
|
||||
}
|
||||
void STQR(spu_opcode_t op)
|
||||
{
|
||||
DisAsm("stqr", spu_reg_name[op.rt], DisAsmBranchTarget(op.si16));
|
||||
DisAsm("stqr", spu_reg_name[op.rt], DisAsmBranchTarget(op.i16));
|
||||
}
|
||||
void BRA(spu_opcode_t op)
|
||||
{
|
||||
DisAsm("bra", DisAsmBranchTarget(op.si16));
|
||||
DisAsm("bra", DisAsmBranchTarget(op.i16));
|
||||
}
|
||||
void LQA(spu_opcode_t op)
|
||||
{
|
||||
DisAsm("lqa", spu_reg_name[op.rt], DisAsmBranchTarget(op.si16));
|
||||
DisAsm("lqa", spu_reg_name[op.rt], DisAsmBranchTarget(op.i16));
|
||||
}
|
||||
void BRASL(spu_opcode_t op)
|
||||
{
|
||||
DisAsm("brasl", spu_reg_name[op.rt], DisAsmBranchTarget(op.si16));
|
||||
DisAsm("brasl", spu_reg_name[op.rt], DisAsmBranchTarget(op.i16));
|
||||
}
|
||||
void BR(spu_opcode_t op)
|
||||
{
|
||||
DisAsm("br", DisAsmBranchTarget(op.si16));
|
||||
DisAsm("br", DisAsmBranchTarget(op.i16));
|
||||
}
|
||||
void FSMBI(spu_opcode_t op)
|
||||
{
|
||||
DisAsm("fsmbi", spu_reg_name[op.rt], op.si16);
|
||||
DisAsm("fsmbi", spu_reg_name[op.rt], op.i16);
|
||||
}
|
||||
void BRSL(spu_opcode_t op)
|
||||
{
|
||||
DisAsm("brsl", spu_reg_name[op.rt], DisAsmBranchTarget(op.si16));
|
||||
DisAsm("brsl", spu_reg_name[op.rt], DisAsmBranchTarget(op.i16));
|
||||
}
|
||||
void LQR(spu_opcode_t op)
|
||||
{
|
||||
DisAsm("lqr", spu_reg_name[op.rt], DisAsmBranchTarget(op.si16));
|
||||
DisAsm("lqr", spu_reg_name[op.rt], DisAsmBranchTarget(op.i16));
|
||||
}
|
||||
void IL(spu_opcode_t op)
|
||||
{
|
||||
@ -772,15 +772,15 @@ private:
|
||||
}
|
||||
void ILHU(spu_opcode_t op)
|
||||
{
|
||||
DisAsm("ilhu", spu_reg_name[op.rt], op.si16);
|
||||
DisAsm("ilhu", spu_reg_name[op.rt], op.i16);
|
||||
}
|
||||
void ILH(spu_opcode_t op)
|
||||
{
|
||||
DisAsm("ilh", spu_reg_name[op.rt], op.si16);
|
||||
DisAsm("ilh", spu_reg_name[op.rt], op.i16);
|
||||
}
|
||||
void IOHL(spu_opcode_t op)
|
||||
{
|
||||
DisAsm("iohl", spu_reg_name[op.rt], op.si16);
|
||||
DisAsm("iohl", spu_reg_name[op.rt], op.i16);
|
||||
}
|
||||
|
||||
//0 - 7
|
||||
@ -904,41 +904,41 @@ private:
|
||||
//0 - 6
|
||||
void HBRA(spu_opcode_t op)
|
||||
{
|
||||
DisAsm("hbra", DisAsmBranchTarget((op.r0h << 7) | op.rt), DisAsmBranchTarget(op.si16));
|
||||
DisAsm("hbra", DisAsmBranchTarget((op.r0h << 7) | op.rt), DisAsmBranchTarget(op.i16));
|
||||
}
|
||||
void HBRR(spu_opcode_t op)
|
||||
{
|
||||
DisAsm("hbrr", DisAsmBranchTarget((op.r0h << 7) | op.rt), DisAsmBranchTarget(op.si16));
|
||||
DisAsm("hbrr", DisAsmBranchTarget((op.r0h << 7) | op.rt), DisAsmBranchTarget(op.i16));
|
||||
}
|
||||
void ILA(spu_opcode_t op)
|
||||
{
|
||||
DisAsm("ila", spu_reg_name[op.rt], op.i18);
|
||||
}
|
||||
|
||||
//0 - 3, rt <> rc
|
||||
//0 - 3
|
||||
void SELB(spu_opcode_t op)
|
||||
{
|
||||
DisAsm("selb", spu_reg_name[op.rc], spu_reg_name[op.ra], spu_reg_name[op.rb], spu_reg_name[op.rt]);
|
||||
DisAsm("selb", spu_reg_name[op.rt4], spu_reg_name[op.ra], spu_reg_name[op.rb], spu_reg_name[op.rc]);
|
||||
}
|
||||
void SHUFB(spu_opcode_t op)
|
||||
{
|
||||
DisAsm("shufb", spu_reg_name[op.rc], spu_reg_name[op.ra], spu_reg_name[op.rb], spu_reg_name[op.rt]);
|
||||
DisAsm("shufb", spu_reg_name[op.rt4], spu_reg_name[op.ra], spu_reg_name[op.rb], spu_reg_name[op.rc]);
|
||||
}
|
||||
void MPYA(spu_opcode_t op)
|
||||
{
|
||||
DisAsm("mpya", spu_reg_name[op.rc], spu_reg_name[op.ra], spu_reg_name[op.rb], spu_reg_name[op.rt]);
|
||||
DisAsm("mpya", spu_reg_name[op.rt4], spu_reg_name[op.ra], spu_reg_name[op.rb], spu_reg_name[op.rc]);
|
||||
}
|
||||
void FNMS(spu_opcode_t op)
|
||||
{
|
||||
DisAsm("fnms", spu_reg_name[op.rc], spu_reg_name[op.ra], spu_reg_name[op.rb], spu_reg_name[op.rt]);
|
||||
DisAsm("fnms", spu_reg_name[op.rt4], spu_reg_name[op.ra], spu_reg_name[op.rb], spu_reg_name[op.rc]);
|
||||
}
|
||||
void FMA(spu_opcode_t op)
|
||||
{
|
||||
DisAsm("fma", spu_reg_name[op.rc], spu_reg_name[op.ra], spu_reg_name[op.rb], spu_reg_name[op.rt]);
|
||||
DisAsm("fma", spu_reg_name[op.rt4], spu_reg_name[op.ra], spu_reg_name[op.rb], spu_reg_name[op.rc]);
|
||||
}
|
||||
void FMS(spu_opcode_t op)
|
||||
{
|
||||
DisAsm("fms", spu_reg_name[op.rc], spu_reg_name[op.ra], spu_reg_name[op.rb], spu_reg_name[op.rt]);
|
||||
DisAsm("fms", spu_reg_name[op.rt4], spu_reg_name[op.ra], spu_reg_name[op.rb], spu_reg_name[op.rc]);
|
||||
}
|
||||
|
||||
void UNK(spu_opcode_t op)
|
||||
@ -949,7 +949,7 @@ private:
|
||||
static const spu_opcode_table_t<void(SPUDisAsm::*)(spu_opcode_t)> opcodes;
|
||||
|
||||
public:
|
||||
inline void do_disasm(u32 opcode)
|
||||
void do_disasm(u32 opcode)
|
||||
{
|
||||
(this->*opcodes[opcode])({ opcode });
|
||||
}
|
||||
|
@ -210,45 +210,45 @@ void spu_interpreter::SHLH(SPUThread& spu, spu_opcode_t op)
|
||||
void spu_interpreter::ROTI(SPUThread& spu, spu_opcode_t op)
|
||||
{
|
||||
const auto a = spu.gpr[op.ra].vi;
|
||||
const s32 n = op.si7 & 0x1f;
|
||||
const s32 n = op.i7 & 0x1f;
|
||||
spu.gpr[op.rt].vi = _mm_or_si128(_mm_slli_epi32(a, n), _mm_srli_epi32(a, 32 - n));
|
||||
}
|
||||
|
||||
void spu_interpreter::ROTMI(SPUThread& spu, spu_opcode_t op)
|
||||
{
|
||||
spu.gpr[op.rt].vi = _mm_srli_epi32(spu.gpr[op.ra].vi, -op.si7 & 0x3f);
|
||||
spu.gpr[op.rt].vi = _mm_srli_epi32(spu.gpr[op.ra].vi, 0-op.i7 & 0x3f);
|
||||
}
|
||||
|
||||
void spu_interpreter::ROTMAI(SPUThread& spu, spu_opcode_t op)
|
||||
{
|
||||
spu.gpr[op.rt].vi = _mm_srai_epi32(spu.gpr[op.ra].vi, -op.si7 & 0x3f);
|
||||
spu.gpr[op.rt].vi = _mm_srai_epi32(spu.gpr[op.ra].vi, 0-op.i7 & 0x3f);
|
||||
}
|
||||
|
||||
void spu_interpreter::SHLI(SPUThread& spu, spu_opcode_t op)
|
||||
{
|
||||
spu.gpr[op.rt].vi = _mm_slli_epi32(spu.gpr[op.ra].vi, op.si7 & 0x3f);
|
||||
spu.gpr[op.rt].vi = _mm_slli_epi32(spu.gpr[op.ra].vi, op.i7 & 0x3f);
|
||||
}
|
||||
|
||||
void spu_interpreter::ROTHI(SPUThread& spu, spu_opcode_t op)
|
||||
{
|
||||
const auto a = spu.gpr[op.ra].vi;
|
||||
const s32 n = op.si7 & 0xf;
|
||||
const s32 n = op.i7 & 0xf;
|
||||
spu.gpr[op.rt].vi = _mm_or_si128(_mm_slli_epi16(a, n), _mm_srli_epi16(a, 16 - n));
|
||||
}
|
||||
|
||||
void spu_interpreter::ROTHMI(SPUThread& spu, spu_opcode_t op)
|
||||
{
|
||||
spu.gpr[op.rt].vi = _mm_srli_epi16(spu.gpr[op.ra].vi, -op.si7 & 0x1f);
|
||||
spu.gpr[op.rt].vi = _mm_srli_epi16(spu.gpr[op.ra].vi, 0-op.i7 & 0x1f);
|
||||
}
|
||||
|
||||
void spu_interpreter::ROTMAHI(SPUThread& spu, spu_opcode_t op)
|
||||
{
|
||||
spu.gpr[op.rt].vi = _mm_srai_epi16(spu.gpr[op.ra].vi, -op.si7 & 0x1f);
|
||||
spu.gpr[op.rt].vi = _mm_srai_epi16(spu.gpr[op.ra].vi, 0-op.i7 & 0x1f);
|
||||
}
|
||||
|
||||
void spu_interpreter::SHLHI(SPUThread& spu, spu_opcode_t op)
|
||||
{
|
||||
spu.gpr[op.rt].vi = _mm_slli_epi16(spu.gpr[op.ra].vi, op.si7 & 0x1f);
|
||||
spu.gpr[op.rt].vi = _mm_slli_epi16(spu.gpr[op.ra].vi, op.i7 & 0x1f);
|
||||
}
|
||||
|
||||
void spu_interpreter::A(SPUThread& spu, spu_opcode_t op)
|
||||
@ -336,7 +336,7 @@ void spu_interpreter::STOPD(SPUThread& spu, spu_opcode_t op)
|
||||
|
||||
void spu_interpreter::STQX(SPUThread& spu, spu_opcode_t op)
|
||||
{
|
||||
spu.write128((spu.gpr[op.ra]._u32[3] + spu.gpr[op.rb]._u32[3]) & 0x3fff0, spu.gpr[op.rt]);
|
||||
spu._ref<v128>((spu.gpr[op.ra]._u32[3] + spu.gpr[op.rb]._u32[3]) & 0x3fff0) = spu.gpr[op.rt];
|
||||
}
|
||||
|
||||
void spu_interpreter::BI(SPUThread& spu, spu_opcode_t op)
|
||||
@ -410,7 +410,7 @@ void spu_interpreter::fast::FRSQEST(SPUThread& spu, spu_opcode_t op)
|
||||
|
||||
void spu_interpreter::LQX(SPUThread& spu, spu_opcode_t op)
|
||||
{
|
||||
spu.gpr[op.rt] = spu.read128((spu.gpr[op.ra]._u32[3] + spu.gpr[op.rb]._u32[3]) & 0x3fff0);
|
||||
spu.gpr[op.rt] = spu._ref<v128>((spu.gpr[op.ra]._u32[3] + spu.gpr[op.rb]._u32[3]) & 0x3fff0);
|
||||
}
|
||||
|
||||
void spu_interpreter::ROTQBYBI(SPUThread& spu, spu_opcode_t op)
|
||||
@ -575,7 +575,7 @@ void spu_interpreter::ROTQBII(SPUThread& spu, spu_opcode_t op)
|
||||
void spu_interpreter::ROTQMBII(SPUThread& spu, spu_opcode_t op)
|
||||
{
|
||||
const auto a = spu.gpr[op.ra].vi;
|
||||
const s32 n = -op.si7 & 0x7;
|
||||
const s32 n = 0-op.i7 & 0x7;
|
||||
spu.gpr[op.rt].vi = _mm_or_si128(_mm_srli_epi64(a, n), _mm_slli_epi64(_mm_srli_si128(a, 8), 64 - n));
|
||||
}
|
||||
|
||||
@ -593,7 +593,7 @@ void spu_interpreter::ROTQBYI(SPUThread& spu, spu_opcode_t op)
|
||||
|
||||
void spu_interpreter::ROTQMBYI(SPUThread& spu, spu_opcode_t op)
|
||||
{
|
||||
spu.gpr[op.rt].vi = _mm_shuffle_epi8(spu.gpr[op.ra].vi, g_spu_imm.srdq_pshufb[-op.si7 & 0x1f].vi);
|
||||
spu.gpr[op.rt].vi = _mm_shuffle_epi8(spu.gpr[op.ra].vi, g_spu_imm.srdq_pshufb[0-op.i7 & 0x1f].vi);
|
||||
}
|
||||
|
||||
void spu_interpreter::SHLQBYI(SPUThread& spu, spu_opcode_t op)
|
||||
@ -977,7 +977,7 @@ void spu_interpreter::BRZ(SPUThread& spu, spu_opcode_t op)
|
||||
|
||||
void spu_interpreter::STQA(SPUThread& spu, spu_opcode_t op)
|
||||
{
|
||||
spu.write128((op.i16 << 2) & 0x3fff0, spu.gpr[op.rt]);
|
||||
spu._ref<v128>(spu_ls_target(0, op.i16)) = spu.gpr[op.rt];
|
||||
}
|
||||
|
||||
void spu_interpreter::BRNZ(SPUThread& spu, spu_opcode_t op)
|
||||
@ -1006,7 +1006,7 @@ void spu_interpreter::BRHNZ(SPUThread& spu, spu_opcode_t op)
|
||||
|
||||
void spu_interpreter::STQR(SPUThread& spu, spu_opcode_t op)
|
||||
{
|
||||
spu.write128(spu_branch_target(spu.pc, op.i16) & 0x3fff0, spu.gpr[op.rt]);
|
||||
spu._ref<v128>(spu_ls_target(spu.pc, op.i16)) = spu.gpr[op.rt];
|
||||
}
|
||||
|
||||
void spu_interpreter::BRA(SPUThread& spu, spu_opcode_t op)
|
||||
@ -1016,7 +1016,7 @@ void spu_interpreter::BRA(SPUThread& spu, spu_opcode_t op)
|
||||
|
||||
void spu_interpreter::LQA(SPUThread& spu, spu_opcode_t op)
|
||||
{
|
||||
spu.gpr[op.rt] = spu.read128((op.i16 << 2) & 0x3fff0);
|
||||
spu.gpr[op.rt] = spu._ref<v128>(spu_ls_target(0, op.i16));
|
||||
}
|
||||
|
||||
void spu_interpreter::BRASL(SPUThread& spu, spu_opcode_t op)
|
||||
@ -1045,7 +1045,7 @@ void spu_interpreter::BRSL(SPUThread& spu, spu_opcode_t op)
|
||||
|
||||
void spu_interpreter::LQR(SPUThread& spu, spu_opcode_t op)
|
||||
{
|
||||
spu.gpr[op.rt] = spu.read128(spu_branch_target(spu.pc, op.i16) & 0x3fff0);
|
||||
spu.gpr[op.rt] = spu._ref<v128>(spu_ls_target(spu.pc, op.i16));
|
||||
}
|
||||
|
||||
void spu_interpreter::IL(SPUThread& spu, spu_opcode_t op)
|
||||
@ -1121,12 +1121,12 @@ void spu_interpreter::AHI(SPUThread& spu, spu_opcode_t op)
|
||||
|
||||
void spu_interpreter::STQD(SPUThread& spu, spu_opcode_t op)
|
||||
{
|
||||
spu.write128((spu.gpr[op.ra]._s32[3] + (op.si10 << 4)) & 0x3fff0, spu.gpr[op.rt]);
|
||||
spu._ref<v128>((spu.gpr[op.ra]._s32[3] + (op.si10 << 4)) & 0x3fff0) = spu.gpr[op.rt];
|
||||
}
|
||||
|
||||
void spu_interpreter::LQD(SPUThread& spu, spu_opcode_t op)
|
||||
{
|
||||
spu.gpr[op.rt] = spu.read128((spu.gpr[op.ra]._s32[3] + (op.si10 << 4)) & 0x3fff0);
|
||||
spu.gpr[op.rt] = spu._ref<v128>((spu.gpr[op.ra]._s32[3] + (op.si10 << 4)) & 0x3fff0);
|
||||
}
|
||||
|
||||
void spu_interpreter::XORI(SPUThread& spu, spu_opcode_t op)
|
||||
@ -1242,14 +1242,12 @@ void spu_interpreter::ILA(SPUThread& spu, spu_opcode_t op)
|
||||
|
||||
void spu_interpreter::SELB(SPUThread& spu, spu_opcode_t op)
|
||||
{
|
||||
// rt <> rc
|
||||
spu.gpr[op.rc] = (spu.gpr[op.rt] & spu.gpr[op.rb]) | v128::andnot(spu.gpr[op.rt], spu.gpr[op.ra]);
|
||||
spu.gpr[op.rt4] = (spu.gpr[op.rc] & spu.gpr[op.rb]) | v128::andnot(spu.gpr[op.rc], spu.gpr[op.ra]);
|
||||
}
|
||||
|
||||
void spu_interpreter::SHUFB(SPUThread& spu, spu_opcode_t op)
|
||||
{
|
||||
// rt <> rc
|
||||
const auto index = _mm_xor_si128(spu.gpr[op.rt].vi, _mm_set1_epi32(0x0f0f0f0f));
|
||||
const auto index = _mm_xor_si128(spu.gpr[op.rc].vi, _mm_set1_epi32(0x0f0f0f0f));
|
||||
const auto res1 = _mm_shuffle_epi8(spu.gpr[op.ra].vi, index);
|
||||
const auto bit4 = _mm_set1_epi32(0x10101010);
|
||||
const auto k1 = _mm_cmpeq_epi8(_mm_and_si128(index, bit4), bit4);
|
||||
@ -1259,32 +1257,28 @@ void spu_interpreter::SHUFB(SPUThread& spu, spu_opcode_t op)
|
||||
const auto res3 = _mm_or_si128(res2, k2);
|
||||
const auto bit567 = _mm_set1_epi32(0xe0e0e0e0);
|
||||
const auto k3 = _mm_cmpeq_epi8(_mm_and_si128(index, bit567), bit567);
|
||||
spu.gpr[op.rc].vi = _mm_sub_epi8(res3, _mm_and_si128(k3, _mm_set1_epi32(0x7f7f7f7f)));
|
||||
spu.gpr[op.rt4].vi = _mm_sub_epi8(res3, _mm_and_si128(k3, _mm_set1_epi32(0x7f7f7f7f)));
|
||||
}
|
||||
|
||||
void spu_interpreter::MPYA(SPUThread& spu, spu_opcode_t op)
|
||||
{
|
||||
// rt <> rc
|
||||
const auto mask = _mm_set1_epi32(0xffff);
|
||||
spu.gpr[op.rc].vi = _mm_add_epi32(spu.gpr[op.rt].vi, _mm_madd_epi16(_mm_and_si128(spu.gpr[op.ra].vi, mask), _mm_and_si128(spu.gpr[op.rb].vi, mask)));
|
||||
spu.gpr[op.rt4].vi = _mm_add_epi32(spu.gpr[op.rc].vi, _mm_madd_epi16(_mm_and_si128(spu.gpr[op.ra].vi, mask), _mm_and_si128(spu.gpr[op.rb].vi, mask)));
|
||||
}
|
||||
|
||||
void spu_interpreter::fast::FNMS(SPUThread& spu, spu_opcode_t op)
|
||||
{
|
||||
// rt <> rc
|
||||
spu.gpr[op.rc].vf = _mm_sub_ps(spu.gpr[op.rt].vf, _mm_mul_ps(spu.gpr[op.ra].vf, spu.gpr[op.rb].vf));
|
||||
spu.gpr[op.rt4].vf = _mm_sub_ps(spu.gpr[op.rc].vf, _mm_mul_ps(spu.gpr[op.ra].vf, spu.gpr[op.rb].vf));
|
||||
}
|
||||
|
||||
void spu_interpreter::fast::FMA(SPUThread& spu, spu_opcode_t op)
|
||||
{
|
||||
// rt <> rc
|
||||
spu.gpr[op.rc].vf = _mm_add_ps(_mm_mul_ps(spu.gpr[op.ra].vf, spu.gpr[op.rb].vf), spu.gpr[op.rt].vf);
|
||||
spu.gpr[op.rt4].vf = _mm_add_ps(_mm_mul_ps(spu.gpr[op.ra].vf, spu.gpr[op.rb].vf), spu.gpr[op.rc].vf);
|
||||
}
|
||||
|
||||
void spu_interpreter::fast::FMS(SPUThread& spu, spu_opcode_t op)
|
||||
{
|
||||
// rt <> rc
|
||||
spu.gpr[op.rc].vf = _mm_sub_ps(_mm_mul_ps(spu.gpr[op.ra].vf, spu.gpr[op.rb].vf), spu.gpr[op.rt].vf);
|
||||
spu.gpr[op.rt4].vf = _mm_sub_ps(_mm_mul_ps(spu.gpr[op.ra].vf, spu.gpr[op.rb].vf), spu.gpr[op.rc].vf);
|
||||
}
|
||||
|
||||
static void SetHostRoundingMode(u32 rn)
|
||||
@ -1932,14 +1926,12 @@ void spu_interpreter::precise::CUFLT(SPUThread& spu, spu_opcode_t op)
|
||||
|
||||
static void FMA(SPUThread& spu, spu_opcode_t op, bool neg, bool sub)
|
||||
{
|
||||
// rt <> rc
|
||||
|
||||
SetHostRoundingMode(FPSCR_RN_ZERO);
|
||||
for (int w = 0; w < 4; w++)
|
||||
{
|
||||
float a = spu.gpr[op.ra]._f[w];
|
||||
float b = neg ? -spu.gpr[op.rb]._f[w] : spu.gpr[op.rb]._f[w];
|
||||
float c = (neg != sub) ? -spu.gpr[op.rt]._f[w] : spu.gpr[op.rt]._f[w];
|
||||
float c = (neg != sub) ? -spu.gpr[op.rc]._f[w] : spu.gpr[op.rc]._f[w];
|
||||
if (isdenormal(a))
|
||||
{
|
||||
spu.fpscr.setSinglePrecisionExceptionFlags(w, FPSCR_SDIFF);
|
||||
@ -2073,7 +2065,7 @@ static void FMA(SPUThread& spu, spu_opcode_t op, bool neg, bool sub)
|
||||
{
|
||||
result = +0.0f;
|
||||
}
|
||||
spu.gpr[op.rc]._f[w] = result;
|
||||
spu.gpr[op.rt4]._f[w] = result;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,76 +4,23 @@ union spu_opcode_t
|
||||
{
|
||||
u32 opcode;
|
||||
|
||||
struct
|
||||
{
|
||||
u32 rt : 7; // 25..31, it's actually RC in 4-op instructions
|
||||
u32 ra : 7; // 18..24
|
||||
u32 rb : 7; // 11..17
|
||||
u32 rc : 7; // 4..10, it's actually RT in 4-op instructions
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
u32 : 14; // 18..31
|
||||
u32 i7 : 7; // 11..17
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
u32 : 14; // 18..31
|
||||
u32 i8 : 8; // 10..17
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
u32 : 7; // 25..31
|
||||
u32 i16 : 16; // 9..24
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
u32 : 7; // 25..31
|
||||
u32 i18 : 18; // 7..24
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
s32 : 14; // 18..31
|
||||
s32 si7 : 7; // 11..17
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
s32 : 14; // 18..31
|
||||
s32 si8 : 8; // 10..17
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
s32 : 14; // 18..31
|
||||
s32 si10 : 10; // 8..17
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
s32 : 7; // 25..31
|
||||
s32 si16 : 16; // 9..24
|
||||
s32 r0h : 2; // 7..8
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
s32 : 14; // 18..31
|
||||
s32 roh : 2; // 16..17
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
u32 : 18; // 14..31
|
||||
u32 e : 1; // 13, "enable interrupts" bit
|
||||
u32 d : 1; // 12, "disable interrupts" bit
|
||||
u32 c : 1; // 11, "C" bit for SYNC instruction
|
||||
};
|
||||
bf_t<u32, 0, 7> rt; // 25..31, for 3-op instructions
|
||||
bf_t<u32, 0, 7> rc; // 25..31
|
||||
bf_t<u32, 7, 7> ra; // 18..24
|
||||
bf_t<u32, 14, 7> rb; // 11..17
|
||||
bf_t<u32, 21, 7> rt4; // 4..10, for 4-op instructions
|
||||
bf_t<u32, 18, 1> e; // 13, "enable interrupts" bit
|
||||
bf_t<u32, 19, 1> d; // 12, "disable interrupts" bit
|
||||
bf_t<u32, 20, 1> c; // 11, "C" bit for SYNC instruction
|
||||
bf_t<s32, 23, 2> r0h; // 7..8, signed
|
||||
bf_t<s32, 14, 2> roh; // 16..17, signed
|
||||
bf_t<u32, 14, 7> i7; // 11..17
|
||||
bf_t<s32, 14, 7> si7; // 11..17, signed
|
||||
bf_t<u32, 14, 8> i8; // 10..17
|
||||
bf_t<s32, 14, 10> si10; // 8..17, signed
|
||||
bf_t<u32, 7, 16> i16; // 9..24
|
||||
bf_t<s32, 7, 16> si16; // 9..24, signed
|
||||
bf_t<u32, 7, 18> i18; // 7..24
|
||||
};
|
||||
|
||||
#define DEFINE_SPU_OPCODES(ns) { \
|
||||
@ -309,14 +256,19 @@ public:
|
||||
}
|
||||
|
||||
// access opcode table
|
||||
inline T operator [](u32 opcode_data) const
|
||||
T operator [](u32 opcode_data) const
|
||||
{
|
||||
// the whole decoding process is shifting opcode data
|
||||
return m_data[opcode_data >> 21];
|
||||
}
|
||||
};
|
||||
|
||||
inline u32 spu_branch_target(u32 pc, s32 imm = 0)
|
||||
inline u32 spu_branch_target(u32 pc, u32 imm = 0)
|
||||
{
|
||||
return (pc + (imm << 2)) & 0x3fffc;
|
||||
}
|
||||
|
||||
inline u32 spu_ls_target(u32 pc, u32 imm = 0)
|
||||
{
|
||||
return (pc + (imm << 2)) & 0x3fff0;
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ u32 SPURecompilerDecoder::DecodeMemory(const u32 address)
|
||||
}
|
||||
|
||||
// get SPU LS pointer
|
||||
const auto _ls = vm::get_ptr<be_t<u32>>(spu.offset);
|
||||
const auto _ls = vm::ps3::_ptr<u32>(spu.offset);
|
||||
|
||||
// always validate (TODO)
|
||||
const auto func = db->analyse(_ls, spu.pc);
|
||||
|
@ -114,7 +114,7 @@ void SPUThread::task()
|
||||
const auto& table = Ini.SPUDecoderMode.GetValue() == 0 ? spu_interpreter::precise::g_spu_opcode_table : spu_interpreter::fast::g_spu_opcode_table;
|
||||
|
||||
// LS base address
|
||||
const auto base = vm::get_ptr<const be_t<u32>>(offset);
|
||||
const auto base = vm::_ptr<const u32>(offset);
|
||||
|
||||
while (true)
|
||||
{
|
||||
@ -238,7 +238,7 @@ void SPUThread::fast_call(u32 ls_addr)
|
||||
}
|
||||
|
||||
// LS:0x0: this is originally the entry point of the interrupt handler, but interrupts are not implemented
|
||||
write32(0x0, 2);
|
||||
_ref<u32>(0) = 0x00000002; // STOP 2
|
||||
|
||||
auto old_pc = pc;
|
||||
auto old_lr = gpr[0]._u32[3];
|
||||
@ -291,7 +291,7 @@ void SPUThread::do_dma_transfer(u32 cmd, spu_mfc_arg_t args)
|
||||
}
|
||||
else if ((cmd & MFC_PUT_CMD) && args.size == 4 && (offset == SYS_SPU_THREAD_SNR1 || offset == SYS_SPU_THREAD_SNR2))
|
||||
{
|
||||
spu.push_snr(SYS_SPU_THREAD_SNR2 == offset, read32(args.lsa));
|
||||
spu.push_snr(SYS_SPU_THREAD_SNR2 == offset, _ref<u32>(args.lsa));
|
||||
return;
|
||||
}
|
||||
else
|
||||
@ -310,13 +310,13 @@ void SPUThread::do_dma_transfer(u32 cmd, spu_mfc_arg_t args)
|
||||
case MFC_PUT_CMD:
|
||||
case MFC_PUTR_CMD:
|
||||
{
|
||||
memcpy(vm::get_ptr(eal), vm::get_ptr(offset + args.lsa), args.size);
|
||||
std::memcpy(vm::base(eal), vm::base(offset + args.lsa), args.size);
|
||||
return;
|
||||
}
|
||||
|
||||
case MFC_GET_CMD:
|
||||
{
|
||||
memcpy(vm::get_ptr(offset + args.lsa), vm::get_ptr(eal), args.size);
|
||||
std::memcpy(vm::base(offset + args.lsa), vm::base(eal), args.size);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -422,7 +422,7 @@ void SPUThread::process_mfc_cmd(u32 cmd)
|
||||
|
||||
const u32 raddr = VM_CAST(ch_mfc_args.ea);
|
||||
|
||||
vm::reservation_acquire(vm::get_ptr(offset + ch_mfc_args.lsa), raddr, 128);
|
||||
vm::reservation_acquire(vm::base(offset + ch_mfc_args.lsa), raddr, 128);
|
||||
|
||||
if (last_raddr)
|
||||
{
|
||||
@ -441,7 +441,7 @@ void SPUThread::process_mfc_cmd(u32 cmd)
|
||||
break;
|
||||
}
|
||||
|
||||
if (vm::reservation_update(VM_CAST(ch_mfc_args.ea), vm::get_ptr(offset + ch_mfc_args.lsa), 128))
|
||||
if (vm::reservation_update(VM_CAST(ch_mfc_args.ea), vm::base(offset + ch_mfc_args.lsa), 128))
|
||||
{
|
||||
if (last_raddr == 0)
|
||||
{
|
||||
@ -475,7 +475,7 @@ void SPUThread::process_mfc_cmd(u32 cmd)
|
||||
|
||||
vm::reservation_op(VM_CAST(ch_mfc_args.ea), 128, [this]()
|
||||
{
|
||||
std::memcpy(vm::priv_ptr(VM_CAST(ch_mfc_args.ea)), vm::get_ptr(offset + ch_mfc_args.lsa), 128);
|
||||
std::memcpy(vm::base_priv(VM_CAST(ch_mfc_args.ea)), vm::base(offset + ch_mfc_args.lsa), 128);
|
||||
});
|
||||
|
||||
if (last_raddr != 0 && vm::g_tls_did_break_reservation)
|
||||
|
@ -618,27 +618,22 @@ public:
|
||||
void stop_and_signal(u32 code);
|
||||
void halt();
|
||||
|
||||
u8 read8(u32 lsa) const { return vm::read8(lsa + offset); }
|
||||
u16 read16(u32 lsa) const { return vm::ps3::read16(lsa + offset); }
|
||||
u32 read32(u32 lsa) const { return vm::ps3::read32(lsa + offset); }
|
||||
u64 read64(u32 lsa) const { return vm::ps3::read64(lsa + offset); }
|
||||
v128 read128(u32 lsa) const { return vm::ps3::read128(lsa + offset); }
|
||||
// Convert specified SPU LS address to a pointer of specified (possibly converted to BE) type
|
||||
template<typename T> inline to_be_t<T>* _ptr(u32 lsa)
|
||||
{
|
||||
return static_cast<to_be_t<T>*>(vm::base(offset + lsa));
|
||||
}
|
||||
|
||||
void write8(u32 lsa, u8 data) const { vm::write8(lsa + offset, data); }
|
||||
void write16(u32 lsa, u16 data) const { vm::ps3::write16(lsa + offset, data); }
|
||||
void write32(u32 lsa, u32 data) const { vm::ps3::write32(lsa + offset, data); }
|
||||
void write64(u32 lsa, u64 data) const { vm::ps3::write64(lsa + offset, data); }
|
||||
void write128(u32 lsa, v128 data) const { vm::ps3::write128(lsa + offset, data); }
|
||||
|
||||
void write16(u32 lsa, be_t<u16> data) const { vm::ps3::write16(lsa + offset, data); }
|
||||
void write32(u32 lsa, be_t<u32> data) const { vm::ps3::write32(lsa + offset, data); }
|
||||
void write64(u32 lsa, be_t<u64> data) const { vm::ps3::write64(lsa + offset, data); }
|
||||
void write128(u32 lsa, be_t<v128> data) const { vm::ps3::write128(lsa + offset, data); }
|
||||
// Convert specified SPU LS address to a reference of specified (possibly converted to BE) type
|
||||
template<typename T> inline to_be_t<T>& _ref(u32 lsa)
|
||||
{
|
||||
return *_ptr<T>(lsa);
|
||||
}
|
||||
|
||||
void RegisterHleFunction(u32 addr, std::function<bool(SPUThread & SPU)> function)
|
||||
{
|
||||
m_addr_to_hle_function_map[addr] = function;
|
||||
write32(addr, 0x00000003); // STOP 3
|
||||
_ref<u32>(addr) = 0x00000003; // STOP 3
|
||||
}
|
||||
|
||||
void UnregisterHleFunction(u32 addr)
|
||||
|
@ -20,7 +20,7 @@ bool vfsLocalDir::Open(const std::string& path)
|
||||
std::string name;
|
||||
fs::stat_t file_info;
|
||||
|
||||
for (bool is_ok = m_dir.get_first(name, file_info); is_ok; is_ok = m_dir.get_next(name, file_info))
|
||||
while (m_dir.read(name, file_info))
|
||||
{
|
||||
m_entries.emplace_back();
|
||||
|
||||
|
@ -10,7 +10,7 @@ u64 vfsStreamMemory::Write(const void* src, u64 count)
|
||||
count = m_size - m_pos;
|
||||
}
|
||||
|
||||
memcpy(vm::get_ptr<void>(VM_CAST(m_addr + m_pos)), src, count);
|
||||
std::memcpy(vm::base(VM_CAST(m_addr + m_pos)), src, count);
|
||||
m_pos += count;
|
||||
return count;
|
||||
}
|
||||
@ -23,7 +23,7 @@ u64 vfsStreamMemory::Read(void* dst, u64 count)
|
||||
count = m_size - m_pos;
|
||||
}
|
||||
|
||||
memcpy(dst, vm::get_ptr<void>(VM_CAST(m_addr + m_pos)), count);
|
||||
std::memcpy(dst, vm::base(VM_CAST(m_addr + m_pos)), count);
|
||||
m_pos += count;
|
||||
return count;
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ namespace idm
|
||||
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()
|
||||
static inline u32 get_last_id()
|
||||
{
|
||||
return g_tls_last_id;
|
||||
}
|
||||
|
@ -326,4 +326,4 @@ public:
|
||||
std::vector<KbButton>& GetButtons(const u32 keyboard) { return m_keyboards[keyboard].m_buttons; }
|
||||
KbData& GetData(const u32 keyboard) { return m_keyboards[keyboard].m_data; }
|
||||
KbConfig& GetConfig(const u32 keyboard) { return m_keyboards[keyboard].m_config; }
|
||||
};
|
||||
};
|
||||
|
@ -157,4 +157,4 @@ public:
|
||||
std::vector<Mouse>& GetMice() { return m_mice; }
|
||||
MouseData& GetData(const u32 mouse) { return m_mice[mouse].m_data; }
|
||||
MouseRawData& GetRawData(const u32 mouse) { return m_mice[mouse].m_rawdata; }
|
||||
};
|
||||
};
|
||||
|
@ -277,4 +277,4 @@ public:
|
||||
std::vector<Pad>& GetPads() { return m_pads; }
|
||||
std::vector<Button>& GetButtons(const u32 pad) { return m_pads[pad].m_buttons; }
|
||||
std::vector<AnalogStick>& GetSticks(const u32 pad) { return m_pads[pad].m_sticks; }
|
||||
};
|
||||
};
|
||||
|
@ -25,60 +25,71 @@
|
||||
|
||||
namespace vm
|
||||
{
|
||||
void* initialize()
|
||||
template<std::size_t Size> struct mapped_ptr_deleter
|
||||
{
|
||||
void operator ()(void* ptr)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
::UnmapViewOfFile(ptr);
|
||||
#else
|
||||
::munmap(ptr, Size);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
using mapped_ptr_t = std::unique_ptr<u8[], mapped_ptr_deleter<0x100000000>>;
|
||||
|
||||
std::array<mapped_ptr_t, 2> initialize()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
HANDLE memory_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE | SEC_RESERVE, 0x1, 0x0, NULL);
|
||||
const HANDLE memory_handle = ::CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE | SEC_RESERVE, 0x1, 0x0, NULL);
|
||||
|
||||
void* base_addr = MapViewOfFile(memory_handle, FILE_MAP_WRITE, 0, 0, 0x100000000);
|
||||
g_priv_addr = MapViewOfFile(memory_handle, FILE_MAP_WRITE, 0, 0, 0x100000000);
|
||||
if (memory_handle == NULL)
|
||||
{
|
||||
std::printf("CreateFileMapping() failed\n");
|
||||
return{};
|
||||
}
|
||||
|
||||
CloseHandle(memory_handle);
|
||||
mapped_ptr_t base_addr(static_cast<u8*>(::MapViewOfFile(memory_handle, FILE_MAP_WRITE, 0, 0, 0x100000000)));
|
||||
mapped_ptr_t priv_addr(static_cast<u8*>(::MapViewOfFile(memory_handle, FILE_MAP_WRITE, 0, 0, 0x100000000)));
|
||||
|
||||
return base_addr;
|
||||
::CloseHandle(memory_handle);
|
||||
#else
|
||||
int memory_handle = shm_open("/rpcs3_vm", O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
|
||||
const int memory_handle = ::shm_open("/rpcs3_vm", O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
|
||||
|
||||
if (memory_handle == -1)
|
||||
{
|
||||
std::printf("shm_open('/rpcs3_vm') failed\n");
|
||||
return (void*)-1;
|
||||
return{};
|
||||
}
|
||||
|
||||
if (ftruncate(memory_handle, 0x100000000) == -1)
|
||||
if (::ftruncate(memory_handle, 0x100000000) == -1)
|
||||
{
|
||||
std::printf("ftruncate(memory_handle) failed\n");
|
||||
shm_unlink("/rpcs3_vm");
|
||||
return (void*)-1;
|
||||
::shm_unlink("/rpcs3_vm");
|
||||
return{};
|
||||
}
|
||||
|
||||
void* base_addr = mmap(nullptr, 0x100000000, PROT_NONE, MAP_SHARED, memory_handle, 0);
|
||||
g_priv_addr = mmap(nullptr, 0x100000000, PROT_NONE, MAP_SHARED, memory_handle, 0);
|
||||
mapped_ptr_t base_addr(static_cast<u8*>(::mmap(nullptr, 0x100000000, PROT_NONE, MAP_SHARED, memory_handle, 0)));
|
||||
mapped_ptr_t priv_addr(static_cast<u8*>(::mmap(nullptr, 0x100000000, PROT_NONE, MAP_SHARED, memory_handle, 0)));
|
||||
|
||||
shm_unlink("/rpcs3_vm");
|
||||
|
||||
std::printf("/rpcs3_vm: g_base_addr = %p, g_priv_addr = %p\n", base_addr, g_priv_addr);
|
||||
|
||||
return base_addr;
|
||||
::shm_unlink("/rpcs3_vm");
|
||||
#endif
|
||||
|
||||
std::printf("vm: base_addr = %p, priv_addr = %p\n", base_addr.get(), priv_addr.get());
|
||||
|
||||
return{ std::move(base_addr), std::move(priv_addr) };
|
||||
}
|
||||
|
||||
void finalize()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
UnmapViewOfFile(g_base_addr);
|
||||
UnmapViewOfFile(g_priv_addr);
|
||||
#else
|
||||
munmap(g_base_addr, 0x100000000);
|
||||
munmap(g_priv_addr, 0x100000000);
|
||||
#endif
|
||||
}
|
||||
const auto g_addr_set = vm::initialize();
|
||||
|
||||
void* const g_base_addr = (atexit(finalize), initialize());
|
||||
void* g_priv_addr;
|
||||
u8* const g_base_addr = g_addr_set[0].get();
|
||||
u8* const g_priv_addr = g_addr_set[1].get();
|
||||
|
||||
std::array<atomic_t<u8>, 0x100000000ull / 4096> g_pages{}; // information about every page
|
||||
|
||||
std::vector<std::shared_ptr<block_t>> g_locations; // memory locations
|
||||
|
||||
const thread_ctrl_t* const INVALID_THREAD = reinterpret_cast<const thread_ctrl_t*>(~0ull);
|
||||
|
||||
//using reservation_mutex_t = std::mutex;
|
||||
@ -361,9 +372,9 @@ namespace vm
|
||||
{
|
||||
#ifdef _WIN32
|
||||
DWORD old;
|
||||
if (!VirtualProtect(get_ptr(addr & ~0xfff), 4096, no_access ? PAGE_NOACCESS : PAGE_READONLY, &old))
|
||||
if (!::VirtualProtect(vm::base(addr & ~0xfff), 4096, no_access ? PAGE_NOACCESS : PAGE_READONLY, &old))
|
||||
#else
|
||||
if (mprotect(get_ptr(addr & ~0xfff), 4096, no_access ? PROT_NONE : PROT_READ))
|
||||
if (::mprotect(vm::base(addr & ~0xfff), 4096, no_access ? PROT_NONE : PROT_READ))
|
||||
#endif
|
||||
{
|
||||
throw EXCEPTION("System failure (addr=0x%x)", addr);
|
||||
@ -376,9 +387,9 @@ namespace vm
|
||||
{
|
||||
#ifdef _WIN32
|
||||
DWORD old;
|
||||
if (!VirtualProtect(get_ptr(addr & ~0xfff), 4096, PAGE_READWRITE, &old))
|
||||
if (!::VirtualProtect(vm::base(addr & ~0xfff), 4096, PAGE_READWRITE, &old))
|
||||
#else
|
||||
if (mprotect(get_ptr(addr & ~0xfff), 4096, PROT_READ | PROT_WRITE))
|
||||
if (::mprotect(vm::base(addr & ~0xfff), 4096, PROT_READ | PROT_WRITE))
|
||||
#endif
|
||||
{
|
||||
throw EXCEPTION("System failure (addr=0x%x)", addr);
|
||||
@ -443,7 +454,7 @@ namespace vm
|
||||
g_reservation_owner = get_current_thread_ctrl();
|
||||
|
||||
// copy data
|
||||
std::memcpy(data, get_ptr(addr), size);
|
||||
std::memcpy(data, vm::base(addr), size);
|
||||
}
|
||||
|
||||
bool reservation_update(u32 addr, const void* data, u32 size)
|
||||
@ -467,7 +478,7 @@ namespace vm
|
||||
_reservation_set(addr, true);
|
||||
|
||||
// update memory using privileged access
|
||||
std::memcpy(priv_ptr(addr), data, size);
|
||||
std::memcpy(vm::base_priv(addr), data, size);
|
||||
|
||||
// free the reservation and restore memory protection
|
||||
_reservation_break(addr);
|
||||
@ -578,7 +589,10 @@ namespace vm
|
||||
|
||||
void _page_map(u32 addr, u32 size, u8 flags)
|
||||
{
|
||||
assert(size && (size | addr) % 4096 == 0 && flags < page_allocated);
|
||||
if (!size || (size | addr) % 4096 || flags & page_allocated)
|
||||
{
|
||||
throw EXCEPTION("Invalid arguments (addr=0x%x, size=0x%x)", addr, size);
|
||||
}
|
||||
|
||||
for (u32 i = addr / 4096; i < addr / 4096 + size / 4096; i++)
|
||||
{
|
||||
@ -588,15 +602,15 @@ namespace vm
|
||||
}
|
||||
}
|
||||
|
||||
void* real_addr = get_ptr(addr);
|
||||
void* priv_addr = priv_ptr(addr);
|
||||
void* real_addr = vm::base(addr);
|
||||
void* priv_addr = vm::base_priv(addr);
|
||||
|
||||
#ifdef _WIN32
|
||||
auto protection = flags & page_writable ? PAGE_READWRITE : (flags & page_readable ? PAGE_READONLY : PAGE_NOACCESS);
|
||||
if (!VirtualAlloc(priv_addr, size, MEM_COMMIT, PAGE_READWRITE) || !VirtualAlloc(real_addr, size, MEM_COMMIT, protection))
|
||||
if (!::VirtualAlloc(priv_addr, size, MEM_COMMIT, PAGE_READWRITE) || !::VirtualAlloc(real_addr, size, MEM_COMMIT, protection))
|
||||
#else
|
||||
auto protection = flags & page_writable ? PROT_WRITE | PROT_READ : (flags & page_readable ? PROT_READ : PROT_NONE);
|
||||
if (mprotect(priv_addr, size, PROT_READ | PROT_WRITE) || mprotect(real_addr, size, protection))
|
||||
if (::mprotect(priv_addr, size, PROT_READ | PROT_WRITE) || ::mprotect(real_addr, size, protection))
|
||||
#endif
|
||||
{
|
||||
throw EXCEPTION("System failure (addr=0x%x, size=0x%x, flags=0x%x)", addr, size, flags);
|
||||
@ -610,16 +624,19 @@ namespace vm
|
||||
}
|
||||
}
|
||||
|
||||
memset(priv_addr, 0, size); // ???
|
||||
std::memset(priv_addr, 0, size); // ???
|
||||
}
|
||||
|
||||
bool page_protect(u32 addr, u32 size, u8 flags_test, u8 flags_set, u8 flags_clear)
|
||||
{
|
||||
std::lock_guard<reservation_mutex_t> lock(g_reservation_mutex);
|
||||
|
||||
u8 flags_inv = flags_set & flags_clear;
|
||||
if (!size || (size | addr) % 4096)
|
||||
{
|
||||
throw EXCEPTION("Invalid arguments (addr=0x%x, size=0x%x)", addr, size);
|
||||
}
|
||||
|
||||
assert(size && (size | addr) % 4096 == 0);
|
||||
const u8 flags_inv = flags_set & flags_clear;
|
||||
|
||||
flags_test |= page_allocated;
|
||||
|
||||
@ -646,16 +663,16 @@ namespace vm
|
||||
|
||||
if (f1 != f2)
|
||||
{
|
||||
void* real_addr = get_ptr(i * 4096);
|
||||
void* real_addr = vm::base(i * 4096);
|
||||
|
||||
#ifdef _WIN32
|
||||
DWORD old;
|
||||
|
||||
auto protection = f2 & page_writable ? PAGE_READWRITE : (f2 & page_readable ? PAGE_READONLY : PAGE_NOACCESS);
|
||||
if (!VirtualProtect(real_addr, 4096, protection, &old))
|
||||
if (!::VirtualProtect(real_addr, 4096, protection, &old))
|
||||
#else
|
||||
auto protection = f2 & page_writable ? PROT_WRITE | PROT_READ : (f2 & page_readable ? PROT_READ : PROT_NONE);
|
||||
if (mprotect(real_addr, 4096, protection))
|
||||
if (::mprotect(real_addr, 4096, protection))
|
||||
#endif
|
||||
{
|
||||
throw EXCEPTION("System failure (addr=0x%x, size=0x%x, flags_test=0x%x, flags_set=0x%x, flags_clear=0x%x)", addr, size, flags_test, flags_set, flags_clear);
|
||||
@ -668,7 +685,10 @@ namespace vm
|
||||
|
||||
void _page_unmap(u32 addr, u32 size)
|
||||
{
|
||||
assert(size && (size | addr) % 4096 == 0);
|
||||
if (!size || (size | addr) % 4096)
|
||||
{
|
||||
throw EXCEPTION("Invalid arguments (addr=0x%x, size=0x%x)", addr, size);
|
||||
}
|
||||
|
||||
for (u32 i = addr / 4096; i < addr / 4096 + size / 4096; i++)
|
||||
{
|
||||
@ -688,15 +708,15 @@ namespace vm
|
||||
}
|
||||
}
|
||||
|
||||
void* real_addr = get_ptr(addr);
|
||||
void* priv_addr = priv_ptr(addr);
|
||||
void* real_addr = vm::base(addr);
|
||||
void* priv_addr = vm::base_priv(addr);
|
||||
|
||||
#ifdef _WIN32
|
||||
DWORD old;
|
||||
|
||||
if (!VirtualProtect(real_addr, size, PAGE_NOACCESS, &old) || !VirtualProtect(priv_addr, size, PAGE_NOACCESS, &old))
|
||||
if (!::VirtualProtect(real_addr, size, PAGE_NOACCESS, &old) || !::VirtualProtect(priv_addr, size, PAGE_NOACCESS, &old))
|
||||
#else
|
||||
if (mprotect(real_addr, size, PROT_NONE) || mprotect(priv_addr, size, PROT_NONE))
|
||||
if (::mprotect(real_addr, size, PROT_NONE) || ::mprotect(priv_addr, size, PROT_NONE))
|
||||
#endif
|
||||
{
|
||||
throw EXCEPTION("System failure (addr=0x%x, size=0x%x)", addr, size);
|
||||
@ -705,8 +725,6 @@ namespace vm
|
||||
|
||||
bool check_addr(u32 addr, u32 size)
|
||||
{
|
||||
assert(size);
|
||||
|
||||
if (addr + (size - 1) < addr)
|
||||
{
|
||||
return false;
|
||||
@ -723,8 +741,6 @@ namespace vm
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<block_t>> g_locations;
|
||||
|
||||
u32 alloc(u32 size, memory_location_t location, u32 align)
|
||||
{
|
||||
const auto block = get(location);
|
||||
@ -1003,8 +1019,7 @@ namespace vm
|
||||
std::make_shared<block_t>(0x20000000, 0x10000000), // user
|
||||
std::make_shared<block_t>(0xC0000000, 0x10000000), // video
|
||||
std::make_shared<block_t>(0xD0000000, 0x10000000), // stack
|
||||
|
||||
std::make_shared<block_t>(0xE0000000, 0x20000000), // SPU
|
||||
std::make_shared<block_t>(0xE0000000, 0x20000000), // SPU reserved
|
||||
};
|
||||
|
||||
vm::start();
|
||||
@ -1019,8 +1034,8 @@ namespace vm
|
||||
{
|
||||
std::make_shared<block_t>(0x81000000, 0x10000000), // RAM
|
||||
std::make_shared<block_t>(0x91000000, 0x2F000000), // user
|
||||
nullptr, // video
|
||||
nullptr, // stack
|
||||
std::make_shared<block_t>(0xC0000000, 0x10000000), // video (arbitrarily)
|
||||
std::make_shared<block_t>(0xD0000000, 0x10000000), // stack (arbitrarily)
|
||||
};
|
||||
|
||||
vm::start();
|
||||
@ -1051,16 +1066,16 @@ namespace vm
|
||||
g_locations.clear();
|
||||
}
|
||||
|
||||
u32 stack_push(CPUThread& cpu, u32 size, u32 align_v, u32& old_pos)
|
||||
u32 stack_push(u32 size, u32 align_v)
|
||||
{
|
||||
switch (cpu.get_type())
|
||||
if (auto cpu = get_current_cpu_thread()) switch (cpu->get_type())
|
||||
{
|
||||
case CPU_THREAD_PPU:
|
||||
{
|
||||
PPUThread& context = static_cast<PPUThread&>(cpu);
|
||||
PPUThread& context = static_cast<PPUThread&>(*cpu);
|
||||
|
||||
old_pos = VM_CAST(context.GPR[1]);
|
||||
context.GPR[1] -= align(size, 8); // room minimal possible size
|
||||
const u32 old_pos = VM_CAST(context.GPR[1]);
|
||||
context.GPR[1] -= align(size + 4, 8); // room minimal possible size
|
||||
context.GPR[1] &= ~(align_v - 1); // fix stack alignment
|
||||
|
||||
if (context.GPR[1] < context.stack_addr)
|
||||
@ -1069,17 +1084,19 @@ namespace vm
|
||||
}
|
||||
else
|
||||
{
|
||||
return static_cast<u32>(context.GPR[1]);
|
||||
const u32 addr = static_cast<u32>(context.GPR[1]);
|
||||
vm::ps3::_ref<nse_t<u32>>(addr + size) = old_pos;
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
|
||||
case CPU_THREAD_SPU:
|
||||
case CPU_THREAD_RAW_SPU:
|
||||
{
|
||||
SPUThread& context = static_cast<SPUThread&>(cpu);
|
||||
SPUThread& context = static_cast<SPUThread&>(*cpu);
|
||||
|
||||
old_pos = context.gpr[1]._u32[3];
|
||||
context.gpr[1]._u32[3] -= align(size, 16);
|
||||
const u32 old_pos = context.gpr[1]._u32[3];
|
||||
context.gpr[1]._u32[3] -= align(size + 4, 16);
|
||||
context.gpr[1]._u32[3] &= ~(align_v - 1);
|
||||
|
||||
if (context.gpr[1]._u32[3] >= 0x40000) // extremely rough
|
||||
@ -1088,16 +1105,18 @@ namespace vm
|
||||
}
|
||||
else
|
||||
{
|
||||
return context.gpr[1]._u32[3] + context.offset;
|
||||
const u32 addr = context.gpr[1]._u32[3] + context.offset;
|
||||
vm::ps3::_ref<nse_t<u32>>(addr + size) = old_pos;
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
|
||||
case CPU_THREAD_ARMv7:
|
||||
{
|
||||
ARMv7Context& context = static_cast<ARMv7Thread&>(cpu);
|
||||
ARMv7Context& context = static_cast<ARMv7Thread&>(*cpu);
|
||||
|
||||
old_pos = context.SP;
|
||||
context.SP -= align(size, 4); // room minimal possible size
|
||||
const u32 old_pos = context.SP;
|
||||
context.SP -= align(size + 4, 4); // room minimal possible size
|
||||
context.SP &= ~(align_v - 1); // fix stack alignment
|
||||
|
||||
if (context.SP < context.stack_addr)
|
||||
@ -1106,65 +1125,70 @@ namespace vm
|
||||
}
|
||||
else
|
||||
{
|
||||
vm::psv::_ref<nse_t<u32>>(context.SP + size) = old_pos;
|
||||
return context.SP;
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
throw EXCEPTION("Invalid thread type (%d)", cpu.get_id());
|
||||
throw EXCEPTION("Invalid thread type (%d)", cpu->get_type());
|
||||
}
|
||||
}
|
||||
|
||||
throw EXCEPTION("Invalid thread");
|
||||
}
|
||||
|
||||
void stack_pop(CPUThread& cpu, u32 addr, u32 old_pos)
|
||||
void stack_pop(u32 addr, u32 size)
|
||||
{
|
||||
switch (cpu.get_type())
|
||||
if (auto cpu = get_current_cpu_thread()) switch (cpu->get_type())
|
||||
{
|
||||
case CPU_THREAD_PPU:
|
||||
{
|
||||
PPUThread& context = static_cast<PPUThread&>(cpu);
|
||||
PPUThread& context = static_cast<PPUThread&>(*cpu);
|
||||
|
||||
if (context.GPR[1] != addr)
|
||||
{
|
||||
throw EXCEPTION("Stack inconsistency (addr=0x%x, SP=0x%llx, old_pos=0x%x)", addr, context.GPR[1], old_pos);
|
||||
throw EXCEPTION("Stack inconsistency (addr=0x%x, SP=0x%llx, size=0x%x)", addr, context.GPR[1], size);
|
||||
}
|
||||
|
||||
context.GPR[1] = old_pos;
|
||||
context.GPR[1] = vm::ps3::_ref<nse_t<u32>>(context.GPR[1] + size);
|
||||
return;
|
||||
}
|
||||
|
||||
case CPU_THREAD_SPU:
|
||||
case CPU_THREAD_RAW_SPU:
|
||||
{
|
||||
SPUThread& context = static_cast<SPUThread&>(cpu);
|
||||
SPUThread& context = static_cast<SPUThread&>(*cpu);
|
||||
|
||||
if (context.gpr[1]._u32[3] + context.offset != addr)
|
||||
{
|
||||
throw EXCEPTION("Stack inconsistency (addr=0x%x, SP=LS:0x%05x, old_pos=LS:0x%05x)", addr, context.gpr[1]._u32[3], old_pos);
|
||||
throw EXCEPTION("Stack inconsistency (addr=0x%x, SP=LS:0x%05x, size=0x%x)", addr, context.gpr[1]._u32[3], size);
|
||||
}
|
||||
|
||||
context.gpr[1]._u32[3] = old_pos;
|
||||
context.gpr[1]._u32[3] = vm::ps3::_ref<nse_t<u32>>(context.gpr[1]._u32[3] + context.offset + size);
|
||||
return;
|
||||
}
|
||||
|
||||
case CPU_THREAD_ARMv7:
|
||||
{
|
||||
ARMv7Context& context = static_cast<ARMv7Thread&>(cpu);
|
||||
ARMv7Context& context = static_cast<ARMv7Thread&>(*cpu);
|
||||
|
||||
if (context.SP != addr)
|
||||
{
|
||||
throw EXCEPTION("Stack inconsistency (addr=0x%x, SP=0x%x, old_pos=0x%x)", addr, context.SP, old_pos);
|
||||
throw EXCEPTION("Stack inconsistency (addr=0x%x, SP=0x%x, size=0x%x)", addr, context.SP, size);
|
||||
}
|
||||
|
||||
context.SP = old_pos;
|
||||
context.SP = vm::psv::_ref<nse_t<u32>>(context.SP + size);
|
||||
return;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
throw EXCEPTION("Invalid thread type (%d)", cpu.get_type());
|
||||
throw EXCEPTION("Invalid thread type (%d)", cpu->get_type());
|
||||
}
|
||||
}
|
||||
|
||||
throw EXCEPTION("Invalid thread");
|
||||
}
|
||||
}
|
||||
|
@ -8,8 +8,8 @@ class named_thread_t;
|
||||
|
||||
namespace vm
|
||||
{
|
||||
extern void* const g_base_addr; // base address of ps3/psv virtual memory for common access
|
||||
extern void* g_priv_addr; // base address of ps3/psv virtual memory for privileged access
|
||||
extern u8* const g_base_addr;
|
||||
extern u8* const g_priv_addr;
|
||||
|
||||
enum memory_location_t : uint
|
||||
{
|
||||
@ -39,7 +39,7 @@ namespace vm
|
||||
u32 addr = 0;
|
||||
u32 mask = ~0;
|
||||
named_thread_t* thread = nullptr;
|
||||
|
||||
|
||||
std::function<bool()> pred;
|
||||
|
||||
waiter_t() = default;
|
||||
@ -68,8 +68,6 @@ namespace vm
|
||||
std::unique_lock<std::mutex> m_lock;
|
||||
|
||||
public:
|
||||
waiter_lock_t() = delete;
|
||||
|
||||
waiter_lock_t(named_thread_t& thread, u32 addr, u32 size);
|
||||
|
||||
waiter_t* operator ->() const
|
||||
@ -82,7 +80,7 @@ namespace vm
|
||||
~waiter_lock_t();
|
||||
};
|
||||
|
||||
// wait until pred() returns true, addr must be aligned to size which must be a power of 2, pred() may be called by any thread
|
||||
// Wait until pred() returns true, addr must be aligned to size which must be a power of 2, pred() may be called by any thread
|
||||
template<typename F, typename... Args> auto wait_op(named_thread_t& thread, u32 addr, u32 size, F pred, Args&&... args) -> decltype(static_cast<void>(pred(args...)))
|
||||
{
|
||||
// return immediately if condition passed (optimistic case)
|
||||
@ -98,10 +96,10 @@ namespace vm
|
||||
lock.wait();
|
||||
}
|
||||
|
||||
// notify waiters on specific addr, addr must be aligned to size which must be a power of 2
|
||||
// Notify waiters on specific addr, addr must be aligned to size which must be a power of 2
|
||||
void notify_at(u32 addr, u32 size);
|
||||
|
||||
// try to poll each waiter's condition (false if try_lock failed)
|
||||
// Try to poll each waiter's condition (false if try_lock failed)
|
||||
bool notify_all();
|
||||
|
||||
// This flag is changed by various reservation functions and may have different meaning.
|
||||
@ -152,7 +150,7 @@ namespace vm
|
||||
// dealloc() with no return value and no exceptions
|
||||
void dealloc_verbose_nothrow(u32 addr, memory_location_t location = any) noexcept;
|
||||
|
||||
// Object that handles memory allocations inside specific constant bounds ("location"), currently non-virtual
|
||||
// Object that handles memory allocations inside specific constant bounds ("location")
|
||||
class block_t final
|
||||
{
|
||||
std::map<u32, u32> m_map; // addr -> size mapping of mapped locations
|
||||
@ -161,12 +159,11 @@ namespace vm
|
||||
bool try_alloc(u32 addr, u32 size);
|
||||
|
||||
public:
|
||||
block_t() = delete;
|
||||
|
||||
block_t(u32 addr, u32 size, u64 flags = 0)
|
||||
: addr(addr)
|
||||
, size(size)
|
||||
, flags(flags)
|
||||
, used(0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -177,7 +174,7 @@ namespace vm
|
||||
const u32 size; // total size
|
||||
const u64 flags; // currently unused
|
||||
|
||||
atomic_t<u32> used{}; // amount of memory used, may be increased manually to prevent some memory from allocating
|
||||
atomic_t<u32> used; // amount of memory used, may be increased manually to prevent some memory from allocating
|
||||
|
||||
// Search and map memory (don't pass alignment smaller than 4096)
|
||||
u32 alloc(u32 size, u32 align = 4096);
|
||||
@ -197,30 +194,16 @@ namespace vm
|
||||
|
||||
// get memory block associated with optionally specified memory location or optionally specified address
|
||||
std::shared_ptr<block_t> get(memory_location_t location, u32 addr = 0);
|
||||
|
||||
template<typename T = void> T* get_ptr(u32 addr)
|
||||
{
|
||||
return reinterpret_cast<T*>(static_cast<u8*>(g_base_addr) + addr);
|
||||
}
|
||||
|
||||
template<typename T> T& get_ref(u32 addr)
|
||||
// Get PS3/PSV virtual memory address from the provided pointer (nullptr always converted to 0)
|
||||
inline u32 get_addr(const void* real_ptr)
|
||||
{
|
||||
return *get_ptr<T>(addr);
|
||||
}
|
||||
if (!real_ptr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename T = void> T* priv_ptr(u32 addr)
|
||||
{
|
||||
return reinterpret_cast<T*>(static_cast<u8*>(g_priv_addr) + addr);
|
||||
}
|
||||
|
||||
template<typename T> T& priv_ref(u32 addr)
|
||||
{
|
||||
return *priv_ptr<T>(addr);
|
||||
}
|
||||
|
||||
inline u32 get_addr(const void* real_pointer)
|
||||
{
|
||||
const std::uintptr_t diff = reinterpret_cast<std::uintptr_t>(real_pointer) - reinterpret_cast<std::uintptr_t>(g_base_addr);
|
||||
const std::ptrdiff_t diff = static_cast<const u8*>(real_ptr) - g_base_addr;
|
||||
const u32 res = static_cast<u32>(diff);
|
||||
|
||||
if (res == diff)
|
||||
@ -228,27 +211,23 @@ namespace vm
|
||||
return res;
|
||||
}
|
||||
|
||||
if (real_pointer)
|
||||
{
|
||||
throw EXCEPTION("Not a virtual memory pointer (%p)", real_pointer);
|
||||
}
|
||||
throw EXCEPTION("Not a virtual memory pointer (%p)", real_ptr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
// Convert pointer-to-member to a vm address compatible offset
|
||||
template<typename MT, typename T> inline u32 get_offset(MT T::*const member_ptr)
|
||||
{
|
||||
return static_cast<u32>(reinterpret_cast<std::uintptr_t>(&(reinterpret_cast<T*>(0ull)->*member_ptr)));
|
||||
}
|
||||
|
||||
template<typename T> struct cast_ptr
|
||||
{
|
||||
static_assert(std::is_same<T, u32>::value, "Unsupported VM_CAST() type");
|
||||
|
||||
force_inline static u32 cast(const T& addr, const char* file, int line, const char* func)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct cast_ptr<u32>
|
||||
{
|
||||
force_inline static u32 cast(const u32 addr, const char* file, int line, const char* func)
|
||||
static u32 cast(const u32 addr, const char* file, int line, const char* func)
|
||||
{
|
||||
return addr;
|
||||
}
|
||||
@ -256,131 +235,157 @@ namespace vm
|
||||
|
||||
template<> struct cast_ptr<u64>
|
||||
{
|
||||
force_inline static u32 cast(const u64 addr, const char* file, int line, const char* func)
|
||||
static u32 cast(const u64 addr, const char* file, int line, const char* func)
|
||||
{
|
||||
const u32 res = static_cast<u32>(addr);
|
||||
|
||||
if (res != addr)
|
||||
{
|
||||
throw fmt::exception(file, line, func, "VM_CAST failed (addr=0x%llx)", addr);
|
||||
}
|
||||
|
||||
return res;
|
||||
return static_cast<u32>(addr) == addr ? static_cast<u32>(addr) : throw fmt::exception(file, line, func, "VM_CAST failed (addr=0x%llx)", addr);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, bool Se> struct cast_ptr<se_t<T, Se>>
|
||||
{
|
||||
force_inline static u32 cast(const se_t<T, Se>& addr, const char* file, int line, const char* func)
|
||||
static u32 cast(const se_t<T, Se>& addr, const char* file, int line, const char* func)
|
||||
{
|
||||
return cast_ptr<T>::cast(addr, file, line, func);
|
||||
}
|
||||
};
|
||||
|
||||
// function for VM_CAST
|
||||
template<typename T> force_inline static u32 impl_cast(const T& addr, const char* file, int line, const char* func)
|
||||
template<typename T> u32 impl_cast(const T& addr, const char* file, int line, const char* func)
|
||||
{
|
||||
return cast_ptr<T>::cast(addr, file, line, func);
|
||||
}
|
||||
|
||||
static const u8& read8(u32 addr)
|
||||
// Convert specified PS3/PSV virtual memory address to a pointer for common access
|
||||
inline void* base(u32 addr)
|
||||
{
|
||||
return get_ref<const u8>(addr);
|
||||
return g_base_addr + addr;
|
||||
}
|
||||
|
||||
static void write8(u32 addr, u8 value)
|
||||
// Convert specified PS3/PSV virtual memory address to a pointer for privileged access (always readable/writable if allocated)
|
||||
inline void* base_priv(u32 addr)
|
||||
{
|
||||
get_ref<u8>(addr) = value;
|
||||
return g_priv_addr + addr;
|
||||
}
|
||||
|
||||
inline const u8& read8(u32 addr)
|
||||
{
|
||||
return g_base_addr[addr];
|
||||
}
|
||||
|
||||
inline void write8(u32 addr, u8 value)
|
||||
{
|
||||
g_base_addr[addr] = value;
|
||||
}
|
||||
|
||||
namespace ps3
|
||||
{
|
||||
void init();
|
||||
// Convert specified PS3 address to a pointer of specified (possibly converted to BE) type
|
||||
template<typename T> inline to_be_t<T>* _ptr(u32 addr)
|
||||
{
|
||||
return static_cast<to_be_t<T>*>(base(addr));
|
||||
}
|
||||
|
||||
template<typename T> inline to_be_t<T>* _ptr_priv(u32 addr)
|
||||
{
|
||||
return static_cast<to_be_t<T>*>(base_priv(addr));
|
||||
}
|
||||
|
||||
// Convert specified PS3 address to a reference of specified (possibly converted to BE) type
|
||||
template<typename T> inline to_be_t<T>& _ref(u32 addr)
|
||||
{
|
||||
return *_ptr<T>(addr);
|
||||
}
|
||||
|
||||
template<typename T> inline to_be_t<T>& _ref_priv(u32 addr)
|
||||
{
|
||||
return *_ptr_priv<T>(addr);
|
||||
}
|
||||
|
||||
inline const be_t<u16>& read16(u32 addr)
|
||||
{
|
||||
return get_ref<const be_t<u16>>(addr);
|
||||
return _ref<u16>(addr);
|
||||
}
|
||||
|
||||
inline void write16(u32 addr, be_t<u16> value)
|
||||
{
|
||||
get_ref<be_t<u16>>(addr) = value;
|
||||
_ref<u16>(addr) = value;
|
||||
}
|
||||
|
||||
inline const be_t<u32>& read32(u32 addr)
|
||||
{
|
||||
return get_ref<const be_t<u32>>(addr);
|
||||
return _ref<u32>(addr);
|
||||
}
|
||||
|
||||
inline void write32(u32 addr, be_t<u32> value)
|
||||
{
|
||||
get_ref<be_t<u32>>(addr) = value;
|
||||
_ref<u32>(addr) = value;
|
||||
}
|
||||
|
||||
inline const be_t<u64>& read64(u32 addr)
|
||||
{
|
||||
return get_ref<const be_t<u64>>(addr);
|
||||
return _ref<u64>(addr);
|
||||
}
|
||||
|
||||
inline void write64(u32 addr, be_t<u64> value)
|
||||
{
|
||||
get_ref<be_t<u64>>(addr) = value;
|
||||
_ref<u64>(addr) = value;
|
||||
}
|
||||
|
||||
inline const be_t<v128>& read128(u32 addr)
|
||||
{
|
||||
return get_ref<const be_t<v128>>(addr);
|
||||
}
|
||||
|
||||
inline void write128(u32 addr, be_t<v128> value)
|
||||
{
|
||||
get_ref<be_t<v128>>(addr) = value;
|
||||
}
|
||||
void init();
|
||||
}
|
||||
|
||||
namespace psv
|
||||
{
|
||||
void init();
|
||||
template<typename T> inline to_le_t<T>* _ptr(u32 addr)
|
||||
{
|
||||
return static_cast<to_le_t<T>*>(base(addr));
|
||||
}
|
||||
|
||||
template<typename T> inline to_le_t<T>* _ptr_priv(u32 addr)
|
||||
{
|
||||
return static_cast<to_le_t<T>*>(base_priv(addr));
|
||||
}
|
||||
|
||||
template<typename T> inline to_le_t<T>& _ref(u32 addr)
|
||||
{
|
||||
return *_ptr<T>(addr);
|
||||
}
|
||||
|
||||
template<typename T> inline to_le_t<T>& _ref_priv(u32 addr)
|
||||
{
|
||||
return *_ptr_priv<T>(addr);
|
||||
}
|
||||
|
||||
inline const le_t<u16>& read16(u32 addr)
|
||||
{
|
||||
return get_ref<const le_t<u16>>(addr);
|
||||
return _ref<u16>(addr);
|
||||
}
|
||||
|
||||
inline void write16(u32 addr, le_t<u16> value)
|
||||
{
|
||||
get_ref<le_t<u16>>(addr) = value;
|
||||
_ref<u16>(addr) = value;
|
||||
}
|
||||
|
||||
inline const le_t<u32>& read32(u32 addr)
|
||||
{
|
||||
return get_ref<const le_t<u32>>(addr);
|
||||
return _ref<u32>(addr);
|
||||
}
|
||||
|
||||
inline void write32(u32 addr, le_t<u32> value)
|
||||
{
|
||||
get_ref<le_t<u32>>(addr) = value;
|
||||
_ref<u32>(addr) = value;
|
||||
}
|
||||
|
||||
inline const le_t<u64>& read64(u32 addr)
|
||||
{
|
||||
return get_ref<const le_t<u64>>(addr);
|
||||
return _ref<u64>(addr);
|
||||
}
|
||||
|
||||
inline void write64(u32 addr, le_t<u64> value)
|
||||
{
|
||||
get_ref<le_t<u64>>(addr) = value;
|
||||
_ref<u64>(addr) = value;
|
||||
}
|
||||
|
||||
inline const le_t<v128>& read128(u32 addr)
|
||||
{
|
||||
return get_ref<const le_t<v128>>(addr);
|
||||
}
|
||||
|
||||
inline void write128(u32 addr, le_t<v128> value)
|
||||
{
|
||||
get_ref<le_t<v128>>(addr) = value;
|
||||
}
|
||||
void init();
|
||||
}
|
||||
|
||||
namespace psp
|
||||
@ -393,11 +398,8 @@ namespace vm
|
||||
void close();
|
||||
}
|
||||
|
||||
#include "vm_ref.h"
|
||||
#include "vm_ptr.h"
|
||||
|
||||
class CPUThread;
|
||||
|
||||
namespace vm
|
||||
{
|
||||
class stack
|
||||
@ -433,8 +435,8 @@ namespace vm
|
||||
}
|
||||
};
|
||||
|
||||
u32 stack_push(CPUThread& cpu, u32 size, u32 align_v, u32& old_pos);
|
||||
void stack_pop(CPUThread& cpu, u32 addr, u32 old_pos);
|
||||
u32 stack_push(u32 size, u32 align_v);
|
||||
void stack_pop(u32 addr, u32 size);
|
||||
}
|
||||
|
||||
#include "vm_var.h"
|
||||
|
@ -1,12 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "vm_ref.h"
|
||||
|
||||
class PPUThread;
|
||||
class ARMv7Thread;
|
||||
|
||||
namespace vm
|
||||
{
|
||||
template<typename T, typename AT> struct _ref_base;
|
||||
|
||||
// helper SFINAE type for vm::_ptr_base comparison operators (enables comparison between equal types and between any type and void*)
|
||||
template<typename T1, typename T2, typename RT = void> using if_comparable_t = std::enable_if_t<
|
||||
std::is_void<T1>::value ||
|
||||
@ -14,84 +14,83 @@ namespace vm
|
||||
std::is_same<std::remove_cv_t<T1>, std::remove_cv_t<T2>>::value,
|
||||
RT>;
|
||||
|
||||
// helper SFINAE type for vm::_ptr_base pointer arithmetic operators and indirection (disabled for void and function pointers)
|
||||
template<typename T, typename RT = void> using if_arithmetical_ptr_t = std::enable_if_t<
|
||||
!std::is_void<T>::value &&
|
||||
!std::is_function<T>::value,
|
||||
RT>;
|
||||
|
||||
template<typename T, typename AT = u32>
|
||||
struct _ptr_base
|
||||
template<typename T, typename AT = u32> class _ptr_base
|
||||
{
|
||||
AT m_addr; // don't access directly
|
||||
|
||||
using type = T;
|
||||
AT m_addr;
|
||||
|
||||
static_assert(!std::is_pointer<T>::value, "vm::_ptr_base<> error: invalid type (pointer)");
|
||||
static_assert(!std::is_reference<T>::value, "vm::_ptr_base<> error: invalid type (reference)");
|
||||
|
||||
AT addr() const
|
||||
public:
|
||||
using type = T;
|
||||
using addr_type = std::remove_cv_t<AT>;
|
||||
|
||||
_ptr_base() = default;
|
||||
|
||||
constexpr _ptr_base(addr_type addr, const addr_tag_t&)
|
||||
: m_addr(addr)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr addr_type addr() const
|
||||
{
|
||||
return m_addr;
|
||||
}
|
||||
|
||||
// get vm pointer to a struct member
|
||||
template<typename MT, typename T2, typename = if_comparable_t<T, T2>> _ptr_base<MT> ptr(MT T2::*const member) const
|
||||
template<typename MT, typename T2, typename = if_comparable_t<T, T2>> _ptr_base<MT> ptr(MT T2::*const mptr) const
|
||||
{
|
||||
const u32 offset = static_cast<u32>(reinterpret_cast<std::ptrdiff_t>(&(reinterpret_cast<T*>(0ull)->*member)));
|
||||
return{ VM_CAST(m_addr + offset) };
|
||||
return{ VM_CAST(m_addr) + get_offset(mptr), vm::addr };
|
||||
}
|
||||
|
||||
// get vm pointer to a struct member with array subscription
|
||||
template<typename MT, typename T2, typename = if_comparable_t<T, T2>> _ptr_base<std::remove_extent_t<MT>> ptr(MT T2::*const member, u32 index) const
|
||||
template<typename MT, typename T2, typename = if_comparable_t<T, T2>> _ptr_base<std::remove_extent_t<MT>> ptr(MT T2::*const mptr, u32 index) const
|
||||
{
|
||||
const u32 offset = static_cast<u32>(reinterpret_cast<std::ptrdiff_t>(&(reinterpret_cast<T*>(0ull)->*member)));
|
||||
return{ VM_CAST(m_addr + offset + sizeof32(T) * index) };
|
||||
return{ VM_CAST(m_addr) + get_offset(mptr) + sizeof32(T) * index, vm::addr };
|
||||
}
|
||||
|
||||
// get vm reference to a struct member
|
||||
template<typename MT, typename T2, typename = if_comparable_t<T, T2>> _ref_base<MT> ref(MT T2::*const member) const
|
||||
template<typename MT, typename T2, typename = if_comparable_t<T, T2>> _ref_base<MT> ref(MT T2::*const mptr) const
|
||||
{
|
||||
const u32 offset = static_cast<u32>(reinterpret_cast<std::ptrdiff_t>(&(reinterpret_cast<T*>(0ull)->*member)));
|
||||
return{ VM_CAST(m_addr + offset) };
|
||||
return{ VM_CAST(m_addr) + get_offset(mptr), vm::addr };
|
||||
}
|
||||
|
||||
// get vm reference to a struct member with array subscription
|
||||
template<typename MT, typename T2, typename = if_comparable_t<T, T2>> _ref_base<std::remove_extent_t<MT>> ref(MT T2::*const member, u32 index) const
|
||||
template<typename MT, typename T2, typename = if_comparable_t<T, T2>> _ref_base<std::remove_extent_t<MT>> ref(MT T2::*const mptr, u32 index) const
|
||||
{
|
||||
const u32 offset = static_cast<u32>(reinterpret_cast<std::ptrdiff_t>(&(reinterpret_cast<T*>(0ull)->*member)));
|
||||
return{ VM_CAST(m_addr + offset + sizeof32(T) * index) };
|
||||
return{ VM_CAST(m_addr) + get_offset(mptr) + sizeof32(T) * index, vm::addr };
|
||||
}
|
||||
|
||||
// get vm reference
|
||||
_ref_base<T, u32> ref() const
|
||||
{
|
||||
return{ VM_CAST(m_addr) };
|
||||
return{ VM_CAST(m_addr), vm::addr };
|
||||
}
|
||||
|
||||
template<typename CT> std::enable_if_t<std::is_assignable<AT&, CT>::value> set(const CT& value)
|
||||
/*[[deprecated("Use constructor instead")]]*/ void set(addr_type value)
|
||||
{
|
||||
m_addr = value;
|
||||
}
|
||||
|
||||
template<typename AT2 = AT> static std::enable_if_t<std::is_constructible<AT, AT2>::value, _ptr_base> make(const AT2& addr)
|
||||
/*[[deprecated("Use constructor instead")]]*/ static _ptr_base make(addr_type addr)
|
||||
{
|
||||
const AT value = addr;
|
||||
return{ value };
|
||||
return{ addr, vm::addr };
|
||||
}
|
||||
|
||||
T* get_ptr() const
|
||||
{
|
||||
return vm::get_ptr<T>(VM_CAST(m_addr));
|
||||
return static_cast<T*>(vm::base(VM_CAST(m_addr)));
|
||||
}
|
||||
|
||||
T* priv_ptr() const
|
||||
T* get_ptr_priv() const
|
||||
{
|
||||
return vm::priv_ptr<T>(VM_CAST(m_addr));
|
||||
return static_cast<T*>(vm::base_priv(VM_CAST(m_addr)));
|
||||
}
|
||||
|
||||
T* operator ->() const
|
||||
{
|
||||
static_assert(!std::is_void<T>::value, "vm::_ptr_base<> error: operator-> is not available for void pointers");
|
||||
|
||||
return get_ptr();
|
||||
}
|
||||
|
||||
@ -99,59 +98,127 @@ namespace vm
|
||||
{
|
||||
static_assert(!std::is_void<T>::value, "vm::_ptr_base<> error: operator[] is not available for void pointers");
|
||||
|
||||
return vm::get_ref<T>(VM_CAST(m_addr + sizeof32(T) * index));
|
||||
return *static_cast<T*>(vm::base(VM_CAST(m_addr) + sizeof32(T) * index));
|
||||
}
|
||||
|
||||
// enable only the conversions which are originally possible between pointer types
|
||||
template<typename T2, typename AT2, typename = std::enable_if_t<std::is_convertible<T*, T2*>::value>> operator _ptr_base<T2, AT2>() const
|
||||
{
|
||||
return{ VM_CAST(m_addr) };
|
||||
return{ VM_CAST(m_addr), vm::addr };
|
||||
}
|
||||
|
||||
template<typename T2, typename = std::enable_if_t<std::is_convertible<T*, T2*>::value>> explicit operator T2*() const
|
||||
{
|
||||
return get_ptr();
|
||||
}
|
||||
//template<typename T2, typename = std::enable_if_t<std::is_convertible<T*, T2*>::value>> explicit operator T2*() const
|
||||
//{
|
||||
// return get_ptr();
|
||||
//}
|
||||
|
||||
explicit operator bool() const
|
||||
{
|
||||
return m_addr != 0;
|
||||
}
|
||||
|
||||
// test address alignment using alignof(T)
|
||||
// Test address for arbitrary alignment: (addr & (align - 1)) != 0
|
||||
bool aligned(u32 align) const
|
||||
{
|
||||
return (m_addr & (align - 1)) == 0;
|
||||
}
|
||||
|
||||
// Test address for type's alignment using alignof(T)
|
||||
bool aligned() const
|
||||
{
|
||||
return m_addr % alignof32(T) == 0;
|
||||
static_assert(!std::is_void<T>::value, "vm::_ptr_base<> error: aligned() is not available for void pointers");
|
||||
|
||||
return aligned(alignof32(T));
|
||||
}
|
||||
|
||||
// test address for arbitrary alignment or something
|
||||
force_inline explicit_bool_t operator %(to_ne_t<AT> right) const
|
||||
// Call aligned(value)
|
||||
explicit_bool_t operator %(u32 align) const
|
||||
{
|
||||
return m_addr % right != 0;
|
||||
return aligned(align);
|
||||
}
|
||||
|
||||
_ptr_base& operator =(const _ptr_base&) = default;
|
||||
// pointer increment (postfix)
|
||||
_ptr_base operator ++(int)
|
||||
{
|
||||
static_assert(!std::is_void<T>::value, "vm::_ptr_base<> error: operator++ is not available for void pointers");
|
||||
|
||||
const addr_type result = m_addr;
|
||||
m_addr = VM_CAST(m_addr) + sizeof32(T);
|
||||
return{ result, vm::addr };
|
||||
}
|
||||
|
||||
// pointer increment (prefix)
|
||||
_ptr_base& operator ++()
|
||||
{
|
||||
static_assert(!std::is_void<T>::value, "vm::_ptr_base<> error: operator++ is not available for void pointers");
|
||||
|
||||
m_addr = VM_CAST(m_addr) + sizeof32(T);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// pointer decrement (postfix)
|
||||
_ptr_base operator --(int)
|
||||
{
|
||||
static_assert(!std::is_void<T>::value, "vm::_ptr_base<> error: operator-- is not available for void pointers");
|
||||
|
||||
const addr_type result = m_addr;
|
||||
m_addr = VM_CAST(m_addr) - sizeof32(T);
|
||||
return{ result, vm::addr };
|
||||
}
|
||||
|
||||
// pointer decrement (prefix)
|
||||
_ptr_base& operator --()
|
||||
{
|
||||
static_assert(!std::is_void<T>::value, "vm::_ptr_base<> error: operator-- is not available for void pointers");
|
||||
|
||||
m_addr = VM_CAST(m_addr) - sizeof32(T);
|
||||
return *this;
|
||||
}
|
||||
|
||||
_ptr_base& operator +=(s32 count)
|
||||
{
|
||||
static_assert(!std::is_void<T>::value, "vm::_ptr_base<> error: operator+= is not available for void pointers");
|
||||
|
||||
m_addr = VM_CAST(m_addr) + count * sizeof32(T);
|
||||
return *this;
|
||||
}
|
||||
|
||||
_ptr_base& operator -=(s32 count)
|
||||
{
|
||||
static_assert(!std::is_void<T>::value, "vm::_ptr_base<> error: operator-= is not available for void pointers");
|
||||
|
||||
m_addr = VM_CAST(m_addr) - count * sizeof32(T);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename AT, typename RT, typename... T>
|
||||
struct _ptr_base<RT(T...), AT>
|
||||
template<typename AT, typename RT, typename... T> class _ptr_base<RT(T...), AT>
|
||||
{
|
||||
AT m_addr;
|
||||
|
||||
AT addr() const
|
||||
public:
|
||||
using addr_type = std::remove_cv_t<AT>;
|
||||
|
||||
_ptr_base() = default;
|
||||
|
||||
constexpr _ptr_base(addr_type addr, const addr_tag_t&)
|
||||
: m_addr(addr)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr addr_type addr() const
|
||||
{
|
||||
return m_addr;
|
||||
}
|
||||
|
||||
template<typename CT> std::enable_if_t<std::is_assignable<AT&, CT>::value> set(const CT& value)
|
||||
/*[[deprecated("Use constructor instead")]]*/ void set(addr_type value)
|
||||
{
|
||||
m_addr = value;
|
||||
}
|
||||
|
||||
template<typename AT2 = AT> static std::enable_if_t<std::is_constructible<AT, AT2>::value, _ptr_base> make(const AT2& addr)
|
||||
/*[[deprecated("Use constructor instead")]]*/ static _ptr_base make(addr_type addr)
|
||||
{
|
||||
const AT value = addr;
|
||||
return{ value };
|
||||
return{ addr, vm::addr };
|
||||
}
|
||||
|
||||
// defined in CB_FUNC.h, passing context is mandatory
|
||||
@ -163,19 +230,16 @@ namespace vm
|
||||
// conversion to another function pointer
|
||||
template<typename AT2> operator _ptr_base<RT(T...), AT2>() const
|
||||
{
|
||||
return{ VM_CAST(m_addr) };
|
||||
return{ VM_CAST(m_addr), vm::addr };
|
||||
}
|
||||
|
||||
explicit operator bool() const
|
||||
{
|
||||
return m_addr != 0;
|
||||
}
|
||||
|
||||
_ptr_base& operator =(const _ptr_base&) = default;
|
||||
};
|
||||
|
||||
template<typename AT, typename RT, typename... T>
|
||||
struct _ptr_base<RT(*)(T...), AT>
|
||||
template<typename AT, typename RT, typename... T> class _ptr_base<RT(*)(T...), AT>
|
||||
{
|
||||
AT m_addr;
|
||||
|
||||
@ -222,6 +286,18 @@ namespace vm
|
||||
|
||||
template<typename T, typename AT = u32> using cpptr = pptr<const T, AT>;
|
||||
template<typename T, typename AT = u32> using bcpptr = bpptr<const T, AT>;
|
||||
|
||||
// perform static_cast (for example, vm::ptr<void> to vm::ptr<char>)
|
||||
template<typename CT, typename T, typename AT, typename = decltype(static_cast<to_be_t<CT>*>(std::declval<T*>()))> inline _ptr_base<to_be_t<CT>> static_ptr_cast(const _ptr_base<T, AT>& other)
|
||||
{
|
||||
return{ VM_CAST(other.addr()), vm::addr };
|
||||
}
|
||||
|
||||
// perform const_cast (for example, vm::cptr<char> to vm::ptr<char>)
|
||||
template<typename CT, typename T, typename AT, typename = decltype(const_cast<to_be_t<CT>*>(std::declval<T*>()))> inline _ptr_base<to_be_t<CT>> const_ptr_cast(const _ptr_base<T, AT>& other)
|
||||
{
|
||||
return{ VM_CAST(other.addr()), vm::addr };
|
||||
}
|
||||
}
|
||||
|
||||
namespace psv
|
||||
@ -246,268 +322,203 @@ namespace vm
|
||||
|
||||
template<typename T> using cpptr = pptr<const T>;
|
||||
template<typename T> using lcpptr = lpptr<const T>;
|
||||
|
||||
// perform static_cast (for example, vm::ptr<void> to vm::ptr<char>)
|
||||
template<typename CT, typename T, typename AT, typename = decltype(static_cast<to_le_t<CT>*>(std::declval<T*>()))> inline _ptr_base<to_le_t<CT>> static_ptr_cast(const _ptr_base<T, AT>& other)
|
||||
{
|
||||
return{ VM_CAST(other.addr()), vm::addr };
|
||||
}
|
||||
|
||||
// perform const_cast (for example, vm::cptr<char> to vm::ptr<char>)
|
||||
template<typename CT, typename T, typename AT, typename = decltype(const_cast<to_le_t<CT>*>(std::declval<T*>()))> inline _ptr_base<to_le_t<CT>> const_ptr_cast(const _ptr_base<T, AT>& other)
|
||||
{
|
||||
return{ VM_CAST(other.addr()), vm::addr };
|
||||
}
|
||||
}
|
||||
|
||||
struct null_t
|
||||
{
|
||||
template<typename T, typename AT> operator _ptr_base<T, AT>() const
|
||||
{
|
||||
return{};
|
||||
return{ 0, vm::addr };
|
||||
}
|
||||
};
|
||||
|
||||
// vm::null is convertible to any vm::ptr type as null pointer in virtual memory
|
||||
static null_t null;
|
||||
|
||||
// perform static_cast (for example, vm::ptr<void> to vm::ptr<char>)
|
||||
template<typename CT, typename T, typename AT, typename = decltype(static_cast<CT*>(std::declval<T*>()))> inline _ptr_base<CT, AT> static_ptr_cast(const _ptr_base<T, AT>& other)
|
||||
// Call wait_op() for specified vm pointer
|
||||
template<typename T, typename AT, typename F, typename... Args> inline auto wait_op(named_thread_t& thread, const _ptr_base<T, AT>& ptr, F pred, Args&&... args) -> decltype(static_cast<void>(pred(args...)))
|
||||
{
|
||||
return{ other.m_addr };
|
||||
return wait_op(thread, ptr.addr(), sizeof32(T), std::move(pred), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// perform const_cast (for example, vm::cptr<char> to vm::ptr<char>)
|
||||
template<typename CT, typename T, typename AT, typename = decltype(const_cast<CT*>(std::declval<T*>()))> inline _ptr_base<CT, AT> const_ptr_cast(const _ptr_base<T, AT>& other)
|
||||
// Call notify_at() for specified vm pointer
|
||||
template<typename T, typename AT> inline void notify_at(const vm::_ptr_base<T, AT>& ptr)
|
||||
{
|
||||
return{ other.m_addr };
|
||||
}
|
||||
|
||||
// perform reinterpret_cast (for example, vm::ptr<char> to vm::ptr<u32>)
|
||||
template<typename CT, typename T, typename AT, typename = decltype(reinterpret_cast<CT*>(std::declval<T*>()))> inline _ptr_base<CT, AT> reinterpret_ptr_cast(const _ptr_base<T, AT>& other)
|
||||
{
|
||||
return{ other.m_addr };
|
||||
return notify_at(ptr.addr(), sizeof32(T));
|
||||
}
|
||||
}
|
||||
|
||||
// unary plus operator for vm::_ptr_base (always available)
|
||||
template<typename T, typename AT> inline vm::_ptr_base<T, AT> operator +(const vm::_ptr_base<T, AT>& ptr)
|
||||
template<typename T, typename AT> inline vm::_ptr_base<T> operator +(const vm::_ptr_base<T, AT>& ptr)
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// indirection operator for vm::_ptr_base
|
||||
template<typename T, typename AT> inline vm::if_arithmetical_ptr_t<T, T&> operator *(const vm::_ptr_base<T, AT>& ptr)
|
||||
template<typename T, typename AT> inline std::enable_if_t<std::is_object<T>::value, T&> operator *(const vm::_ptr_base<T, AT>& ptr)
|
||||
{
|
||||
return vm::get_ref<T>(VM_CAST(ptr.m_addr));
|
||||
}
|
||||
|
||||
// postfix increment operator for vm::_ptr_base
|
||||
template<typename T, typename AT> inline vm::if_arithmetical_ptr_t<T, vm::_ptr_base<T, AT>> operator ++(vm::_ptr_base<T, AT>& ptr, int)
|
||||
{
|
||||
const AT result = ptr.m_addr;
|
||||
ptr.m_addr += sizeof32(T);
|
||||
return{ result };
|
||||
}
|
||||
|
||||
// prefix increment operator for vm::_ptr_base
|
||||
template<typename T, typename AT> inline vm::if_arithmetical_ptr_t<T, vm::_ptr_base<T, AT>&> operator ++(vm::_ptr_base<T, AT>& ptr)
|
||||
{
|
||||
ptr.m_addr += sizeof32(T);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// postfix decrement operator for vm::_ptr_base
|
||||
template<typename T, typename AT> inline vm::if_arithmetical_ptr_t<T, vm::_ptr_base<T, AT>> operator --(vm::_ptr_base<T, AT>& ptr, int)
|
||||
{
|
||||
const AT result = ptr.m_addr;
|
||||
ptr.m_addr -= sizeof32(T);
|
||||
return{ result };
|
||||
}
|
||||
|
||||
// prefix decrement operator for vm::_ptr_base
|
||||
template<typename T, typename AT> inline vm::if_arithmetical_ptr_t<T, vm::_ptr_base<T, AT>&> operator --(vm::_ptr_base<T, AT>& ptr)
|
||||
{
|
||||
ptr.m_addr -= sizeof32(T);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// addition assignment operator for vm::_ptr_base (pointer += integer)
|
||||
template<typename T, typename AT> inline vm::if_arithmetical_ptr_t<T, vm::_ptr_base<T, AT>&> operator +=(vm::_ptr_base<T, AT>& ptr, to_ne_t<AT> count)
|
||||
{
|
||||
ptr.m_addr += count * sizeof32(T);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// subtraction assignment operator for vm::_ptr_base (pointer -= integer)
|
||||
template<typename T, typename AT> inline vm::if_arithmetical_ptr_t<T, vm::_ptr_base<T, AT>&> operator -=(vm::_ptr_base<T, AT>& ptr, to_ne_t<AT> count)
|
||||
{
|
||||
ptr.m_addr -= count * sizeof32(T);
|
||||
return ptr;
|
||||
return *ptr.get_ptr();
|
||||
}
|
||||
|
||||
// addition operator for vm::_ptr_base (pointer + integer)
|
||||
template<typename T, typename AT> inline vm::if_arithmetical_ptr_t<T, vm::_ptr_base<T, AT>> operator +(const vm::_ptr_base<T, AT>& ptr, to_ne_t<AT> count)
|
||||
template<typename T, typename AT> inline std::enable_if_t<std::is_object<T>::value, vm::_ptr_base<T>> operator +(const vm::_ptr_base<T, AT>& ptr, u32 count)
|
||||
{
|
||||
return{ ptr.m_addr + count * sizeof32(T) };
|
||||
return{ VM_CAST(ptr.addr()) + count * sizeof32(T), vm::addr };
|
||||
}
|
||||
|
||||
// addition operator for vm::_ptr_base (integer + pointer)
|
||||
template<typename T, typename AT> inline vm::if_arithmetical_ptr_t<T, vm::_ptr_base<T, AT>> operator +(to_ne_t<AT> count, const vm::_ptr_base<T, AT>& ptr)
|
||||
template<typename T, typename AT> inline std::enable_if_t<std::is_object<T>::value, vm::_ptr_base<T>> operator +(u32 count, const vm::_ptr_base<T, AT>& ptr)
|
||||
{
|
||||
return{ ptr.m_addr + count * sizeof32(T) };
|
||||
return{ VM_CAST(ptr.addr()) + count * sizeof32(T), vm::addr };
|
||||
}
|
||||
|
||||
// subtraction operator for vm::_ptr_base (pointer - integer)
|
||||
template<typename T, typename AT> inline vm::if_arithmetical_ptr_t<T, vm::_ptr_base<T, AT>> operator -(const vm::_ptr_base<T, AT>& ptr, to_ne_t<AT> count)
|
||||
template<typename T, typename AT> inline std::enable_if_t<std::is_object<T>::value, vm::_ptr_base<T>> operator -(const vm::_ptr_base<T, AT>& ptr, u32 count)
|
||||
{
|
||||
return{ ptr.m_addr - count * sizeof32(T) };
|
||||
return{ VM_CAST(ptr.addr()) - count * sizeof32(T), vm::addr };
|
||||
}
|
||||
|
||||
// pointer difference operator for vm::_ptr_base
|
||||
template<typename T1, typename AT1, typename T2, typename AT2> inline std::enable_if_t<
|
||||
!std::is_void<T1>::value &&
|
||||
!std::is_void<T2>::value &&
|
||||
!std::is_function<T1>::value &&
|
||||
!std::is_function<T2>::value &&
|
||||
std::is_object<T1>::value &&
|
||||
std::is_object<T2>::value &&
|
||||
std::is_same<std::remove_cv_t<T1>, std::remove_cv_t<T2>>::value,
|
||||
s32> operator -(const vm::_ptr_base<T1, AT1>& left, const vm::_ptr_base<T2, AT2>& right)
|
||||
{
|
||||
return static_cast<s32>(left.m_addr - right.m_addr) / sizeof32(T1);
|
||||
return static_cast<s32>(VM_CAST(left.addr()) - VM_CAST(right.addr())) / sizeof32(T1);
|
||||
}
|
||||
|
||||
// comparison operator for vm::_ptr_base (pointer1 == pointer2)
|
||||
template<typename T1, typename AT1, typename T2, typename AT2> vm::if_comparable_t<T1, T2, bool> operator ==(const vm::_ptr_base<T1, AT1>& left, const vm::_ptr_base<T2, AT2>& right)
|
||||
template<typename T1, typename AT1, typename T2, typename AT2> inline vm::if_comparable_t<T1, T2, bool> operator ==(const vm::_ptr_base<T1, AT1>& left, const vm::_ptr_base<T2, AT2>& right)
|
||||
{
|
||||
return left.m_addr == right.m_addr;
|
||||
return left.addr() == right.addr();
|
||||
}
|
||||
|
||||
template<typename T, typename AT> bool operator ==(const vm::null_t&, const vm::_ptr_base<T, AT>& ptr)
|
||||
template<typename T, typename AT> inline bool operator ==(const vm::null_t&, const vm::_ptr_base<T, AT>& ptr)
|
||||
{
|
||||
return ptr.m_addr == 0;
|
||||
return !ptr.operator bool();
|
||||
}
|
||||
|
||||
template<typename T, typename AT> bool operator ==(const vm::_ptr_base<T, AT>& ptr, const vm::null_t&)
|
||||
template<typename T, typename AT> inline bool operator ==(const vm::_ptr_base<T, AT>& ptr, const vm::null_t&)
|
||||
{
|
||||
return ptr.m_addr == 0;
|
||||
return !ptr.operator bool();
|
||||
}
|
||||
|
||||
// comparison operator for vm::_ptr_base (pointer1 != pointer2)
|
||||
template<typename T1, typename AT1, typename T2, typename AT2> vm::if_comparable_t<T1, T2, bool> operator !=(const vm::_ptr_base<T1, AT1>& left, const vm::_ptr_base<T2, AT2>& right)
|
||||
template<typename T1, typename AT1, typename T2, typename AT2> inline vm::if_comparable_t<T1, T2, bool> operator !=(const vm::_ptr_base<T1, AT1>& left, const vm::_ptr_base<T2, AT2>& right)
|
||||
{
|
||||
return left.m_addr != right.m_addr;
|
||||
return left.addr() != right.addr();
|
||||
}
|
||||
|
||||
template<typename T, typename AT> bool operator !=(const vm::null_t&, const vm::_ptr_base<T, AT>& ptr)
|
||||
template<typename T, typename AT> inline bool operator !=(const vm::null_t&, const vm::_ptr_base<T, AT>& ptr)
|
||||
{
|
||||
return ptr.m_addr != 0;
|
||||
return ptr.operator bool();
|
||||
}
|
||||
|
||||
template<typename T, typename AT> bool operator !=(const vm::_ptr_base<T, AT>& ptr, const vm::null_t&)
|
||||
template<typename T, typename AT> inline bool operator !=(const vm::_ptr_base<T, AT>& ptr, const vm::null_t&)
|
||||
{
|
||||
return ptr.m_addr != 0;
|
||||
return ptr.operator bool();
|
||||
}
|
||||
|
||||
// comparison operator for vm::_ptr_base (pointer1 < pointer2)
|
||||
template<typename T1, typename AT1, typename T2, typename AT2> vm::if_comparable_t<T1, T2, bool> operator <(const vm::_ptr_base<T1, AT1>& left, const vm::_ptr_base<T2, AT2>& right)
|
||||
template<typename T1, typename AT1, typename T2, typename AT2> inline vm::if_comparable_t<T1, T2, bool> operator <(const vm::_ptr_base<T1, AT1>& left, const vm::_ptr_base<T2, AT2>& right)
|
||||
{
|
||||
return left.m_addr < right.m_addr;
|
||||
return left.addr() < right.addr();
|
||||
}
|
||||
|
||||
template<typename T, typename AT> bool operator <(const vm::null_t&, const vm::_ptr_base<T, AT>& ptr)
|
||||
template<typename T, typename AT> inline bool operator <(const vm::null_t&, const vm::_ptr_base<T, AT>& ptr)
|
||||
{
|
||||
return ptr.m_addr != 0;
|
||||
return ptr.operator bool();
|
||||
}
|
||||
|
||||
template<typename T, typename AT> bool operator <(const vm::_ptr_base<T, AT>&, const vm::null_t&)
|
||||
template<typename T, typename AT> inline bool operator <(const vm::_ptr_base<T, AT>&, const vm::null_t&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// comparison operator for vm::_ptr_base (pointer1 <= pointer2)
|
||||
template<typename T1, typename AT1, typename T2, typename AT2> vm::if_comparable_t<T1, T2, bool> operator <=(const vm::_ptr_base<T1, AT1>& left, const vm::_ptr_base<T2, AT2>& right)
|
||||
template<typename T1, typename AT1, typename T2, typename AT2> inline vm::if_comparable_t<T1, T2, bool> operator <=(const vm::_ptr_base<T1, AT1>& left, const vm::_ptr_base<T2, AT2>& right)
|
||||
{
|
||||
return left.m_addr <= right.m_addr;
|
||||
return left.addr() <= right.addr();
|
||||
}
|
||||
|
||||
template<typename T, typename AT> bool operator <=(const vm::null_t&, const vm::_ptr_base<T, AT>&)
|
||||
template<typename T, typename AT> inline bool operator <=(const vm::null_t&, const vm::_ptr_base<T, AT>&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T, typename AT> bool operator <=(const vm::_ptr_base<T, AT>& ptr, const vm::null_t&)
|
||||
template<typename T, typename AT> inline bool operator <=(const vm::_ptr_base<T, AT>& ptr, const vm::null_t&)
|
||||
{
|
||||
return ptr.m_addr == 0;
|
||||
return !ptr.operator bool();
|
||||
}
|
||||
|
||||
// comparison operator for vm::_ptr_base (pointer1 > pointer2)
|
||||
template<typename T1, typename AT1, typename T2, typename AT2> vm::if_comparable_t<T1, T2, bool> operator >(const vm::_ptr_base<T1, AT1>& left, const vm::_ptr_base<T2, AT2>& right)
|
||||
template<typename T1, typename AT1, typename T2, typename AT2> inline vm::if_comparable_t<T1, T2, bool> operator >(const vm::_ptr_base<T1, AT1>& left, const vm::_ptr_base<T2, AT2>& right)
|
||||
{
|
||||
return left.m_addr > right.m_addr;
|
||||
return left.addr() > right.addr();
|
||||
}
|
||||
|
||||
template<typename T, typename AT> bool operator >(const vm::null_t&, const vm::_ptr_base<T, AT>&)
|
||||
template<typename T, typename AT> inline bool operator >(const vm::null_t&, const vm::_ptr_base<T, AT>&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename T, typename AT> bool operator >(const vm::_ptr_base<T, AT>& ptr, const vm::null_t&)
|
||||
template<typename T, typename AT> inline bool operator >(const vm::_ptr_base<T, AT>& ptr, const vm::null_t&)
|
||||
{
|
||||
return ptr.m_addr != 0;
|
||||
return ptr.operator bool();
|
||||
}
|
||||
|
||||
// comparison operator for vm::_ptr_base (pointer1 >= pointer2)
|
||||
template<typename T1, typename AT1, typename T2, typename AT2> vm::if_comparable_t<T1, T2, bool> operator >=(const vm::_ptr_base<T1, AT1>& left, const vm::_ptr_base<T2, AT2>& right)
|
||||
template<typename T1, typename AT1, typename T2, typename AT2> inline vm::if_comparable_t<T1, T2, bool> operator >=(const vm::_ptr_base<T1, AT1>& left, const vm::_ptr_base<T2, AT2>& right)
|
||||
{
|
||||
return left.m_addr >= right.m_addr;
|
||||
return left.addr() >= right.addr();
|
||||
}
|
||||
|
||||
template<typename T, typename AT> bool operator >=(const vm::null_t&, const vm::_ptr_base<T, AT>& ptr)
|
||||
template<typename T, typename AT> inline bool operator >=(const vm::null_t&, const vm::_ptr_base<T, AT>& ptr)
|
||||
{
|
||||
return ptr.m_addr == 0;
|
||||
return !ptr.operator bool();
|
||||
}
|
||||
|
||||
template<typename T, typename AT> bool operator >=(const vm::_ptr_base<T, AT>&, const vm::null_t&)
|
||||
template<typename T, typename AT> inline bool operator >=(const vm::_ptr_base<T, AT>&, const vm::null_t&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// external specialization for is_be_t<> (true if AT is be_t<>)
|
||||
// external specialization for to_se<> (change AT endianness to BE/LE)
|
||||
|
||||
template<typename T, typename AT>
|
||||
struct is_be_t<vm::_ptr_base<T, AT>> : public std::integral_constant<bool, is_be_t<AT>::value>
|
||||
template<typename T, typename AT, bool Se> struct to_se<vm::_ptr_base<T, AT>, Se>
|
||||
{
|
||||
using type = vm::_ptr_base<T, typename to_se<AT, Se>::type>;
|
||||
};
|
||||
|
||||
// external specialization for is_le_t<> (true if AT is le_t<>)
|
||||
// external specialization for to_ne<> (change AT endianness to native)
|
||||
|
||||
template<typename T, typename AT>
|
||||
struct is_le_t<vm::_ptr_base<T, AT>> : public std::integral_constant<bool, is_le_t<AT>::value>
|
||||
template<typename T, typename AT> struct to_ne<vm::_ptr_base<T, AT>>
|
||||
{
|
||||
};
|
||||
|
||||
// external specialization for to_ne_t<> (change AT endianness to native)
|
||||
|
||||
template<typename T, typename AT>
|
||||
struct to_ne<vm::_ptr_base<T, AT>>
|
||||
{
|
||||
using type = vm::_ptr_base<T, to_ne_t<AT>>;
|
||||
};
|
||||
|
||||
// external specialization for to_be_t<> (change AT endianness to BE)
|
||||
|
||||
template<typename T, typename AT>
|
||||
struct to_be<vm::_ptr_base<T, AT>>
|
||||
{
|
||||
using type = vm::_ptr_base<T, to_be_t<AT>>;
|
||||
};
|
||||
|
||||
// external specialization for to_le_t<> (change AT endianness to LE)
|
||||
|
||||
template<typename T, typename AT>
|
||||
struct to_le<vm::_ptr_base<T, AT>>
|
||||
{
|
||||
using type = vm::_ptr_base<T, to_le_t<AT>>;
|
||||
using type = vm::_ptr_base<T, typename to_ne<AT>::type>;
|
||||
};
|
||||
|
||||
namespace fmt
|
||||
{
|
||||
// external specialization for fmt::format function
|
||||
|
||||
template<typename T, typename AT>
|
||||
struct unveil<vm::_ptr_base<T, AT>, false>
|
||||
template<typename T, typename AT> struct unveil<vm::_ptr_base<T, AT>, false>
|
||||
{
|
||||
using result_type = typename unveil<AT>::result_type;
|
||||
|
||||
force_inline static result_type get_value(const vm::_ptr_base<T, AT>& arg)
|
||||
static inline result_type get_value(const vm::_ptr_base<T, AT>& arg)
|
||||
{
|
||||
return unveil<AT>::get_value(arg.addr());
|
||||
}
|
||||
@ -516,38 +527,34 @@ namespace fmt
|
||||
|
||||
// external specializations for PPU GPR (SC_FUNC.h, CB_FUNC.h)
|
||||
|
||||
template<typename T, bool is_enum>
|
||||
struct cast_ppu_gpr;
|
||||
template<typename T, bool is_enum> struct cast_ppu_gpr;
|
||||
|
||||
template<typename T, typename AT>
|
||||
struct cast_ppu_gpr<vm::_ptr_base<T, AT>, false>
|
||||
template<typename T, typename AT> struct cast_ppu_gpr<vm::_ptr_base<T, AT>, false>
|
||||
{
|
||||
force_inline static u64 to_gpr(const vm::_ptr_base<T, AT>& value)
|
||||
static inline u64 to_gpr(const vm::_ptr_base<T, AT>& value)
|
||||
{
|
||||
return cast_ppu_gpr<AT, std::is_enum<AT>::value>::to_gpr(value.addr());
|
||||
}
|
||||
|
||||
force_inline static vm::_ptr_base<T, AT> from_gpr(const u64 reg)
|
||||
static inline vm::_ptr_base<T, AT> from_gpr(const u64 reg)
|
||||
{
|
||||
return vm::_ptr_base<T, AT>::make(cast_ppu_gpr<AT, std::is_enum<AT>::value>::from_gpr(reg));
|
||||
return{ cast_ppu_gpr<AT, std::is_enum<AT>::value>::from_gpr(reg), vm::addr };
|
||||
}
|
||||
};
|
||||
|
||||
// external specializations for ARMv7 GPR
|
||||
|
||||
template<typename T, bool is_enum>
|
||||
struct cast_armv7_gpr;
|
||||
template<typename T, bool is_enum> struct cast_armv7_gpr;
|
||||
|
||||
template<typename T, typename AT>
|
||||
struct cast_armv7_gpr<vm::_ptr_base<T, AT>, false>
|
||||
template<typename T, typename AT> struct cast_armv7_gpr<vm::_ptr_base<T, AT>, false>
|
||||
{
|
||||
force_inline static u32 to_gpr(const vm::_ptr_base<T, AT>& value)
|
||||
static inline u32 to_gpr(const vm::_ptr_base<T, AT>& value)
|
||||
{
|
||||
return cast_armv7_gpr<AT, std::is_enum<AT>::value>::to_gpr(value.addr());
|
||||
}
|
||||
|
||||
force_inline static vm::_ptr_base<T, AT> from_gpr(const u32 reg)
|
||||
static inline vm::_ptr_base<T, AT> from_gpr(const u32 reg)
|
||||
{
|
||||
return vm::_ptr_base<T, AT>::make(cast_armv7_gpr<AT, std::is_enum<AT>::value>::from_gpr(reg));
|
||||
return{ cast_armv7_gpr<AT, std::is_enum<AT>::value>::from_gpr(reg), vm::addr };
|
||||
}
|
||||
};
|
||||
|
@ -2,78 +2,138 @@
|
||||
|
||||
namespace vm
|
||||
{
|
||||
template<typename T, typename AT> struct _ptr_base;
|
||||
// Tag which allows to construct vm objects from the address value
|
||||
static struct addr_tag_t {} constexpr addr{};
|
||||
|
||||
template<typename T, typename AT = u32>
|
||||
struct _ref_base
|
||||
template<typename T, typename AT> class _ptr_base;
|
||||
|
||||
template<typename T, typename AT = u32> class _ref_base
|
||||
{
|
||||
AT m_addr; // don't access directly
|
||||
AT m_addr;
|
||||
|
||||
static_assert(!std::is_pointer<T>::value, "vm::_ref_base<> error: invalid type (pointer)");
|
||||
static_assert(!std::is_reference<T>::value, "vm::_ref_base<> error: invalid type (reference)");
|
||||
static_assert(!std::is_function<T>::value, "vm::_ref_base<> error: invalid type (function)");
|
||||
static_assert(!std::is_void<T>::value, "vm::_ref_base<> error: invalid type (void)");
|
||||
|
||||
AT addr() const
|
||||
public:
|
||||
using type = T;
|
||||
using addr_type = std::remove_cv_t<AT>;
|
||||
|
||||
_ref_base() = default;
|
||||
|
||||
_ref_base(const _ref_base&) = default;
|
||||
|
||||
constexpr _ref_base(addr_type addr, const addr_tag_t&)
|
||||
: m_addr(addr)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr addr_type addr() const
|
||||
{
|
||||
return m_addr;
|
||||
}
|
||||
|
||||
template<typename AT2 = AT> static std::enable_if_t<std::is_constructible<AT, AT2>::value, _ref_base> make(const AT2& addr)
|
||||
{
|
||||
return{ addr };
|
||||
}
|
||||
|
||||
T& get_ref() const
|
||||
{
|
||||
return vm::get_ref<T>(VM_CAST(m_addr));
|
||||
return *static_cast<T*>(vm::base(VM_CAST(m_addr)));
|
||||
}
|
||||
|
||||
T& priv_ref() const
|
||||
// convert to vm pointer
|
||||
vm::_ptr_base<T, u32> ptr() const
|
||||
{
|
||||
return vm::priv_ref<T>(VM_CAST(m_addr));
|
||||
return{ VM_CAST(m_addr), vm::addr };
|
||||
}
|
||||
|
||||
// TODO: conversion operator (seems hard to define it correctly)
|
||||
//template<typename CT, typename = std::enable_if_t<std::is_convertible<T, CT>::value || std::is_convertible<to_ne_t<T>, CT>::value>> operator CT() const
|
||||
//{
|
||||
// return get_ref();
|
||||
//}
|
||||
|
||||
operator to_ne_t<T>() const
|
||||
{
|
||||
return get_ref();
|
||||
}
|
||||
|
||||
explicit operator T&() const
|
||||
operator T&() const
|
||||
{
|
||||
return get_ref();
|
||||
}
|
||||
|
||||
// convert to vm pointer
|
||||
vm::_ptr_base<T, u32> operator &() const
|
||||
{
|
||||
return{ VM_CAST(m_addr) };
|
||||
}
|
||||
|
||||
// copy assignment operator:
|
||||
// returns T& by default, this may be wrong if called assignment operator has different return type
|
||||
T& operator =(const _ref_base& right)
|
||||
{
|
||||
static_assert(!std::is_const<T>::value, "vm::_ref_base<> error: operator= is not available for const reference");
|
||||
|
||||
return get_ref() = right.get_ref();
|
||||
}
|
||||
|
||||
template<typename CT, typename AT2> auto operator =(const _ref_base<CT, AT2>& right) const -> decltype(std::declval<T&>() = std::declval<CT>())
|
||||
{
|
||||
return get_ref() = right.get_ref();
|
||||
}
|
||||
|
||||
template<typename CT> auto operator =(const CT& right) const -> decltype(std::declval<T&>() = std::declval<CT>())
|
||||
T& operator =(const T& right) const
|
||||
{
|
||||
return get_ref() = right;
|
||||
}
|
||||
|
||||
decltype(auto) operator ++(int)
|
||||
{
|
||||
return get_ref()++;
|
||||
}
|
||||
|
||||
decltype(auto) operator ++()
|
||||
{
|
||||
return ++get_ref();
|
||||
}
|
||||
|
||||
decltype(auto) operator --(int)
|
||||
{
|
||||
return get_ref()--;
|
||||
}
|
||||
|
||||
decltype(auto) operator --()
|
||||
{
|
||||
return --get_ref();
|
||||
}
|
||||
|
||||
template<typename T2> decltype(auto) operator +=(const T2& right)
|
||||
{
|
||||
return get_ref() += right;
|
||||
}
|
||||
|
||||
template<typename T2> decltype(auto) operator -=(const T2& right)
|
||||
{
|
||||
return get_ref() -= right;
|
||||
}
|
||||
|
||||
template<typename T2> decltype(auto) operator *=(const T2& right)
|
||||
{
|
||||
return get_ref() *= right;
|
||||
}
|
||||
|
||||
template<typename T2> decltype(auto) operator /=(const T2& right)
|
||||
{
|
||||
return get_ref() /= right;
|
||||
}
|
||||
|
||||
template<typename T2> decltype(auto) operator %=(const T2& right)
|
||||
{
|
||||
return get_ref() %= right;
|
||||
}
|
||||
|
||||
template<typename T2> decltype(auto) operator &=(const T2& right)
|
||||
{
|
||||
return get_ref() &= right;
|
||||
}
|
||||
|
||||
template<typename T2> decltype(auto) operator |=(const T2& right)
|
||||
{
|
||||
return get_ref() |= right;
|
||||
}
|
||||
|
||||
template<typename T2> decltype(auto) operator ^=(const T2& right)
|
||||
{
|
||||
return get_ref() ^= right;
|
||||
}
|
||||
|
||||
template<typename T2> decltype(auto) operator <<=(const T2& right)
|
||||
{
|
||||
return get_ref() <<= right;
|
||||
}
|
||||
|
||||
template<typename T2> decltype(auto) operator >>=(const T2& right)
|
||||
{
|
||||
return get_ref() >>= right;
|
||||
}
|
||||
};
|
||||
|
||||
// Native endianness reference to LE data
|
||||
@ -113,138 +173,29 @@ namespace vm
|
||||
}
|
||||
}
|
||||
|
||||
// postfix increment operator for vm::_ref_base
|
||||
template<typename T, typename AT> inline auto operator ++(const vm::_ref_base<T, AT>& ref, int) -> decltype(std::declval<T&>()++)
|
||||
{
|
||||
return ref.get_ref()++;
|
||||
}
|
||||
// external specialization for to_se<> (change AT's endianness to BE/LE)
|
||||
|
||||
// prefix increment operator for vm::_ref_base
|
||||
template<typename T, typename AT> inline auto operator ++(const vm::_ref_base<T, AT>& ref) -> decltype(++std::declval<T&>())
|
||||
{
|
||||
return ++ref.get_ref();
|
||||
}
|
||||
|
||||
// postfix decrement operator for vm::_ref_base
|
||||
template<typename T, typename AT> inline auto operator --(const vm::_ref_base<T, AT>& ref, int) -> decltype(std::declval<T&>()--)
|
||||
{
|
||||
return ref.get_ref()--;
|
||||
}
|
||||
|
||||
// prefix decrement operator for vm::_ref_base
|
||||
template<typename T, typename AT> inline auto operator --(const vm::_ref_base<T, AT>& ref) -> decltype(--std::declval<T&>())
|
||||
{
|
||||
return --ref.get_ref();
|
||||
}
|
||||
|
||||
// addition assignment operator for vm::_ref_base
|
||||
template<typename T, typename AT, typename T2> inline auto operator +=(const vm::_ref_base<T, AT>& ref, const T2& right) -> decltype(std::declval<T&>() += std::declval<T2>())
|
||||
{
|
||||
return ref.get_ref() += right;
|
||||
}
|
||||
|
||||
// subtraction assignment operator for vm::_ref_base
|
||||
template<typename T, typename AT, typename T2> inline auto operator -=(const vm::_ref_base<T, AT>& ref, const T2& right) -> decltype(std::declval<T&>() -= std::declval<T2>())
|
||||
{
|
||||
return ref.get_ref() -= right;
|
||||
}
|
||||
|
||||
// multiplication assignment operator for vm::_ref_base
|
||||
template<typename T, typename AT, typename T2> inline auto operator *=(const vm::_ref_base<T, AT>& ref, const T2& right) -> decltype(std::declval<T&>() *= std::declval<T2>())
|
||||
{
|
||||
return ref.get_ref() *= right;
|
||||
}
|
||||
|
||||
// division assignment operator for vm::_ref_base
|
||||
template<typename T, typename AT, typename T2> inline auto operator /=(const vm::_ref_base<T, AT>& ref, const T2& right) -> decltype(std::declval<T&>() /= std::declval<T2>())
|
||||
{
|
||||
return ref.get_ref() /= right;
|
||||
}
|
||||
|
||||
// modulo assignment operator for vm::_ref_base
|
||||
template<typename T, typename AT, typename T2> inline auto operator %=(const vm::_ref_base<T, AT>& ref, const T2& right) -> decltype(std::declval<T&>() %= std::declval<T2>())
|
||||
{
|
||||
return ref.get_ref() %= right;
|
||||
}
|
||||
|
||||
// bitwise AND assignment operator for vm::_ref_base
|
||||
template<typename T, typename AT, typename T2> inline auto operator &=(const vm::_ref_base<T, AT>& ref, const T2& right) -> decltype(std::declval<T&>() &= std::declval<T2>())
|
||||
{
|
||||
return ref.get_ref() &= right;
|
||||
}
|
||||
|
||||
// bitwise OR assignment operator for vm::_ref_base
|
||||
template<typename T, typename AT, typename T2> inline auto operator |=(const vm::_ref_base<T, AT>& ref, const T2& right) -> decltype(std::declval<T&>() |= std::declval<T2>())
|
||||
{
|
||||
return ref.get_ref() |= right;
|
||||
}
|
||||
|
||||
// bitwise XOR assignment operator for vm::_ref_base
|
||||
template<typename T, typename AT, typename T2> inline auto operator ^=(const vm::_ref_base<T, AT>& ref, const T2& right) -> decltype(std::declval<T&>() ^= std::declval<T2>())
|
||||
{
|
||||
return ref.get_ref() ^= right;
|
||||
}
|
||||
|
||||
// bitwise left shift assignment operator for vm::_ref_base
|
||||
template<typename T, typename AT, typename T2> inline auto operator <<=(const vm::_ref_base<T, AT>& ref, const T2& right) -> decltype(std::declval<T&>() <<= std::declval<T2>())
|
||||
{
|
||||
return ref.get_ref() <<= right;
|
||||
}
|
||||
|
||||
// bitwise right shift assignment operator for vm::_ref_base
|
||||
template<typename T, typename AT, typename T2> inline auto operator >>=(const vm::_ref_base<T, AT>& ref, const T2& right) -> decltype(std::declval<T&>() >>= std::declval<T2>())
|
||||
{
|
||||
return ref.get_ref() >>= right;
|
||||
}
|
||||
|
||||
// external specialization for is_be_t<> (true if AT's endianness is BE)
|
||||
|
||||
template<typename T, typename AT>
|
||||
struct is_be_t<vm::_ref_base<T, AT>> : public std::integral_constant<bool, is_be_t<AT>::value>
|
||||
template<typename T, typename AT, bool Se> struct to_se<vm::_ref_base<T, AT>, Se>
|
||||
{
|
||||
using type = vm::_ref_base<T, typename to_se<AT, Se>::type>;
|
||||
};
|
||||
|
||||
// external specialization for is_le_t<> (true if AT's endianness is LE)
|
||||
// external specialization for to_ne<> (change AT's endianness to native)
|
||||
|
||||
template<typename T, typename AT>
|
||||
struct is_le_t<vm::_ref_base<T, AT>> : public std::integral_constant<bool, is_le_t<AT>::value>
|
||||
template<typename T, typename AT> struct to_ne<vm::_ref_base<T, AT>>
|
||||
{
|
||||
};
|
||||
|
||||
// external specialization for to_ne_t<> (change AT's endianness to native)
|
||||
|
||||
template<typename T, typename AT>
|
||||
struct to_ne<vm::_ref_base<T, AT>>
|
||||
{
|
||||
using type = vm::_ref_base<T, to_ne_t<AT>>;
|
||||
};
|
||||
|
||||
// external specialization for to_be_t<> (change AT's endianness to BE)
|
||||
|
||||
template<typename T, typename AT>
|
||||
struct to_be<vm::_ref_base<T, AT>>
|
||||
{
|
||||
using type = vm::_ref_base<T, to_be_t<AT>>;
|
||||
};
|
||||
|
||||
// external specialization for to_le_t<> (change AT's endianness to LE)
|
||||
|
||||
template<typename T, typename AT>
|
||||
struct to_le<vm::_ref_base<T, AT>>
|
||||
{
|
||||
using type = vm::_ref_base<T, to_le_t<AT>>;
|
||||
using type = vm::_ref_base<T, typename to_ne<AT>::type>;
|
||||
};
|
||||
|
||||
namespace fmt
|
||||
{
|
||||
// external specialization for fmt::format function
|
||||
|
||||
template<typename T, typename AT>
|
||||
struct unveil<vm::_ref_base<T, AT>, false>
|
||||
template<typename T, typename AT> struct unveil<vm::_ref_base<T, AT>, false>
|
||||
{
|
||||
using result_type = typename unveil<AT>::result_type;
|
||||
|
||||
force_inline static result_type get_value(const vm::_ref_base<T, AT>& arg)
|
||||
static inline result_type get_value(const vm::_ref_base<T, AT>& arg)
|
||||
{
|
||||
return unveil<AT>::get_value(arg.addr());
|
||||
}
|
||||
@ -253,38 +204,34 @@ namespace fmt
|
||||
|
||||
// external specializations for PPU GPR (SC_FUNC.h, CB_FUNC.h)
|
||||
|
||||
template<typename T, bool is_enum>
|
||||
struct cast_ppu_gpr;
|
||||
template<typename T, bool is_enum> struct cast_ppu_gpr;
|
||||
|
||||
template<typename T, typename AT>
|
||||
struct cast_ppu_gpr<vm::_ref_base<T, AT>, false>
|
||||
template<typename T, typename AT> struct cast_ppu_gpr<vm::_ref_base<T, AT>, false>
|
||||
{
|
||||
force_inline static u64 to_gpr(const vm::_ref_base<T, AT>& value)
|
||||
static inline u64 to_gpr(const vm::_ref_base<T, AT>& value)
|
||||
{
|
||||
return cast_ppu_gpr<AT, std::is_enum<AT>::value>::to_gpr(value.addr());
|
||||
}
|
||||
|
||||
force_inline static vm::_ref_base<T, AT> from_gpr(const u64 reg)
|
||||
static inline vm::_ref_base<T, AT> from_gpr(const u64 reg)
|
||||
{
|
||||
return vm::_ref_base<T, AT>::make(cast_ppu_gpr<AT, std::is_enum<AT>::value>::from_gpr(reg));
|
||||
return{ cast_ppu_gpr<AT, std::is_enum<AT>::value>::from_gpr(reg), vm::addr };
|
||||
}
|
||||
};
|
||||
|
||||
// external specializations for ARMv7 GPR
|
||||
|
||||
template<typename T, bool is_enum>
|
||||
struct cast_armv7_gpr;
|
||||
template<typename T, bool is_enum> struct cast_armv7_gpr;
|
||||
|
||||
template<typename T, typename AT>
|
||||
struct cast_armv7_gpr<vm::_ref_base<T, AT>, false>
|
||||
template<typename T, typename AT> struct cast_armv7_gpr<vm::_ref_base<T, AT>, false>
|
||||
{
|
||||
force_inline static u32 to_gpr(const vm::_ref_base<T, AT>& value)
|
||||
static inline u32 to_gpr(const vm::_ref_base<T, AT>& value)
|
||||
{
|
||||
return cast_armv7_gpr<AT, std::is_enum<AT>::value>::to_gpr(value.addr());
|
||||
}
|
||||
|
||||
force_inline static vm::_ref_base<T, AT> from_gpr(const u32 reg)
|
||||
static inline vm::_ref_base<T, AT> from_gpr(const u32 reg)
|
||||
{
|
||||
return vm::_ref_base<T, AT>::make(cast_armv7_gpr<AT, std::is_enum<AT>::value>::from_gpr(reg));
|
||||
return{ cast_armv7_gpr<AT, std::is_enum<AT>::value>::from_gpr(reg), vm::addr };
|
||||
}
|
||||
};
|
||||
|
@ -1,34 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
class CPUThread;
|
||||
|
||||
namespace vm
|
||||
{
|
||||
template<typename T> class page_alloc_t
|
||||
template<memory_location_t Location = vm::main> class page_alloc_t
|
||||
{
|
||||
u32 m_addr;
|
||||
|
||||
void dealloc()
|
||||
public:
|
||||
static inline u32 alloc(u32 size, u32 align)
|
||||
{
|
||||
if (m_addr)
|
||||
{
|
||||
vm::dealloc_verbose_nothrow(m_addr);
|
||||
}
|
||||
return vm::alloc(size, Location, std::max<u32>(align, 4096));
|
||||
}
|
||||
|
||||
static inline void dealloc(u32 addr, u32 size) noexcept
|
||||
{
|
||||
return vm::dealloc_verbose_nothrow(addr, Location);
|
||||
}
|
||||
|
||||
public:
|
||||
page_alloc_t()
|
||||
: m_addr(0)
|
||||
{
|
||||
}
|
||||
|
||||
page_alloc_t(vm::memory_location_t location, u32 count = 1)
|
||||
: m_addr(vm::alloc(sizeof32(T) * count, location, std::max<u32>(alignof32(T), 4096)))
|
||||
page_alloc_t(u32 size, u32 align)
|
||||
: m_addr(alloc(size, align))
|
||||
{
|
||||
}
|
||||
|
||||
page_alloc_t(const page_alloc_t&) = delete;
|
||||
|
||||
page_alloc_t(page_alloc_t&& other)
|
||||
: m_addr(other.m_addr)
|
||||
{
|
||||
@ -37,11 +35,12 @@ namespace vm
|
||||
|
||||
~page_alloc_t()
|
||||
{
|
||||
this->dealloc();
|
||||
if (m_addr)
|
||||
{
|
||||
dealloc(m_addr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
page_alloc_t& operator =(const page_alloc_t&) = delete;
|
||||
|
||||
page_alloc_t& operator =(page_alloc_t&& other)
|
||||
{
|
||||
std::swap(m_addr, other.m_addr);
|
||||
@ -55,37 +54,37 @@ namespace vm
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T> class stack_alloc_t
|
||||
class stack_alloc_t
|
||||
{
|
||||
u32 m_addr;
|
||||
u32 m_old_pos; // TODO: use the stack to save it?
|
||||
|
||||
CPUThread& m_thread;
|
||||
u32 m_size;
|
||||
|
||||
public:
|
||||
stack_alloc_t() = delete;
|
||||
|
||||
stack_alloc_t(CPUThread& thread, u32 count = 1)
|
||||
: m_addr(vm::stack_push(thread, sizeof32(T) * count, alignof32(T), m_old_pos))
|
||||
, m_thread(thread)
|
||||
static inline u32 alloc(u32 size, u32 align)
|
||||
{
|
||||
return vm::stack_push(size, align);
|
||||
}
|
||||
|
||||
~stack_alloc_t() noexcept(false) // allow exceptions
|
||||
static inline void dealloc(u32 addr, u32 size)
|
||||
{
|
||||
if (!std::uncaught_exception()) // don't call during stack unwinding (it's pointless anyway)
|
||||
if (!std::uncaught_exception()) // Don't call during stack unwinding
|
||||
{
|
||||
vm::stack_pop(m_thread, m_addr, m_old_pos);
|
||||
vm::stack_pop(addr, size);
|
||||
}
|
||||
}
|
||||
|
||||
stack_alloc_t(const stack_alloc_t&) = delete;
|
||||
stack_alloc_t(u32 size, u32 align)
|
||||
: m_addr(alloc(size, align))
|
||||
, m_size(size)
|
||||
{
|
||||
}
|
||||
|
||||
~stack_alloc_t() noexcept(false) // Allow exceptions
|
||||
{
|
||||
dealloc(m_addr, m_size);
|
||||
}
|
||||
|
||||
stack_alloc_t(stack_alloc_t&&) = delete;
|
||||
|
||||
stack_alloc_t& operator =(const stack_alloc_t&) = delete;
|
||||
|
||||
stack_alloc_t& operator =(stack_alloc_t&&) = delete;
|
||||
stack_alloc_t(const stack_alloc_t&) = delete; // Delete copy/move constructors and copy/move operators
|
||||
|
||||
u32 get_addr() const
|
||||
{
|
||||
@ -93,31 +92,167 @@ namespace vm
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, template<typename> class A> class _var_base final : public _ptr_base<T>, private A<T>
|
||||
{
|
||||
using _ptr_base<T>::m_addr;
|
||||
// _var_base prototype (T - data type, A - allocation traits)
|
||||
template<typename T, typename A> class _var_base;
|
||||
|
||||
using allocation = A<T>;
|
||||
// _var_base general specialization (single object of type T)
|
||||
template<typename T, typename A> class _var_base final : public _ptr_base<T, const u32>
|
||||
{
|
||||
using pointer = _ptr_base<T, const u32>;
|
||||
|
||||
public:
|
||||
template<typename... Args, typename = std::enable_if_t<std::is_constructible<A<T>, Args...>::value>> _var_base(Args&&... args)
|
||||
: allocation(std::forward<Args>(args)...)
|
||||
template<typename... Args, typename = std::enable_if_t<std::is_constructible<T, Args...>::value>> _var_base(Args&&... args)
|
||||
: pointer(A::alloc(sizeof32(T), alignof32(T)), vm::addr)
|
||||
{
|
||||
m_addr = allocation::get_addr();
|
||||
// Call the constructor with specified arguments
|
||||
new(pointer::get_ptr()) T(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
_var_base(const _var_base&) = delete; // Delete copy/move constructors and copy/move operators
|
||||
|
||||
~_var_base() noexcept(noexcept(std::declval<T&>().~T()) && noexcept(A::dealloc(0, 0)))
|
||||
{
|
||||
// Call the destructor
|
||||
pointer::get_ptr()->~T();
|
||||
|
||||
// Deallocate memory
|
||||
A::dealloc(pointer::addr(), sizeof32(T));
|
||||
}
|
||||
|
||||
// Remove operator []
|
||||
std::add_lvalue_reference_t<T> operator [](u32 index) const = delete;
|
||||
};
|
||||
|
||||
template<typename T, template<typename> class A = vm::stack_alloc_t> using varl = _var_base<to_le_t<T>, A>;
|
||||
// _var_base unknown length array specialization
|
||||
template<typename T, typename A> class _var_base<T[], A> final : public _ptr_base<T, const u32>
|
||||
{
|
||||
using pointer = _ptr_base<T, const u32>;
|
||||
|
||||
template<typename T, template<typename> class A = vm::stack_alloc_t> using varb = _var_base<to_be_t<T>, A>;
|
||||
u32 m_count;
|
||||
|
||||
public:
|
||||
_var_base(u32 count)
|
||||
: pointer(A::alloc(sizeof32(T) * count, alignof32(T)), vm::addr)
|
||||
, m_count(count)
|
||||
{
|
||||
// Call the default constructor for each element
|
||||
new(pointer::get_ptr()) T[count]();
|
||||
}
|
||||
|
||||
template<typename T2> _var_base(u32 count, T2 it)
|
||||
: pointer(A::alloc(sizeof32(T) * count, alignof32(T)), vm::addr)
|
||||
, m_count(count)
|
||||
{
|
||||
// Initialize each element using iterator
|
||||
std::uninitialized_copy_n<T2>(it, count, const_cast<std::remove_cv_t<T>*>(pointer::get_ptr()));
|
||||
}
|
||||
|
||||
_var_base(const _var_base&) = delete; // Delete copy/move constructors and copy/move operators
|
||||
|
||||
~_var_base() noexcept(noexcept(std::declval<T&>().~T()) && noexcept(A::dealloc(0, 0)))
|
||||
{
|
||||
// Call the destructor for each element
|
||||
for (u32 i = m_count - 1; ~i; i--) pointer::operator [](i).~T();
|
||||
|
||||
// Deallocate memory
|
||||
A::dealloc(pointer::addr(), sizeof32(T) * m_count);
|
||||
}
|
||||
|
||||
u32 get_count() const
|
||||
{
|
||||
return m_count;
|
||||
}
|
||||
|
||||
std::add_lvalue_reference_t<T> at(u32 index) const
|
||||
{
|
||||
if (index >= m_count) throw EXCEPTION("Out of range (0x%x >= 0x%x)", index, m_count);
|
||||
|
||||
return pointer::operator [](index);
|
||||
}
|
||||
|
||||
// Remove operator ->
|
||||
T* operator ->() const = delete;
|
||||
};
|
||||
|
||||
// _var_base fixed length array specialization
|
||||
template<typename T, typename A, u32 N> class _var_base<T[N], A> final : public _ptr_base<T, const u32>
|
||||
{
|
||||
using pointer = _ptr_base<T, const u32>;
|
||||
|
||||
public:
|
||||
_var_base()
|
||||
: pointer(A::alloc(sizeof32(T) * N, alignof32(T)), vm::addr)
|
||||
{
|
||||
// Call the default constructor for each element
|
||||
new(pointer::get_ptr()) T[N]();
|
||||
}
|
||||
|
||||
template<typename T2> _var_base(const T2(&array)[N])
|
||||
: pointer(A::alloc(sizeof32(T) * N, alignof32(T)), vm::addr)
|
||||
{
|
||||
// Copy the array
|
||||
std::uninitialized_copy_n(array + 0, N, const_cast<std::remove_cv_t<T>*>(pointer::get_ptr()));
|
||||
}
|
||||
|
||||
_var_base(const _var_base&) = delete; // Delete copy/move constructors and copy/move operators
|
||||
|
||||
~_var_base() noexcept(noexcept(std::declval<T&>().~T()) && noexcept(A::dealloc(0, 0)))
|
||||
{
|
||||
// Call the destructor for each element
|
||||
for (u32 i = N - 1; ~i; i--) pointer::operator [](i).~T();
|
||||
|
||||
// Deallocate memory
|
||||
A::dealloc(pointer::addr(), sizeof32(T) * N);
|
||||
}
|
||||
|
||||
constexpr u32 get_count() const
|
||||
{
|
||||
return N;
|
||||
}
|
||||
|
||||
std::add_lvalue_reference_t<T> at(u32 index) const
|
||||
{
|
||||
if (index >= N) throw EXCEPTION("Out of range (0x%x > 0x%x)", index, N);
|
||||
|
||||
return pointer::operator [](index);
|
||||
}
|
||||
|
||||
// Remove operator ->
|
||||
T* operator ->() const = delete;
|
||||
};
|
||||
|
||||
// LE variable
|
||||
template<typename T, typename A = vm::stack_alloc_t> using varl = _var_base<to_le_t<T>, A>;
|
||||
|
||||
// BE variable
|
||||
template<typename T, typename A = vm::stack_alloc_t> using varb = _var_base<to_be_t<T>, A>;
|
||||
|
||||
namespace ps3
|
||||
{
|
||||
template<typename T, template<typename> class A = vm::stack_alloc_t> using var = varb<T, A>;
|
||||
// BE variable
|
||||
template<typename T, typename A = vm::stack_alloc_t> using var = varb<T, A>;
|
||||
|
||||
// BE variable initialized from value
|
||||
template<typename T> inline varb<T, vm::stack_alloc_t> make_var(const T& value)
|
||||
{
|
||||
return{ value };
|
||||
}
|
||||
}
|
||||
|
||||
namespace psv
|
||||
{
|
||||
template<typename T, template<typename> class A = vm::stack_alloc_t> using var = varl<T, A>;
|
||||
// LE variable
|
||||
template<typename T, typename A = vm::stack_alloc_t> using var = varl<T, A>;
|
||||
|
||||
// LE variable initialized from value
|
||||
template<typename T> inline varl<T, vm::stack_alloc_t> make_var(const T& value)
|
||||
{
|
||||
return{ value };
|
||||
}
|
||||
}
|
||||
|
||||
static _var_base<char[], vm::stack_alloc_t> make_str(const std::string& str)
|
||||
{
|
||||
return{ size32(str) + 1, str.data() };
|
||||
}
|
||||
}
|
||||
|
@ -318,11 +318,11 @@ public:
|
||||
size_t size = f.size();
|
||||
vm::ps3::init();
|
||||
ptr = vm::alloc(size, vm::main);
|
||||
f.read(vm::get_ptr(ptr), size);
|
||||
f.read(vm::base(ptr), size);
|
||||
}
|
||||
|
||||
auto& vmprog = vm::get_ref<CgBinaryProgram>(ptr);
|
||||
auto& vmfprog = vm::get_ref<CgBinaryFragmentProgram>(ptr + vmprog.program);
|
||||
auto& vmprog = vm::ps3::_ref<CgBinaryProgram>(ptr);
|
||||
auto& vmfprog = vm::ps3::_ref<CgBinaryFragmentProgram>(ptr + vmprog.program);
|
||||
u32 size;
|
||||
u32 ctrl = (vmfprog.outputFromH0 ? 0 : 0x40) | (vmfprog.depthReplace ? 0xe : 0);
|
||||
GLFragmentDecompilerThread(m_glsl_shader, param_array, ptr + vmprog.ucode, size, ctrl).Task();
|
||||
|
@ -72,7 +72,7 @@ void uploadVertexData(const VertexBufferFormat &vbf, const rsx::data_array_forma
|
||||
size_t offset = (size_t)addr + baseOffset - vbf.range.first;
|
||||
size_t tsize = rsx::get_vertex_type_size(vertex_array_desc[attributeId].type);
|
||||
size_t size = vertex_array_desc[attributeId].size;
|
||||
auto src = vm::get_ptr<const u8>(addr + (u32)baseOffset + (u32)vbf.stride * vertex);
|
||||
auto src = vm::ps3::_ptr<const u8>(addr + (u32)baseOffset + (u32)vbf.stride * vertex);
|
||||
char* dst = (char*)bufferMap + offset + vbf.stride * vertex;
|
||||
|
||||
switch (tsize)
|
||||
|
@ -86,7 +86,6 @@ protected:
|
||||
virtual void insertMainEnd(std::stringstream &OS) = 0;
|
||||
public:
|
||||
ParamArray m_parr;
|
||||
FragmentProgramDecompiler() = delete;
|
||||
FragmentProgramDecompiler(u32 addr, u32& size, u32 ctrl);
|
||||
std::string Decompile();
|
||||
};
|
||||
|
@ -241,7 +241,7 @@ private:
|
||||
|
||||
typename BackendTraits::FragmentProgramData& SearchFp(RSXFragmentProgram* rsx_fp, bool& found)
|
||||
{
|
||||
typename binary2FS::iterator It = m_cacheFS.find(vm::get_ptr<void>(rsx_fp->addr));
|
||||
typename binary2FS::iterator It = m_cacheFS.find(vm::base(rsx_fp->addr));
|
||||
if (It != m_cacheFS.end())
|
||||
{
|
||||
found = true;
|
||||
@ -249,9 +249,9 @@ private:
|
||||
}
|
||||
found = false;
|
||||
LOG_WARNING(RSX, "FP not found in buffer!");
|
||||
size_t actualFPSize = ProgramHashUtil::FragmentProgramUtil::getFPBinarySize(vm::get_ptr<u8>(rsx_fp->addr));
|
||||
size_t actualFPSize = ProgramHashUtil::FragmentProgramUtil::getFPBinarySize(vm::base(rsx_fp->addr));
|
||||
void *fpShadowCopy = malloc(actualFPSize);
|
||||
memcpy(fpShadowCopy, vm::get_ptr<u8>(rsx_fp->addr), actualFPSize);
|
||||
std::memcpy(fpShadowCopy, vm::base(rsx_fp->addr), actualFPSize);
|
||||
typename BackendTraits::FragmentProgramData &newShader = m_cacheFS[fpShadowCopy];
|
||||
BackendTraits::RecompileFragmentProgram(rsx_fp, newShader, m_currentShaderId++);
|
||||
|
||||
@ -339,10 +339,10 @@ public:
|
||||
|
||||
const std::vector<size_t> &getFragmentConstantOffsetsCache(const RSXFragmentProgram *fragmentShader) const
|
||||
{
|
||||
typename binary2FS::const_iterator It = m_cacheFS.find(vm::get_ptr<void>(fragmentShader->addr));
|
||||
typename binary2FS::const_iterator It = m_cacheFS.find(vm::base(fragmentShader->addr));
|
||||
if (It != m_cacheFS.end())
|
||||
return It->second.FragmentConstantOffsetCache;
|
||||
LOG_ERROR(RSX, "Can't retrieve constant offset cache");
|
||||
return dummyFragmentConstantCache;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
@ -484,7 +484,7 @@ std::vector<MipmapLevelInfo> uploadPlacedTexture(const rsx::texture &texture, si
|
||||
std::vector<MipmapLevelInfo> mipInfos;
|
||||
|
||||
const u32 texaddr = rsx::get_address(texture.offset(), texture.location());
|
||||
auto pixels = vm::get_ptr<const u8>(texaddr);
|
||||
auto pixels = vm::ps3::_ptr<const u8>(texaddr);
|
||||
bool is_swizzled = !(texture.format() & CELL_GCM_TEXTURE_LN);
|
||||
switch (format)
|
||||
{
|
||||
@ -509,5 +509,4 @@ std::vector<MipmapLevelInfo> uploadPlacedTexture(const rsx::texture &texture, si
|
||||
default:
|
||||
return writeTexelsGeneric((char*)pixels, (char*)textureData, w, h, blockSizeInByte, texture.mipmap());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -650,11 +650,14 @@ void D3D12GSRender::flip(int buffer)
|
||||
size_t offset = 0;
|
||||
if (false)
|
||||
{
|
||||
CellGcmDisplayInfo* buffers;// = vm::get_ptr<CellGcmDisplayInfo>(m_gcm_buffers_addr);
|
||||
CellGcmDisplayInfo* buffers;// = vm::ps3::_ptr<CellGcmDisplayInfo>(m_gcm_buffers_addr);
|
||||
u32 addr = rsx::get_address(buffers[gcm_current_buffer].offset, CELL_GCM_LOCATION_LOCAL);
|
||||
w = buffers[gcm_current_buffer].width;
|
||||
h = buffers[gcm_current_buffer].height;
|
||||
u8 *src_buffer = vm::get_ptr<u8>(addr);
|
||||
u32 addr = rsx::get_address(gcm_buffers[gcm_current_buffer].offset, CELL_GCM_LOCATION_LOCAL);
|
||||
w = gcm_buffers[gcm_current_buffer].width;
|
||||
h = gcm_buffers[gcm_current_buffer].height;
|
||||
u8 *src_buffer = vm::ps3::_ptr<u8>(addr);
|
||||
|
||||
rowPitch = align(w * 4, 256);
|
||||
size_t textureSize = rowPitch * h; // * 4 for mipmap levels
|
||||
@ -1071,7 +1074,7 @@ void D3D12GSRender::semaphore_PGRAPH_backend_release()
|
||||
if (m_context_dma_z && rpcs3::state.config.rsx.opengl.write_depth_buffer)
|
||||
{
|
||||
u32 address = rsx::get_address(rsx::method_registers[NV4097_SET_SURFACE_ZETA_OFFSET], m_context_dma_z - 0xfeed0000);
|
||||
auto ptr = vm::get_ptr<void>(address);
|
||||
auto ptr = vm::base(address);
|
||||
char *ptrAsChar = (char*)ptr;
|
||||
unsigned char *writeDestPtr;
|
||||
ThrowIfFailed(writeDest->Map(0, nullptr, (void**)&writeDestPtr));
|
||||
@ -1111,54 +1114,43 @@ void D3D12GSRender::semaphore_PGRAPH_backend_release()
|
||||
case CELL_GCM_SURFACE_TARGET_0:
|
||||
{
|
||||
u32 address = rsx::get_address(rsx::method_registers[NV4097_SET_SURFACE_COLOR_AOFFSET], m_context_dma_color_a - 0xfeed0000);
|
||||
void *dstAddress = vm::get_ptr<void>(address);
|
||||
copyToCellRamAndRelease(dstAddress, rtt0, srcPitch, dstPitch, clip_w, clip_h);
|
||||
copyToCellRamAndRelease(vm::base(address), rtt0, srcPitch, dstPitch, clip_w, clip_h);
|
||||
}
|
||||
break;
|
||||
case CELL_GCM_SURFACE_TARGET_1:
|
||||
{
|
||||
u32 address = rsx::get_address(rsx::method_registers[NV4097_SET_SURFACE_COLOR_BOFFSET], m_context_dma_color_b - 0xfeed0000);
|
||||
void *dstAddress = vm::get_ptr<void>(address);
|
||||
copyToCellRamAndRelease(dstAddress, rtt1, srcPitch, dstPitch, clip_w, clip_h);
|
||||
copyToCellRamAndRelease(vm::base(address), rtt1, srcPitch, dstPitch, clip_w, clip_h);
|
||||
}
|
||||
break;
|
||||
case CELL_GCM_SURFACE_TARGET_MRT1:
|
||||
{
|
||||
u32 address = rsx::get_address(rsx::method_registers[NV4097_SET_SURFACE_COLOR_AOFFSET], m_context_dma_color_a - 0xfeed0000);
|
||||
void *dstAddress = vm::get_ptr<void>(address);
|
||||
copyToCellRamAndRelease(dstAddress, rtt0, srcPitch, dstPitch, clip_w, clip_h);
|
||||
copyToCellRamAndRelease(vm::base(address), rtt0, srcPitch, dstPitch, clip_w, clip_h);
|
||||
address = rsx::get_address(rsx::method_registers[NV4097_SET_SURFACE_COLOR_BOFFSET], m_context_dma_color_b - 0xfeed0000);
|
||||
dstAddress = vm::get_ptr<void>(address);
|
||||
copyToCellRamAndRelease(dstAddress, rtt1, srcPitch, dstPitch, clip_w, clip_h);
|
||||
copyToCellRamAndRelease(vm::base(address), rtt1, srcPitch, dstPitch, clip_w, clip_h);
|
||||
}
|
||||
break;
|
||||
case CELL_GCM_SURFACE_TARGET_MRT2:
|
||||
{
|
||||
u32 address = rsx::get_address(rsx::method_registers[NV4097_SET_SURFACE_COLOR_AOFFSET], m_context_dma_color_a - 0xfeed0000);
|
||||
void *dstAddress = vm::get_ptr<void>(address);
|
||||
copyToCellRamAndRelease(dstAddress, rtt0, srcPitch, dstPitch, clip_w, clip_h);
|
||||
copyToCellRamAndRelease(vm::base(address), rtt0, srcPitch, dstPitch, clip_w, clip_h);
|
||||
address = rsx::get_address(rsx::method_registers[NV4097_SET_SURFACE_COLOR_BOFFSET], m_context_dma_color_b - 0xfeed0000);
|
||||
dstAddress = vm::get_ptr<void>(address);
|
||||
copyToCellRamAndRelease(dstAddress, rtt1, srcPitch, dstPitch, clip_w, clip_h);
|
||||
copyToCellRamAndRelease(vm::base(address), rtt1, srcPitch, dstPitch, clip_w, clip_h);
|
||||
address = rsx::get_address(rsx::method_registers[NV4097_SET_SURFACE_COLOR_COFFSET], m_context_dma_color_c - 0xfeed0000);
|
||||
dstAddress = vm::get_ptr<void>(address);
|
||||
copyToCellRamAndRelease(dstAddress, rtt2, srcPitch, dstPitch, clip_w, clip_h);
|
||||
copyToCellRamAndRelease(vm::base(address), rtt2, srcPitch, dstPitch, clip_w, clip_h);
|
||||
}
|
||||
break;
|
||||
case CELL_GCM_SURFACE_TARGET_MRT3:
|
||||
{
|
||||
u32 address = rsx::get_address(rsx::method_registers[NV4097_SET_SURFACE_COLOR_AOFFSET], m_context_dma_color_a - 0xfeed0000);
|
||||
void *dstAddress = vm::get_ptr<void>(address);
|
||||
copyToCellRamAndRelease(dstAddress, rtt0, srcPitch, dstPitch, clip_w, clip_h);
|
||||
copyToCellRamAndRelease(vm::base(address), rtt0, srcPitch, dstPitch, clip_w, clip_h);
|
||||
address = rsx::get_address(rsx::method_registers[NV4097_SET_SURFACE_COLOR_BOFFSET], m_context_dma_color_b - 0xfeed0000);
|
||||
dstAddress = vm::get_ptr<void>(address);
|
||||
copyToCellRamAndRelease(dstAddress, rtt1, srcPitch, dstPitch, clip_w, clip_h);
|
||||
copyToCellRamAndRelease(vm::base(address), rtt1, srcPitch, dstPitch, clip_w, clip_h);
|
||||
address = rsx::get_address(rsx::method_registers[NV4097_SET_SURFACE_COLOR_COFFSET], m_context_dma_color_c - 0xfeed0000);
|
||||
dstAddress = vm::get_ptr<void>(address);
|
||||
copyToCellRamAndRelease(dstAddress, rtt2, srcPitch, dstPitch, clip_w, clip_h);
|
||||
copyToCellRamAndRelease(vm::base(address), rtt2, srcPitch, dstPitch, clip_w, clip_h);
|
||||
address = rsx::get_address(rsx::method_registers[NV4097_SET_SURFACE_COLOR_DOFFSET], m_context_dma_color_d - 0xfeed0000);
|
||||
dstAddress = vm::get_ptr<void>(address);
|
||||
copyToCellRamAndRelease(dstAddress, rtt3, srcPitch, dstPitch, clip_w, clip_h);
|
||||
copyToCellRamAndRelease(vm::base(address), rtt3, srcPitch, dstPitch, clip_w, clip_h);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ void GLTexture::init(rsx::texture& tex)
|
||||
int format = tex.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN);
|
||||
bool is_swizzled = !(tex.format() & CELL_GCM_TEXTURE_LN);
|
||||
|
||||
auto pixels = vm::get_ptr<const u8>(texaddr);
|
||||
const u8* pixels = vm::ps3::_ptr<u8>(texaddr);
|
||||
u8 *unswizzledPixels;
|
||||
static const GLint glRemapStandard[4] = { GL_ALPHA, GL_RED, GL_GREEN, GL_BLUE };
|
||||
// NOTE: This must be in ARGB order in all forms below.
|
||||
@ -470,7 +470,7 @@ void GLTexture::save(rsx::texture& tex, const std::string& name)
|
||||
return;
|
||||
}
|
||||
|
||||
fs::file(name + ".raw", o_write | o_create | o_trunc).write(alldata, texPixelCount * 4);
|
||||
fs::file(name + ".raw", fom::write | fom::create | fom::trunc).write(alldata, texPixelCount * 4);
|
||||
|
||||
u8* data = new u8[texPixelCount * 3];
|
||||
u8* alpha = new u8[texPixelCount];
|
||||
@ -1300,7 +1300,7 @@ bool GLGSRender::load_program()
|
||||
|
||||
for (u32 constant_offset : m_prog_buffer.getFragmentConstantOffsetsCache(&fragment_program))
|
||||
{
|
||||
be_t<u32> *data = vm::get_ptr<be_t<u32>>(fragment_program.addr + constant_offset);
|
||||
auto data = vm::ps3::_ptr<u32>(fragment_program.addr + constant_offset);
|
||||
|
||||
u32 c0 = (data[0] >> 16 | data[0] << 16);
|
||||
u32 c1 = (data[1] >> 16 | data[1] << 16);
|
||||
@ -1544,7 +1544,7 @@ void GLGSRender::read_buffers()
|
||||
for (int i = index; i < index + count; ++i)
|
||||
{
|
||||
u32 color_address = rsx::get_address(rsx::method_registers[mr_color_offset[i]], rsx::method_registers[mr_color_dma[i]]);
|
||||
__glcheck m_draw_tex_color[i].copy_from(vm::get_ptr(color_address), color_format.format, color_format.type);
|
||||
__glcheck m_draw_tex_color[i].copy_from(vm::base(color_address), color_format.format, color_format.type);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1591,7 +1591,7 @@ void GLGSRender::read_buffers()
|
||||
if (m_surface.depth_format == CELL_GCM_SURFACE_Z16)
|
||||
{
|
||||
u16 *dst = (u16*)pixels;
|
||||
const be_t<u16>* src = vm::get_ptr<const be_t<u16>>(depth_address);
|
||||
const be_t<u16>* src = vm::ps3::_ptr<u16>(depth_address);
|
||||
for (int i = 0, end = m_draw_tex_depth_stencil.width() * m_draw_tex_depth_stencil.height(); i < end; ++i)
|
||||
{
|
||||
dst[i] = src[i];
|
||||
@ -1600,7 +1600,7 @@ void GLGSRender::read_buffers()
|
||||
else
|
||||
{
|
||||
u32 *dst = (u32*)pixels;
|
||||
const be_t<u32>* src = vm::get_ptr<const be_t<u32>>(depth_address);
|
||||
const be_t<u32>* src = vm::ps3::_ptr<u32>(depth_address);
|
||||
for (int i = 0, end = m_draw_tex_depth_stencil.width() * m_draw_tex_depth_stencil.height(); i < end; ++i)
|
||||
{
|
||||
dst[i] = src[i];
|
||||
@ -1637,7 +1637,7 @@ void GLGSRender::write_buffers()
|
||||
// //u32 depth_address = rsx::get_address(rsx::method_registers[NV4097_SET_SURFACE_ZETA_OFFSET], rsx::method_registers[NV4097_SET_CONTEXT_DMA_ZETA]);
|
||||
|
||||
// const u32 *src = (const u32*)pixels;
|
||||
// be_t<u32>* dst = vm::get_ptr<be_t<u32>>(color_address);
|
||||
// be_t<u32>* dst = vm::ps3::_ptr<u32>(color_address);
|
||||
// for (int i = 0, end = m_draw_tex_color[i].width() * m_draw_tex_color[i].height(); i < end; ++i)
|
||||
// {
|
||||
// dst[i] = src[i];
|
||||
@ -1646,7 +1646,7 @@ void GLGSRender::write_buffers()
|
||||
//}, gl::buffer::access::read);
|
||||
|
||||
u32 color_address = rsx::get_address(rsx::method_registers[mr_color_offset[i]], rsx::method_registers[mr_color_dma[i]]);
|
||||
__glcheck m_draw_tex_color[i].copy_to(vm::get_ptr(color_address), color_format.format, color_format.type);
|
||||
__glcheck m_draw_tex_color[i].copy_to(vm::base(color_address), color_format.format, color_format.type);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1695,7 +1695,7 @@ void GLGSRender::write_buffers()
|
||||
if (m_surface.depth_format == CELL_GCM_SURFACE_Z16)
|
||||
{
|
||||
const u16 *src = (const u16*)pixels;
|
||||
be_t<u16>* dst = vm::get_ptr<be_t<u16>>(depth_address);
|
||||
be_t<u16>* dst = vm::ps3::_ptr<u16>(depth_address);
|
||||
for (int i = 0, end = m_draw_tex_depth_stencil.width() * m_draw_tex_depth_stencil.height(); i < end; ++i)
|
||||
{
|
||||
dst[i] = src[i];
|
||||
@ -1704,7 +1704,7 @@ void GLGSRender::write_buffers()
|
||||
else
|
||||
{
|
||||
const u32 *src = (const u32*)pixels;
|
||||
be_t<u32>* dst = vm::get_ptr<be_t<u32>>(depth_address);
|
||||
be_t<u32>* dst = vm::ps3::_ptr<u32>(depth_address);
|
||||
for (int i = 0, end = m_draw_tex_depth_stencil.width() * m_draw_tex_depth_stencil.height(); i < end; ++i)
|
||||
{
|
||||
dst[i] = src[i];
|
||||
@ -1771,8 +1771,7 @@ void GLGSRender::flip(int buffer)
|
||||
glDisable(GL_LOGIC_OP);
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
__glcheck m_flip_tex_color.copy_from(vm::get_ptr(buffer_address),
|
||||
gl::texture::format::bgra, gl::texture::type::uint_8_8_8_8);
|
||||
__glcheck m_flip_tex_color.copy_from(vm::base(buffer_address), gl::texture::format::bgra, gl::texture::type::uint_8_8_8_8);
|
||||
}
|
||||
|
||||
areai screen_area = coordi({}, { (int)buffer_width, (int)buffer_height });
|
||||
@ -1825,4 +1824,4 @@ u64 GLGSRender::timestamp() const
|
||||
GLint64 result;
|
||||
glGetInteger64v(GL_TIMESTAMP, &result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -277,7 +277,7 @@ namespace rsx
|
||||
u32 offset = arg & 0xffffff;
|
||||
|
||||
//TODO: use DMA
|
||||
vm::ptr<CellGcmReportData> result = { rsx->local_mem_addr + offset };
|
||||
vm::ptr<CellGcmReportData> result = { rsx->local_mem_addr + offset, vm::addr };
|
||||
|
||||
result->timer = rsx->timestamp();
|
||||
|
||||
@ -391,8 +391,8 @@ namespace rsx
|
||||
const u16 u = arg; // inX (currently ignored)
|
||||
const u16 v = arg >> 16; // inY (currently ignored)
|
||||
|
||||
u8* pixels_src = vm::get_ptr<u8>(get_address(src_offset, src_dma));
|
||||
u8* pixels_dst = vm::get_ptr<u8>(get_address(dst_offset, dst_dma));
|
||||
u8* pixels_src = vm::_ptr<u8>(get_address(src_offset, src_dma));
|
||||
u8* pixels_dst = vm::_ptr<u8>(get_address(dst_offset, dst_dma));
|
||||
|
||||
if (method_registers[NV3062_SET_COLOR_FORMAT] != 4 /* CELL_GCM_TRANSFER_SURFACE_FORMAT_R5G6B5 */ &&
|
||||
method_registers[NV3062_SET_COLOR_FORMAT] != 10 /* CELL_GCM_TRANSFER_SURFACE_FORMAT_A8R8G8B8 */)
|
||||
@ -406,10 +406,14 @@ namespace rsx
|
||||
const s32 out_w = (s32)(u64(width) * (1 << 20) / method_registers[NV3089_DS_DX]);
|
||||
const s32 out_h = (s32)(u64(height) * (1 << 20) / method_registers[NV3089_DT_DY]);
|
||||
|
||||
std::unique_ptr<u8[]> temp1, temp2;
|
||||
|
||||
if (method_registers[NV3089_SET_CONTEXT_SURFACE] == CELL_GCM_CONTEXT_SWIZZLE2D)
|
||||
{
|
||||
temp1.reset(new u8[in_bpp * width * height]);
|
||||
|
||||
u8* linear_pixels = pixels_src;
|
||||
u8* swizzled_pixels = new u8[in_bpp * width * height];
|
||||
u8* swizzled_pixels = temp1.get();
|
||||
|
||||
int sw_width = 1 << (int)log2(width);
|
||||
int sw_height = 1 << (int)log2(height);
|
||||
@ -440,13 +444,11 @@ namespace rsx
|
||||
width, height, pitch, src_offset, double(u) / 16, double(v) / 16, double(1 << 20) / (method_registers[NV3089_DS_DX]),
|
||||
double(1 << 20) / (method_registers[NV3089_DT_DY]));
|
||||
|
||||
std::unique_ptr<u8[]> temp;
|
||||
|
||||
if (in_bpp != out_bpp && width != out_w && height != out_h)
|
||||
{
|
||||
// resize/convert if necessary
|
||||
|
||||
temp.reset(new u8[out_bpp * out_w * out_h]);
|
||||
temp2.reset(new u8[out_bpp * out_w * out_h]);
|
||||
|
||||
AVPixelFormat in_format = method_registers[NV3062_SET_COLOR_FORMAT] == 4 ? AV_PIX_FMT_RGB565BE : AV_PIX_FMT_ARGB; // ???
|
||||
AVPixelFormat out_format = method_registers[NV3089_SET_COLOR_FORMAT] == 7 ? AV_PIX_FMT_RGB565BE : AV_PIX_FMT_ARGB; // ???
|
||||
@ -455,12 +457,12 @@ namespace rsx
|
||||
inter ? SWS_FAST_BILINEAR : SWS_POINT, NULL, NULL, NULL), sws_freeContext);
|
||||
|
||||
int in_line = in_bpp * width;
|
||||
u8* out_ptr = temp.get();
|
||||
u8* out_ptr = temp2.get();
|
||||
int out_line = out_bpp * out_w;
|
||||
|
||||
sws_scale(sws.get(), &pixels_src, &in_line, 0, height, &out_ptr, &out_line);
|
||||
|
||||
pixels_src = temp.get(); // use resized image as a source
|
||||
pixels_src = out_ptr; // use resized image as a source
|
||||
}
|
||||
|
||||
if (method_registers[NV3089_CLIP_SIZE] != method_registers[NV3089_IMAGE_OUT_SIZE] ||
|
||||
@ -495,25 +497,20 @@ namespace rsx
|
||||
d0 = { src_line + z0.second, std::min<size_t>(dst_max - z0.second, src_max) },
|
||||
z1 = { src_line + d0.second, dst_max - z0.second - d0.second };
|
||||
|
||||
memset(z0.first, 0, z0.second);
|
||||
memcpy(d0.first, src_line, d0.second);
|
||||
memset(z1.first, 0, z1.second);
|
||||
std::memset(z0.first, 0, z0.second);
|
||||
std::memcpy(d0.first, src_line, d0.second);
|
||||
std::memset(z1.first, 0, z1.second);
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(dst_line, 0, dst_max);
|
||||
std::memset(dst_line, 0, dst_max);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(pixels_dst, pixels_src, out_w * out_h * out_bpp);
|
||||
}
|
||||
|
||||
if (method_registers[NV3089_SET_CONTEXT_SURFACE] == CELL_GCM_CONTEXT_SWIZZLE2D)
|
||||
{
|
||||
delete[] pixels_src;
|
||||
std::memcpy(pixels_dst, pixels_src, out_w * out_h * out_bpp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -538,9 +535,9 @@ namespace rsx
|
||||
|
||||
if (lineCount == 1 && !inPitch && !outPitch && !notify)
|
||||
{
|
||||
memcpy(
|
||||
vm::get_ptr(get_address(method_registers[NV0039_OFFSET_OUT], method_registers[NV0039_SET_CONTEXT_DMA_BUFFER_OUT])),
|
||||
vm::get_ptr(get_address(method_registers[NV0039_OFFSET_IN], method_registers[NV0039_SET_CONTEXT_DMA_BUFFER_IN])),
|
||||
std::memcpy(
|
||||
vm::base(get_address(method_registers[NV0039_OFFSET_OUT], method_registers[NV0039_SET_CONTEXT_DMA_BUFFER_OUT])),
|
||||
vm::base(get_address(method_registers[NV0039_OFFSET_IN], method_registers[NV0039_SET_CONTEXT_DMA_BUFFER_IN])),
|
||||
lineLength);
|
||||
}
|
||||
else
|
||||
@ -560,11 +557,11 @@ namespace rsx
|
||||
rsx->gcm_current_buffer = arg;
|
||||
rsx->flip_status = 0;
|
||||
|
||||
if (auto cb = rsx->flip_handler)
|
||||
if (rsx->flip_handler)
|
||||
{
|
||||
Emu.GetCallbackManager().Async([=](CPUThread& cpu)
|
||||
Emu.GetCallbackManager().Async([func = rsx->flip_handler](PPUThread& ppu)
|
||||
{
|
||||
cb(static_cast<PPUThread&>(cpu), 1);
|
||||
func(ppu, 1);
|
||||
});
|
||||
}
|
||||
|
||||
@ -838,7 +835,7 @@ namespace rsx
|
||||
|
||||
for (u32 i = 0; i < count; ++i)
|
||||
{
|
||||
auto src = vm::get_ptr<const u8>(address + base_offset + info.stride * (first + i + base_index));
|
||||
const u8* src = vm::_ptr<u8>(address + base_offset + info.stride * (first + i + base_index));
|
||||
u8* dst = data.data() + dst_position + i * element_size;
|
||||
|
||||
switch (type_size)
|
||||
@ -942,11 +939,11 @@ namespace rsx
|
||||
{
|
||||
vblank_count++;
|
||||
|
||||
if (auto cb = vblank_handler)
|
||||
if (vblank_handler)
|
||||
{
|
||||
Emu.GetCallbackManager().Async([=](CPUThread& cpu)
|
||||
Emu.GetCallbackManager().Async([func = vblank_handler](PPUThread& ppu)
|
||||
{
|
||||
cb(static_cast<PPUThread&>(cpu), 1);
|
||||
func(ppu, 1);
|
||||
});
|
||||
}
|
||||
|
||||
@ -969,7 +966,6 @@ namespace rsx
|
||||
LOG_WARNING(RSX, "RSX thread aborted");
|
||||
break;
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(cs_main);
|
||||
|
||||
inc = 1;
|
||||
|
||||
@ -989,7 +985,7 @@ namespace rsx
|
||||
{
|
||||
u32 offs = cmd & 0x1fffffff;
|
||||
//LOG_WARNING(RSX, "rsx jump(0x%x) #addr=0x%x, cmd=0x%x, get=0x%x, put=0x%x", offs, m_ioAddress + get, cmd, get, put);
|
||||
ctrl->get.exchange(offs);
|
||||
ctrl->get = offs;
|
||||
continue;
|
||||
}
|
||||
if (cmd & CELL_GCM_METHOD_FLAG_CALL)
|
||||
@ -997,7 +993,7 @@ namespace rsx
|
||||
m_call_stack.push(get + 4);
|
||||
u32 offs = cmd & ~3;
|
||||
//LOG_WARNING(RSX, "rsx call(0x%x) #0x%x - 0x%x", offs, cmd, get);
|
||||
ctrl->get.exchange(offs);
|
||||
ctrl->get = offs;
|
||||
continue;
|
||||
}
|
||||
if (cmd == CELL_GCM_METHOD_FLAG_RETURN)
|
||||
@ -1005,7 +1001,7 @@ namespace rsx
|
||||
u32 get = m_call_stack.top();
|
||||
m_call_stack.pop();
|
||||
//LOG_WARNING(RSX, "rsx return(0x%x)", get);
|
||||
ctrl->get.exchange(get);
|
||||
ctrl->get = get;
|
||||
continue;
|
||||
}
|
||||
if (cmd & CELL_GCM_METHOD_FLAG_NON_INCREMENT)
|
||||
@ -1016,11 +1012,7 @@ namespace rsx
|
||||
|
||||
if (cmd == 0) //nop
|
||||
{
|
||||
ctrl->get.atomic_op([](be_t<u32>& value)
|
||||
{
|
||||
value += 4;
|
||||
});
|
||||
|
||||
ctrl->get = get + 4;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1049,17 +1041,13 @@ namespace rsx
|
||||
method(this, value);
|
||||
}
|
||||
|
||||
ctrl->get.atomic_op([count](be_t<u32>& value)
|
||||
{
|
||||
value += (count + 1) * 4;
|
||||
});
|
||||
ctrl->get = get + (count + 1) * 4;
|
||||
}
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
LOG_ERROR(Log::RSX, ex.what());
|
||||
|
||||
std::rethrow_exception(std::current_exception());
|
||||
throw;
|
||||
}
|
||||
|
||||
LOG_NOTICE(RSX, "RSX thread ended");
|
||||
@ -1076,7 +1064,7 @@ namespace rsx
|
||||
void thread::reset()
|
||||
{
|
||||
//setup method registers
|
||||
memset(method_registers, 0, sizeof(method_registers));
|
||||
std::memset(method_registers, 0, sizeof(method_registers));
|
||||
|
||||
method_registers[NV4097_SET_COLOR_MASK] = CELL_GCM_COLOR_MASK_R | CELL_GCM_COLOR_MASK_G | CELL_GCM_COLOR_MASK_B | CELL_GCM_COLOR_MASK_A;
|
||||
method_registers[NV4097_SET_SCISSOR_HORIZONTAL] = (4096 << 16) | 0;
|
||||
@ -1145,7 +1133,7 @@ namespace rsx
|
||||
|
||||
void thread::init(const u32 ioAddress, const u32 ioSize, const u32 ctrlAddress, const u32 localAddress)
|
||||
{
|
||||
ctrl = vm::get_ptr<CellGcmControl>(ctrlAddress);
|
||||
ctrl = vm::_ptr<CellGcmControl>(ctrlAddress);
|
||||
this->ioAddress = ioAddress;
|
||||
this->ioSize = ioSize;
|
||||
local_mem_addr = localAddress;
|
||||
|
@ -192,12 +192,11 @@ namespace rsx
|
||||
double fps_limit = 59.94;
|
||||
|
||||
public:
|
||||
std::mutex cs_main;
|
||||
semaphore_t sem_flip;
|
||||
u64 last_flip_time;
|
||||
vm::ps3::ptr<void(u32)> flip_handler = { 0 };
|
||||
vm::ps3::ptr<void(u32)> user_handler = { 0 };
|
||||
vm::ps3::ptr<void(u32)> vblank_handler = { 0 };
|
||||
vm::ps3::ptr<void(u32)> flip_handler = vm::null;
|
||||
vm::ps3::ptr<void(u32)> user_handler = vm::null;
|
||||
vm::ps3::ptr<void(u32)> vblank_handler = vm::null;
|
||||
u64 vblank_count;
|
||||
|
||||
public:
|
||||
|
@ -183,7 +183,7 @@ namespace vm
|
||||
template<typename AT, typename RT, typename... T>
|
||||
force_inline RT _ptr_base<RT(T...), AT>::operator()(PPUThread& CPU, T... args) const
|
||||
{
|
||||
const auto data = vm::get_ptr<be_t<u32>>(VM_CAST(m_addr));
|
||||
const auto data = vm::ps3::_ptr<u32>(VM_CAST(m_addr));
|
||||
const u32 pc = data[0];
|
||||
const u32 rtoc = data[1];
|
||||
|
||||
|
@ -49,7 +49,7 @@ void CallbackManager::Init()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
auto task = [this](CPUThread& cpu)
|
||||
auto task = [this](PPUThread& ppu)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
@ -71,27 +71,16 @@ void CallbackManager::Init()
|
||||
|
||||
if (lock) lock.unlock();
|
||||
|
||||
func(cpu);
|
||||
func(ppu);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
cpu.cv.wait(lock);
|
||||
ppu.cv.wait(lock);
|
||||
}
|
||||
};
|
||||
|
||||
if (vm::get(vm::main)->addr != 0x10000)
|
||||
{
|
||||
auto thread = idm::make_ptr<ARMv7Thread>("Callback Thread");
|
||||
|
||||
thread->prio = 1001;
|
||||
thread->stack_size = 0x10000;
|
||||
thread->custom_task = task;
|
||||
thread->run();
|
||||
|
||||
m_cb_thread = thread;
|
||||
}
|
||||
else
|
||||
if (vm::get(vm::main)->addr == 0x10000)
|
||||
{
|
||||
auto thread = idm::make_ptr<PPUThread>("Callback Thread");
|
||||
|
||||
|
@ -1,18 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
class CPUThread;
|
||||
class PPUThread;
|
||||
|
||||
class CallbackManager
|
||||
{
|
||||
using check_cb_t = std::function<s32(CPUThread&)>;
|
||||
using async_cb_t = std::function<void(CPUThread&)>;
|
||||
using check_cb_t = std::function<s32(PPUThread&)>;
|
||||
using async_cb_t = std::function<void(PPUThread&)>;
|
||||
|
||||
std::mutex m_mutex;
|
||||
|
||||
std::queue<check_cb_t> m_check_cb;
|
||||
std::queue<async_cb_t> m_async_cb;
|
||||
|
||||
std::shared_ptr<CPUThread> m_cb_thread;
|
||||
std::shared_ptr<PPUThread> m_cb_thread;
|
||||
|
||||
public:
|
||||
// register checked callback (accepts CPUThread&, returns s32)
|
||||
|
@ -156,7 +156,7 @@ void execute_ppu_func_by_index(PPUThread& ppu, u32 index)
|
||||
// CPU.LR = CPU.PC + 4;
|
||||
}
|
||||
|
||||
const auto data = vm::get_ptr<be_t<u32>>(func->lle_func.addr());
|
||||
const auto data = vm::_ptr<u32>(func->lle_func.addr());
|
||||
ppu.PC = data[0] - 4;
|
||||
ppu.GPR[2] = data[1]; // set rtoc
|
||||
|
||||
@ -170,7 +170,7 @@ void execute_ppu_func_by_index(PPUThread& ppu, u32 index)
|
||||
{
|
||||
// call LLE function if available
|
||||
|
||||
const auto data = vm::get_ptr<be_t<u32>>(func->lle_func.addr());
|
||||
const auto data = vm::_ptr<u32>(func->lle_func.addr());
|
||||
const u32 pc = data[0];
|
||||
const u32 rtoc = data[1];
|
||||
|
||||
|
@ -79,14 +79,9 @@ protected:
|
||||
std::function<void()> on_alloc;
|
||||
|
||||
public:
|
||||
Module() = delete;
|
||||
Module(const char* name, void(*init)());
|
||||
|
||||
Module(Module& other) = delete;
|
||||
Module(Module&& other) = delete;
|
||||
|
||||
Module& operator =(Module& other) = delete;
|
||||
Module& operator =(Module&& other) = delete;
|
||||
Module(const Module&) = delete; // Delete copy/move constructors and copy/move operators
|
||||
|
||||
~Module();
|
||||
|
||||
@ -121,13 +116,13 @@ public:
|
||||
//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{};
|
||||
new(vm::base(m_addr = vm::alloc(sizeof(T), vm::main))) T();
|
||||
};
|
||||
}
|
||||
|
||||
T* operator ->() const
|
||||
{
|
||||
return vm::get_ptr<T>(m_addr);
|
||||
return vm::_ptr<T>(m_addr);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -164,7 +164,7 @@ next:
|
||||
|
||||
case adecDecodeAu:
|
||||
{
|
||||
memcpy(buf, vm::get_ptr<void>(adec.reader.addr), adec.reader.size);
|
||||
std::memcpy(buf, vm::base(adec.reader.addr), adec.reader.size);
|
||||
|
||||
buf += adec.reader.size;
|
||||
buf_size -= adec.reader.size;
|
||||
@ -203,7 +203,7 @@ next:
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(buf, vm::get_ptr<void>(adec.reader.addr), buf_size);
|
||||
std::memcpy(buf, vm::base(adec.reader.addr), buf_size);
|
||||
|
||||
adec.reader.addr += buf_size;
|
||||
adec.reader.size -= buf_size;
|
||||
|
@ -45,8 +45,8 @@ s32 cellAudioInit()
|
||||
g_audio.indexes = g_audio.indexes ? g_audio.indexes : vm::alloc(sizeof32(u64) * AUDIO_PORT_COUNT, vm::main);
|
||||
|
||||
// clear memory
|
||||
memset(vm::get_ptr<void>(g_audio.buffer), 0, AUDIO_PORT_OFFSET * AUDIO_PORT_COUNT);
|
||||
memset(vm::get_ptr<void>(g_audio.indexes), 0, sizeof32(u64) * AUDIO_PORT_COUNT);
|
||||
std::memset(vm::base(g_audio.buffer), 0, AUDIO_PORT_OFFSET * AUDIO_PORT_COUNT);
|
||||
std::memset(vm::base(g_audio.indexes), 0, sizeof32(u64) * AUDIO_PORT_COUNT);
|
||||
|
||||
// check thread status
|
||||
if (g_audio.thread.joinable())
|
||||
@ -182,7 +182,7 @@ s32 cellAudioInit()
|
||||
const u32 position = port.tag % port.block; // old value
|
||||
const u32 buf_addr = port.addr + position * block_size * sizeof(float);
|
||||
|
||||
auto buf = vm::get_ptr<be_t<float>>(buf_addr);
|
||||
auto buf = vm::_ptr<f32>(buf_addr);
|
||||
|
||||
static const float k = 1.0f; // may be 1.0f
|
||||
const float& m = port.level;
|
||||
|
@ -152,7 +152,7 @@ void ElementaryStream::push_au(u32 size, u64 dts, u64 pts, u64 userdata, bool ra
|
||||
put = memAddr;
|
||||
}
|
||||
|
||||
memcpy(vm::get_ptr<void>(put + 128), raw_data.data(), size);
|
||||
std::memcpy(vm::base(put + 128), raw_data.data(), size);
|
||||
raw_data.erase(raw_data.begin(), raw_data.begin() + size);
|
||||
|
||||
auto info = vm::ptr<CellDmuxAuInfoEx>::make(put);
|
||||
@ -197,7 +197,7 @@ void ElementaryStream::push(DemuxerStream& stream, u32 size)
|
||||
|
||||
raw_data.resize(old_size + size);
|
||||
|
||||
memcpy(raw_data.data() + old_size, vm::get_ptr<void>(stream.addr), size); // append bytes
|
||||
std::memcpy(raw_data.data() + old_size, vm::base(stream.addr), size); // append bytes
|
||||
|
||||
stream.skip(size);
|
||||
}
|
||||
@ -352,7 +352,7 @@ void dmuxOpen(u32 dmux_id) // TODO: call from the constructor
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (code.value())
|
||||
switch (code)
|
||||
{
|
||||
case PACK_START_CODE:
|
||||
{
|
||||
|
@ -304,7 +304,7 @@ struct DemuxerStream
|
||||
{
|
||||
if (sizeof(T) > size) return false;
|
||||
|
||||
out = vm::get_ref<T>(addr);
|
||||
out = vm::_ref<T>(addr);
|
||||
addr += sizeof(T);
|
||||
size -= sizeof(T);
|
||||
|
||||
@ -316,7 +316,7 @@ struct DemuxerStream
|
||||
{
|
||||
if (sizeof(T) + shift > size) return false;
|
||||
|
||||
out = vm::get_ref<T>(addr + shift);
|
||||
out = vm::_ref<T>(addr + shift);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ s32 cellFontOpenFontMemory(vm::ptr<CellFontLibrary> library, u32 fontAddr, u32 f
|
||||
|
||||
font->stbfont = (stbtt_fontinfo*)((u8*)&(font->stbfont) + sizeof(void*)); // hack: use next bytes of the struct
|
||||
|
||||
if (!stbtt_InitFont(font->stbfont, vm::get_ptr<unsigned char>(fontAddr), 0))
|
||||
if (!stbtt_InitFont(font->stbfont, vm::_ptr<unsigned char>(fontAddr), 0))
|
||||
return CELL_FONT_ERROR_FONT_OPEN_FAILED;
|
||||
|
||||
font->renderer_addr = 0;
|
||||
@ -73,7 +73,7 @@ s32 cellFontOpenFontFile(vm::ptr<CellFontLibrary> library, vm::cptr<char> fontPa
|
||||
|
||||
u32 fileSize = (u32)f.GetSize();
|
||||
u32 bufferAddr = vm::alloc(fileSize, vm::main); // Freed in cellFontCloseFont
|
||||
f.Read(vm::get_ptr<void>(bufferAddr), fileSize);
|
||||
f.Read(vm::base(bufferAddr), fileSize);
|
||||
s32 ret = cellFontOpenFontMemory(library, bufferAddr, fileSize, subNum, uniqueId, font);
|
||||
font->origin = CELL_FONT_OPEN_FONT_FILE;
|
||||
|
||||
@ -155,9 +155,7 @@ s32 cellFontOpenFontset(PPUThread& ppu, vm::ptr<CellFontLibrary> library, vm::pt
|
||||
return CELL_FONT_ERROR_NO_SUPPORT_FONTSET;
|
||||
}
|
||||
|
||||
const vm::var<char> f(ppu, (u32)file.length() + 1);
|
||||
memcpy(f.get_ptr(), file.c_str(), file.size() + 1);
|
||||
s32 ret = cellFontOpenFontFile(library, f, 0, 0, font); //TODO: Find the correct values of subNum, uniqueId
|
||||
s32 ret = cellFontOpenFontFile(library, vm::make_str(file), 0, 0, font); //TODO: Find the correct values of subNum, uniqueId
|
||||
font->origin = CELL_FONT_OPEN_FONTSET;
|
||||
|
||||
return ret;
|
||||
@ -324,7 +322,7 @@ s32 cellFontRenderCharGlyphImage(vm::ptr<CellFont> font, u32 code, vm::ptr<CellF
|
||||
baseLineY = (int)((float)ascent * scale); // ???
|
||||
|
||||
// Move the rendered character to the surface
|
||||
unsigned char* buffer = vm::get_ptr<unsigned char>(surface->buffer.addr());
|
||||
unsigned char* buffer = vm::_ptr<unsigned char>(surface->buffer.addr());
|
||||
for (u32 ypos = 0; ypos < (u32)height; ypos++)
|
||||
{
|
||||
if ((u32)y + ypos + yoff + baseLineY >= surface->height)
|
||||
|
@ -24,20 +24,20 @@ s32 cellFsOpen(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, vm::cptr<void> a
|
||||
return sys_fs_open(path, flags, fd, flags & CELL_FS_O_CREAT ? CELL_FS_S_IRUSR | CELL_FS_S_IWUSR : 0, arg, size);
|
||||
}
|
||||
|
||||
s32 cellFsRead(PPUThread& ppu, u32 fd, vm::ptr<void> buf, u64 nbytes, vm::ptr<u64> nread)
|
||||
s32 cellFsRead(u32 fd, vm::ptr<void> buf, u64 nbytes, vm::ptr<u64> nread)
|
||||
{
|
||||
cellFs.Log("cellFsRead(fd=0x%x, buf=0x%x, nbytes=0x%llx, nread=0x%x)", fd, buf, nbytes, nread);
|
||||
|
||||
// call the syscall
|
||||
return sys_fs_read(fd, buf, nbytes, nread ? nread : vm::var<u64>(ppu));
|
||||
return sys_fs_read(fd, buf, nbytes, nread ? nread : vm::var<u64>{});
|
||||
}
|
||||
|
||||
s32 cellFsWrite(PPUThread& ppu, u32 fd, vm::cptr<void> buf, u64 nbytes, vm::ptr<u64> nwrite)
|
||||
s32 cellFsWrite(u32 fd, vm::cptr<void> buf, u64 nbytes, vm::ptr<u64> nwrite)
|
||||
{
|
||||
cellFs.Log("cellFsWrite(fd=0x%x, buf=*0x%x, nbytes=0x%llx, nwrite=*0x%x)", fd, buf, nbytes, nwrite);
|
||||
|
||||
// call the syscall
|
||||
return sys_fs_write(fd, buf, nbytes, nwrite ? nwrite : vm::var<u64>(ppu));
|
||||
return sys_fs_write(fd, buf, nbytes, nwrite ? nwrite : vm::var<u64>{});
|
||||
}
|
||||
|
||||
s32 cellFsClose(u32 fd)
|
||||
@ -147,22 +147,22 @@ s32 cellFsFsync(u32 fd)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFsFGetBlockSize(PPUThread& ppu, u32 fd, vm::ptr<u64> sector_size, vm::ptr<u64> block_size)
|
||||
s32 cellFsFGetBlockSize(u32 fd, vm::ptr<u64> sector_size, vm::ptr<u64> block_size)
|
||||
{
|
||||
cellFs.Log("cellFsFGetBlockSize(fd=0x%x, sector_size=*0x%x, block_size=*0x%x)", fd, sector_size, block_size);
|
||||
|
||||
// call the syscall
|
||||
return sector_size && block_size ? sys_fs_fget_block_size(fd, sector_size, block_size, vm::var<u64>(ppu), vm::var<u64>(ppu)) : CELL_FS_EFAULT;
|
||||
return sector_size && block_size ? sys_fs_fget_block_size(fd, sector_size, block_size, vm::var<u64>{}, vm::var<u64>{}) : CELL_FS_EFAULT;
|
||||
}
|
||||
|
||||
s32 cellFsGetBlockSize(PPUThread& ppu, vm::cptr<char> path, vm::ptr<u64> sector_size, vm::ptr<u64> block_size)
|
||||
s32 cellFsGetBlockSize(vm::cptr<char> path, vm::ptr<u64> sector_size, vm::ptr<u64> block_size)
|
||||
{
|
||||
cellFs.Warning("cellFsGetBlockSize(path=*0x%x, sector_size=*0x%x, block_size=*0x%x) -> sys_fs_get_block_size()", path, sector_size, block_size);
|
||||
|
||||
// TODO
|
||||
|
||||
// call the syscall
|
||||
return sys_fs_get_block_size(path, sector_size, block_size, vm::var<u64>(ppu));
|
||||
return sys_fs_get_block_size(path, sector_size, block_size, vm::var<u64>{});
|
||||
}
|
||||
|
||||
s32 cellFsTruncate(vm::cptr<char> path, u64 size)
|
||||
@ -494,7 +494,7 @@ s32 cellFsStReadStart(u32 fd, u64 offset, u64 size)
|
||||
|
||||
file->st_read_size = size;
|
||||
|
||||
file->st_thread.start([=]{ return fmt::format("FS ST Thread[0x%x]", fd); }, [=]()
|
||||
file->st_thread.start(COPY_EXPR(fmt::format("FS ST Thread[0x%x]", fd)), [=]()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(file->mutex);
|
||||
|
||||
@ -509,7 +509,7 @@ s32 cellFsStReadStart(u32 fd, u64 offset, u64 size)
|
||||
// read data
|
||||
auto old = file->file->Tell();
|
||||
file->file->Seek(offset + file->st_total_read);
|
||||
auto res = file->file->Read(vm::get_ptr(position), file->st_block_size);
|
||||
auto res = file->file->Read(vm::base(position), file->st_block_size);
|
||||
file->file->Seek(old);
|
||||
|
||||
// notify
|
||||
@ -526,9 +526,9 @@ s32 cellFsStReadStart(u32 fd, u64 offset, u64 size)
|
||||
{
|
||||
const auto func = file->st_callback.exchange({}).func;
|
||||
|
||||
Emu.GetCallbackManager().Async([=](CPUThread& ppu)
|
||||
Emu.GetCallbackManager().Async([=](PPUThread& ppu)
|
||||
{
|
||||
func(static_cast<PPUThread&>(ppu), fd, available);
|
||||
func(ppu, fd, available);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -600,8 +600,8 @@ s32 cellFsStRead(u32 fd, vm::ptr<u8> buf, u64 size, vm::ptr<u64> rsize)
|
||||
|
||||
// copy data
|
||||
const u64 first_size = std::min<u64>(copy_size, file->st_ringbuf_size - (position - file->st_buffer));
|
||||
memcpy(buf.get_ptr(), vm::get_ptr(position), first_size);
|
||||
memcpy((buf + first_size).get_ptr(), vm::get_ptr(file->st_buffer), copy_size - first_size);
|
||||
std::memcpy(buf.get_ptr(), vm::base(position), first_size);
|
||||
std::memcpy((buf + first_size).get_ptr(), vm::base(file->st_buffer), copy_size - first_size);
|
||||
|
||||
// notify
|
||||
file->st_copied += copy_size;
|
||||
@ -823,7 +823,7 @@ s32 sdata_unpack(const std::string& packed_file, const std::string& unpacked_fil
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFsSdataOpen(PPUThread& ppu, vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, vm::cptr<void> arg, u64 size)
|
||||
s32 cellFsSdataOpen(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, vm::cptr<void> arg, u64 size)
|
||||
{
|
||||
cellFs.Notice("cellFsSdataOpen(path=*0x%x, flags=%#o, fd=*0x%x, arg=*0x%x, size=0x%llx)", path, flags, fd, arg, size);
|
||||
|
||||
@ -832,17 +832,7 @@ s32 cellFsSdataOpen(PPUThread& ppu, vm::cptr<char> path, s32 flags, vm::ptr<u32>
|
||||
return CELL_FS_EINVAL;
|
||||
}
|
||||
|
||||
struct _arg_t
|
||||
{
|
||||
be_t<u32> a, b;
|
||||
};
|
||||
|
||||
const vm::var<_arg_t> _arg(ppu);
|
||||
|
||||
_arg->a = 0x180;
|
||||
_arg->b = 0x10;
|
||||
|
||||
return cellFsOpen(path, CELL_FS_O_RDONLY, fd, _arg, 8);
|
||||
return cellFsOpen(path, CELL_FS_O_RDONLY, fd, vm::make_var<be_t<u32>[2]>({ 0x180, 0x10 }), 8);
|
||||
|
||||
// Don't implement sdata decryption in this function, it should be done in sys_fs_open() syscall or somewhere else
|
||||
|
||||
@ -901,9 +891,9 @@ void fsAio(vm::ptr<CellFsAio> aio, bool write, s32 xid, fs_aio_cb_t func)
|
||||
}
|
||||
|
||||
// should be executed directly by FS AIO thread
|
||||
Emu.GetCallbackManager().Async([=](CPUThread& ppu)
|
||||
Emu.GetCallbackManager().Async([=](PPUThread& ppu)
|
||||
{
|
||||
func(static_cast<PPUThread&>(ppu), aio, error, xid, result);
|
||||
func(ppu, aio, error, xid, result);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -64,20 +64,10 @@ s32 cellHddGameCheck(PPUThread& ppu, u32 version, vm::cptr<char> dirName, u32 er
|
||||
return CELL_HDDGAME_ERROR_PARAM;
|
||||
}
|
||||
|
||||
struct _stack_t
|
||||
{
|
||||
CellHddGameSystemFileParam param;
|
||||
CellHddGameCBResult result;
|
||||
CellHddGameStatGet get;
|
||||
CellHddGameStatSet set;
|
||||
};
|
||||
|
||||
const vm::var<_stack_t> stack(ppu);
|
||||
|
||||
const auto param = stack.ptr(&_stack_t::param);
|
||||
const auto result = stack.ptr(&_stack_t::result);
|
||||
const auto get = stack.ptr(&_stack_t::get);
|
||||
const auto set = stack.ptr(&_stack_t::set);
|
||||
vm::var<CellHddGameSystemFileParam> param;
|
||||
vm::var<CellHddGameCBResult> result;
|
||||
vm::var<CellHddGameStatGet> get;
|
||||
vm::var<CellHddGameStatSet> set;
|
||||
|
||||
get->hddFreeSizeKB = 40 * 1024 * 1024; // 40 GB, TODO: Use the free space of the computer's HDD where RPCS3 is being run.
|
||||
get->isNewData = CELL_HDDGAME_ISNEWDATA_EXIST;
|
||||
@ -403,20 +393,9 @@ s32 cellGameDataCheckCreate2(PPUThread& ppu, u32 version, vm::cptr<char> dirName
|
||||
return CELL_GAMEDATA_ERROR_BROKEN;
|
||||
}
|
||||
|
||||
struct _stack_t
|
||||
{
|
||||
CellGameDataCBResult result;
|
||||
CellGameDataStatGet get;
|
||||
CellGameDataStatSet set;
|
||||
};
|
||||
|
||||
const vm::var<_stack_t> stack(ppu);
|
||||
|
||||
const auto cbResult = stack.ptr(&_stack_t::result);
|
||||
const auto cbGet = stack.ptr(&_stack_t::get);
|
||||
const auto cbSet = stack.ptr(&_stack_t::set);
|
||||
|
||||
*cbGet = {};
|
||||
vm::var<CellGameDataCBResult> cbResult;
|
||||
vm::var<CellGameDataStatGet> cbGet;
|
||||
vm::var<CellGameDataStatSet> cbSet;
|
||||
|
||||
// TODO: Use the free space of the computer's HDD where RPCS3 is being run.
|
||||
cbGet->hddFreeSizeKB = 40000000; //40 GB
|
||||
|
@ -379,17 +379,17 @@ s32 _cellGcmInitBody(vm::pptr<CellGcmContextData> context, u32 cmdSize, u32 ioSi
|
||||
|
||||
gcm_info.label_addr = vm::alloc(0x1000, vm::main); // ???
|
||||
|
||||
vm::get_ref<CellGcmContextData>(gcm_info.context_addr) = current_context;
|
||||
vm::_ref<CellGcmContextData>(gcm_info.context_addr) = current_context;
|
||||
context->set(gcm_info.context_addr);
|
||||
|
||||
auto& ctrl = vm::get_ref<CellGcmControl>(gcm_info.control_addr);
|
||||
auto& ctrl = vm::_ref<CellGcmControl>(gcm_info.control_addr);
|
||||
ctrl.put = 0;
|
||||
ctrl.get = 0;
|
||||
ctrl.ref = -1;
|
||||
|
||||
auto& render = Emu.GetGSManager().GetRender();
|
||||
render.ctxt_addr = context.addr();
|
||||
render.gcm_buffers = { vm::alloc(sizeof(CellGcmDisplayInfo) * 8, vm::main) };
|
||||
render.gcm_buffers.set(vm::alloc(sizeof(CellGcmDisplayInfo) * 8, vm::main));
|
||||
render.zculls_addr = vm::alloc(sizeof(CellGcmZcullInfo) * 8, vm::main);
|
||||
render.tiles_addr = vm::alloc(sizeof(CellGcmTileInfo) * 15, vm::main);
|
||||
render.gcm_buffers_count = 0;
|
||||
@ -511,14 +511,14 @@ s32 cellGcmSetPrepareFlip(PPUThread& ppu, vm::ptr<CellGcmContextData> ctxt, u32
|
||||
|
||||
if (ctxt.addr() == gcm_info.context_addr)
|
||||
{
|
||||
vm::get_ref<CellGcmControl>(gcm_info.control_addr).put += 2 * sizeof(u32);
|
||||
vm::_ref<CellGcmControl>(gcm_info.control_addr).put += 2 * sizeof(u32);
|
||||
}
|
||||
#else
|
||||
u32 command_size = rsx::make_command(ctxt->current, GCM_FLIP_COMMAND, id);
|
||||
|
||||
if (ctxt.addr() == gcm_info.context_addr)
|
||||
{
|
||||
vm::get_ref<CellGcmControl>(gcm_info.control_addr).put += command_size * sizeof(u32);
|
||||
vm::_ref<CellGcmControl>(gcm_info.control_addr).put += command_size * sizeof(u32);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -592,7 +592,7 @@ s32 cellGcmSetTileInfo(u8 index, u8 location, u32 offset, u32 size, u32 pitch, u
|
||||
tile.base = base;
|
||||
tile.bank = bank;
|
||||
|
||||
vm::get_ptr<CellGcmTileInfo>(Emu.GetGSManager().GetRender().tiles_addr)[index] = tile.pack();
|
||||
vm::_ptr<CellGcmTileInfo>(Emu.GetGSManager().GetRender().tiles_addr)[index] = tile.pack();
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -653,7 +653,7 @@ s32 cellGcmSetZcull(u8 index, u32 offset, u32 width, u32 height, u32 cullStart,
|
||||
zcull.sRef = sRef;
|
||||
zcull.sMask = sMask;
|
||||
|
||||
vm::get_ptr<CellGcmZcullInfo>(Emu.GetGSManager().GetRender().zculls_addr)[index] = zcull.pack();
|
||||
vm::_ptr<CellGcmZcullInfo>(Emu.GetGSManager().GetRender().zculls_addr)[index] = zcull.pack();
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -1183,7 +1183,7 @@ s32 cellGcmSetTile(u8 index, u8 location, u32 offset, u32 size, u32 pitch, u8 co
|
||||
tile.base = base;
|
||||
tile.bank = bank;
|
||||
|
||||
vm::get_ptr<CellGcmTileInfo>(Emu.GetGSManager().GetRender().tiles_addr)[index] = tile.pack();
|
||||
vm::_ptr<CellGcmTileInfo>(Emu.GetGSManager().GetRender().tiles_addr)[index] = tile.pack();
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -1274,7 +1274,7 @@ s32 cellGcmCallback(vm::ptr<CellGcmContextData> context, u32 count)
|
||||
{
|
||||
cellGcmSys.Log("cellGcmCallback(context=*0x%x, count=0x%x)", context, count);
|
||||
|
||||
auto& ctrl = vm::get_ref<CellGcmControl>(gcm_info.control_addr);
|
||||
auto& ctrl = vm::_ref<CellGcmControl>(gcm_info.control_addr);
|
||||
const std::chrono::time_point<std::chrono::system_clock> enterWait = std::chrono::system_clock::now();
|
||||
// Flush command buffer (ie allow RSX to read up to context->current)
|
||||
ctrl.put.exchange(getOffsetFromAddress(context->current.addr()));
|
||||
@ -1291,7 +1291,7 @@ s32 cellGcmCallback(vm::ptr<CellGcmContextData> context, u32 count)
|
||||
// Wait for rsx to "release" the new command buffer
|
||||
while (!Emu.IsStopped())
|
||||
{
|
||||
u32 getPos = ctrl.get.load().value();
|
||||
u32 getPos = ctrl.get.load();
|
||||
if (isInCommandBufferExcept(getPos, newCommandBuffer.first, newCommandBuffer.second))
|
||||
break;
|
||||
std::chrono::time_point<std::chrono::system_clock> waitPoint = std::chrono::system_clock::now();
|
||||
|
@ -55,7 +55,7 @@ s32 cellGifDecOpen(PMainHandle mainHandle, PPSubHandle subHandle, PSrc src, POpe
|
||||
current_subHandle.fd = 0;
|
||||
current_subHandle.src = *src;
|
||||
|
||||
switch (src->srcSelect.value())
|
||||
switch (src->srcSelect)
|
||||
{
|
||||
case CELL_GIFDEC_BUFFER:
|
||||
current_subHandle.fileSize = src->streamSize;
|
||||
@ -96,7 +96,7 @@ s32 cellGifDecReadHeader(PMainHandle mainHandle, PSubHandle subHandle, PInfo inf
|
||||
// Write the header to buffer
|
||||
u8 buffer[13];
|
||||
|
||||
switch (subHandle->src.srcSelect.value())
|
||||
switch (subHandle->src.srcSelect)
|
||||
{
|
||||
case CELL_GIFDEC_BUFFER:
|
||||
std::memcpy(buffer, subHandle->src.streamPtr.get_ptr(), sizeof(buffer));
|
||||
@ -180,7 +180,7 @@ s32 cellGifDecDecodeData(PMainHandle mainHandle, PSubHandle subHandle, vm::ptr<u
|
||||
//Copy the GIF file to a buffer
|
||||
std::unique_ptr<u8[]> gif(new u8[fileSize]);
|
||||
|
||||
switch (subHandle->src.srcSelect.value())
|
||||
switch (subHandle->src.srcSelect)
|
||||
{
|
||||
case CELL_GIFDEC_BUFFER:
|
||||
std::memcpy(gif.get(), subHandle->src.streamPtr.get_ptr(), fileSize);
|
||||
|
@ -44,7 +44,7 @@ s32 cellJpgDecOpen(u32 mainHandle, vm::ptr<u32> subHandle, vm::ptr<CellJpgDecSrc
|
||||
current_subHandle.fd = 0;
|
||||
current_subHandle.src = *src;
|
||||
|
||||
switch(src->srcSelect.value())
|
||||
switch (src->srcSelect)
|
||||
{
|
||||
case CELL_JPGDEC_BUFFER:
|
||||
current_subHandle.fileSize = src->streamSize;
|
||||
@ -108,10 +108,10 @@ s32 cellJpgDecReadHeader(u32 mainHandle, u32 subHandle, vm::ptr<CellJpgDecInfo>
|
||||
// Write the header to buffer
|
||||
std::unique_ptr<u8[]> buffer(new u8[fileSize]);
|
||||
|
||||
switch(subHandle_data->src.srcSelect.value())
|
||||
switch (subHandle_data->src.srcSelect)
|
||||
{
|
||||
case CELL_JPGDEC_BUFFER:
|
||||
std::memcpy(buffer.get(), vm::get_ptr(subHandle_data->src.streamPtr), fileSize);
|
||||
std::memcpy(buffer.get(), vm::base(subHandle_data->src.streamPtr), fileSize);
|
||||
break;
|
||||
|
||||
case CELL_JPGDEC_FILE:
|
||||
@ -187,10 +187,10 @@ s32 cellJpgDecDecodeData(u32 mainHandle, u32 subHandle, vm::ptr<u8> data, vm::cp
|
||||
//Copy the JPG file to a buffer
|
||||
std::unique_ptr<u8[]> jpg(new u8[fileSize]);
|
||||
|
||||
switch(subHandle_data->src.srcSelect.value())
|
||||
switch (subHandle_data->src.srcSelect)
|
||||
{
|
||||
case CELL_JPGDEC_BUFFER:
|
||||
std::memcpy(jpg.get(), vm::get_ptr(subHandle_data->src.streamPtr), fileSize);
|
||||
std::memcpy(jpg.get(), vm::base(subHandle_data->src.streamPtr), fileSize);
|
||||
break;
|
||||
|
||||
case CELL_JPGDEC_FILE:
|
||||
|
@ -1056,7 +1056,7 @@ s32 UTF8toBIG5()
|
||||
throw EXCEPTION("");
|
||||
}
|
||||
|
||||
s32 UTF16stoUTF8s(vm::cptr<char16_t> utf16, vm::ref<u32> utf16_len, vm::ptr<char> utf8, vm::ref<u32> utf8_len)
|
||||
s32 UTF16stoUTF8s(vm::cptr<u16> utf16, vm::ref<u32> utf16_len, vm::ptr<u8> utf8, vm::ref<u32> utf8_len)
|
||||
{
|
||||
cellL10n.Error("UTF16stoUTF8s(utf16=*0x%x, utf16_len=*0x%x, utf8=*0x%x, utf8_len=*0x%x)", utf16, utf16_len, utf8, utf8_len);
|
||||
|
||||
@ -1064,7 +1064,7 @@ s32 UTF16stoUTF8s(vm::cptr<char16_t> utf16, vm::ref<u32> utf16_len, vm::ptr<char
|
||||
|
||||
for (u32 i = 0, len = 0; i < utf16_len; i++, utf8_len = len)
|
||||
{
|
||||
const char16_t ch = utf16[i];
|
||||
const u16 ch = utf16[i];
|
||||
|
||||
// increase required length (TODO)
|
||||
len = len + 1;
|
||||
@ -1086,7 +1086,7 @@ s32 UTF16stoUTF8s(vm::cptr<char16_t> utf16, vm::ref<u32> utf16_len, vm::ptr<char
|
||||
|
||||
if (ch <= 0x7f)
|
||||
{
|
||||
*utf8++ = static_cast<char>(ch);
|
||||
*utf8++ = static_cast<u8>(ch);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -10,14 +10,6 @@
|
||||
|
||||
extern Module<> cellSysutil;
|
||||
|
||||
void MsgDialogBase::Close(s32 status)
|
||||
{
|
||||
if (state.compare_and_swap_test(MsgDialogState::Open, MsgDialogState::Close))
|
||||
{
|
||||
on_close(status);
|
||||
}
|
||||
}
|
||||
|
||||
s32 cellMsgDialogOpen()
|
||||
{
|
||||
throw EXCEPTION("");
|
||||
@ -32,49 +24,37 @@ s32 cellMsgDialogOpen2(u32 type, vm::cptr<char> msgString, vm::ptr<CellMsgDialog
|
||||
return CELL_MSGDIALOG_ERROR_PARAM;
|
||||
}
|
||||
|
||||
switch (type & CELL_MSGDIALOG_TYPE_BUTTON_TYPE)
|
||||
const MsgDialogType _type = { type };
|
||||
|
||||
switch (_type.button_type.unshifted())
|
||||
{
|
||||
case CELL_MSGDIALOG_TYPE_BUTTON_TYPE_NONE:
|
||||
{
|
||||
if (type & CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR)
|
||||
if (_type.default_cursor || _type.progress_bar_count > 2)
|
||||
{
|
||||
return CELL_MSGDIALOG_ERROR_PARAM;
|
||||
}
|
||||
switch (type & CELL_MSGDIALOG_TYPE_PROGRESSBAR)
|
||||
{
|
||||
case CELL_MSGDIALOG_TYPE_PROGRESSBAR_NONE: break;
|
||||
case CELL_MSGDIALOG_TYPE_PROGRESSBAR_SINGLE: break;
|
||||
case CELL_MSGDIALOG_TYPE_PROGRESSBAR_DOUBLE: break;
|
||||
default: return CELL_MSGDIALOG_ERROR_PARAM;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case CELL_MSGDIALOG_TYPE_BUTTON_TYPE_YESNO:
|
||||
{
|
||||
switch (type & CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR)
|
||||
{
|
||||
case CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR_YES: break;
|
||||
case CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR_NO: break;
|
||||
default: return CELL_MSGDIALOG_ERROR_PARAM;
|
||||
}
|
||||
if (type & CELL_MSGDIALOG_TYPE_PROGRESSBAR)
|
||||
if (_type.default_cursor > 1 || _type.progress_bar_count)
|
||||
{
|
||||
return CELL_MSGDIALOG_ERROR_PARAM;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK:
|
||||
{
|
||||
if (type & CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR)
|
||||
{
|
||||
return CELL_MSGDIALOG_ERROR_PARAM;
|
||||
}
|
||||
if (type & CELL_MSGDIALOG_TYPE_PROGRESSBAR)
|
||||
if (_type.default_cursor || _type.progress_bar_count)
|
||||
{
|
||||
return CELL_MSGDIALOG_ERROR_PARAM;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -88,49 +68,43 @@ s32 cellMsgDialogOpen2(u32 type, vm::cptr<char> msgString, vm::ptr<CellMsgDialog
|
||||
return CELL_SYSUTIL_ERROR_BUSY;
|
||||
}
|
||||
|
||||
dlg->type = type;
|
||||
|
||||
switch (type & CELL_MSGDIALOG_TYPE_PROGRESSBAR)
|
||||
if (_type.se_mute_on)
|
||||
{
|
||||
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;
|
||||
// TODO
|
||||
}
|
||||
|
||||
switch (type & CELL_MSGDIALOG_TYPE_SE_MUTE) // TODO
|
||||
if (_type.se_normal)
|
||||
{
|
||||
case CELL_MSGDIALOG_TYPE_SE_MUTE_OFF: break;
|
||||
case CELL_MSGDIALOG_TYPE_SE_MUTE_ON: break;
|
||||
cellSysutil.Warning(msgString.get_ptr());
|
||||
}
|
||||
else
|
||||
{
|
||||
cellSysutil.Error(msgString.get_ptr());
|
||||
}
|
||||
|
||||
switch (type & CELL_MSGDIALOG_TYPE_SE_TYPE)
|
||||
dlg->type = _type;
|
||||
|
||||
dlg->on_close = [callback, userData, wptr = std::weak_ptr<MsgDialogBase>(dlg)](s32 status)
|
||||
{
|
||||
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;
|
||||
}
|
||||
const auto dlg = wptr.lock();
|
||||
|
||||
dlg->callback = callback;
|
||||
dlg->user_data = userData;
|
||||
dlg->extra_param = extParam;
|
||||
|
||||
dlg->on_close = [](s32 status)
|
||||
{
|
||||
const auto dlg = fxm::get<MsgDialogBase>();
|
||||
|
||||
if (dlg->callback)
|
||||
if (dlg && dlg->state.compare_and_swap_test(MsgDialogState::Open, MsgDialogState::Close))
|
||||
{
|
||||
Emu.GetCallbackManager().Register([func = dlg->callback, status, arg = dlg->user_data](CPUThread& cpu)->s32
|
||||
if (callback)
|
||||
{
|
||||
func(static_cast<PPUThread&>(cpu), status, arg);
|
||||
return CELL_OK;
|
||||
});
|
||||
}
|
||||
Emu.GetCallbackManager().Register([=](PPUThread& ppu) -> s32
|
||||
{
|
||||
callback(ppu, status, userData);
|
||||
return CELL_OK;
|
||||
});
|
||||
}
|
||||
|
||||
fxm::remove<MsgDialogBase>();
|
||||
fxm::remove<MsgDialogBase>();
|
||||
}
|
||||
};
|
||||
|
||||
// call initialization asynchronously from the GUI thread, wait for the "result"
|
||||
Emu.CallAfter(WRAP_EXPR(dlg->Create(type, msgString.get_ptr()))).get();
|
||||
Emu.CallAfter(WRAP_EXPR(dlg->Create(msgString.get_ptr()))).get();
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -209,11 +183,7 @@ s32 cellMsgDialogOpenErrorCode(PPUThread& ppu, u32 errorCode, vm::ptr<CellMsgDia
|
||||
|
||||
error.append(fmt::format("\n(%08x)", errorCode));
|
||||
|
||||
const vm::var<char> message(ppu, error.size() + 1);
|
||||
|
||||
std::memcpy(message.get_ptr(), error.c_str(), error.size() + 1);
|
||||
|
||||
return cellMsgDialogOpen2(CELL_MSGDIALOG_DIALOG_TYPE_ERROR | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK, message, callback, userData, extParam);
|
||||
return cellMsgDialogOpen2(CELL_MSGDIALOG_TYPE_SE_TYPE_ERROR | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK, vm::make_str(error), callback, userData, extParam);
|
||||
}
|
||||
|
||||
s32 cellMsgDialogOpenSimulViewWarning()
|
||||
@ -234,7 +204,7 @@ s32 cellMsgDialogClose(f32 delay)
|
||||
|
||||
extern u64 get_system_time();
|
||||
|
||||
const u64 wait_until = get_system_time() + static_cast<u64>(std::max<float>(delay, 0.0f) * 1000);
|
||||
const u64 wait_until = get_system_time() + static_cast<s64>(std::max<float>(delay, 0.0f) * 1000);
|
||||
|
||||
named_thread_t(WRAP_EXPR("MsgDialog Thread"), [=]()
|
||||
{
|
||||
@ -245,9 +215,7 @@ s32 cellMsgDialogClose(f32 delay)
|
||||
std::this_thread::sleep_for(1ms);
|
||||
}
|
||||
|
||||
Emu.CallAfter(COPY_EXPR(dlg->Destroy()));
|
||||
|
||||
dlg->Close(CELL_MSGDIALOG_BUTTON_NONE);
|
||||
dlg->on_close(CELL_MSGDIALOG_BUTTON_NONE);
|
||||
|
||||
}).detach();
|
||||
|
||||
@ -275,9 +243,6 @@ s32 cellMsgDialogAbort()
|
||||
throw EXCEPTION("Failed to remove MsgDialog object");
|
||||
}
|
||||
|
||||
// call finalization from the GUI thread
|
||||
Emu.CallAfter(COPY_EXPR(dlg->Destroy()));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -292,7 +257,7 @@ s32 cellMsgDialogProgressBarSetMsg(u32 progressBarIndex, vm::cptr<char> msgStrin
|
||||
return CELL_MSGDIALOG_ERROR_DIALOG_NOT_OPENED;
|
||||
}
|
||||
|
||||
if (progressBarIndex >= dlg->progress_bar_count)
|
||||
if (progressBarIndex >= dlg->type.progress_bar_count)
|
||||
{
|
||||
return CELL_MSGDIALOG_ERROR_PARAM;
|
||||
}
|
||||
@ -316,7 +281,7 @@ s32 cellMsgDialogProgressBarReset(u32 progressBarIndex)
|
||||
return CELL_MSGDIALOG_ERROR_DIALOG_NOT_OPENED;
|
||||
}
|
||||
|
||||
if (progressBarIndex >= dlg->progress_bar_count)
|
||||
if (progressBarIndex >= dlg->type.progress_bar_count)
|
||||
{
|
||||
return CELL_MSGDIALOG_ERROR_PARAM;
|
||||
}
|
||||
@ -337,7 +302,7 @@ s32 cellMsgDialogProgressBarInc(u32 progressBarIndex, u32 delta)
|
||||
return CELL_MSGDIALOG_ERROR_DIALOG_NOT_OPENED;
|
||||
}
|
||||
|
||||
if (progressBarIndex >= dlg->progress_bar_count)
|
||||
if (progressBarIndex >= dlg->type.progress_bar_count)
|
||||
{
|
||||
return CELL_MSGDIALOG_ERROR_PARAM;
|
||||
}
|
||||
|
@ -8,67 +8,32 @@ enum
|
||||
CELL_MSGDIALOG_ERROR_DIALOG_NOT_OPENED = 0x8002b302,
|
||||
};
|
||||
|
||||
enum CellMsgDialogType : u32
|
||||
{
|
||||
CELL_MSGDIALOG_DIALOG_TYPE_ERROR = 0x00000000,
|
||||
CELL_MSGDIALOG_DIALOG_TYPE_NORMAL = 0x00000001,
|
||||
CELL_MSGDIALOG_BUTTON_TYPE_NONE = 0x00000000,
|
||||
CELL_MSGDIALOG_BUTTON_TYPE_YESNO = 0x00000010,
|
||||
CELL_MSGDIALOG_DEFAULT_CURSOR_YES = 0x00000000,
|
||||
CELL_MSGDIALOG_DEFAULT_CURSOR_NO = 0x00000100,
|
||||
};
|
||||
|
||||
enum : u32
|
||||
{
|
||||
CELL_MSGDIALOG_TYPE_SE_TYPE = 0x1,
|
||||
CELL_MSGDIALOG_TYPE_SE_TYPE_ERROR = 0 << 0,
|
||||
CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL = 1 << 0,
|
||||
};
|
||||
CELL_MSGDIALOG_TYPE_SE_TYPE_ERROR = 0 << 0,
|
||||
CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL = 1 << 0,
|
||||
|
||||
enum : u32
|
||||
{
|
||||
CELL_MSGDIALOG_TYPE_SE_MUTE = 0x2,
|
||||
CELL_MSGDIALOG_TYPE_SE_MUTE_OFF = 0 << 1,
|
||||
CELL_MSGDIALOG_TYPE_SE_MUTE_ON = 1 << 1,
|
||||
};
|
||||
CELL_MSGDIALOG_TYPE_SE_MUTE_OFF = 0 << 1,
|
||||
CELL_MSGDIALOG_TYPE_SE_MUTE_ON = 1 << 1,
|
||||
|
||||
enum : u32
|
||||
{
|
||||
CELL_MSGDIALOG_TYPE_BG = 0x4,
|
||||
CELL_MSGDIALOG_TYPE_BG_VISIBLE = 0 << 2,
|
||||
CELL_MSGDIALOG_TYPE_BG_INVISIBLE = 1 << 2,
|
||||
};
|
||||
CELL_MSGDIALOG_TYPE_BG_VISIBLE = 0 << 2,
|
||||
CELL_MSGDIALOG_TYPE_BG_INVISIBLE = 1 << 2,
|
||||
|
||||
enum : u32
|
||||
{
|
||||
CELL_MSGDIALOG_TYPE_BUTTON_TYPE = 0x70,
|
||||
CELL_MSGDIALOG_TYPE_BUTTON_TYPE_NONE = 0 << 4,
|
||||
CELL_MSGDIALOG_TYPE_BUTTON_TYPE_YESNO = 1 << 4,
|
||||
CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK = 2 << 4,
|
||||
};
|
||||
CELL_MSGDIALOG_TYPE_BUTTON_TYPE_NONE = 0 << 4,
|
||||
CELL_MSGDIALOG_TYPE_BUTTON_TYPE_YESNO = 1 << 4,
|
||||
CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK = 2 << 4,
|
||||
|
||||
enum : u32
|
||||
{
|
||||
CELL_MSGDIALOG_TYPE_DISABLE_CANCEL = 0x80,
|
||||
CELL_MSGDIALOG_TYPE_DISABLE_CANCEL_OFF = 0 << 7,
|
||||
CELL_MSGDIALOG_TYPE_DISABLE_CANCEL_ON = 1 << 7,
|
||||
};
|
||||
CELL_MSGDIALOG_TYPE_DISABLE_CANCEL_OFF = 0 << 7,
|
||||
CELL_MSGDIALOG_TYPE_DISABLE_CANCEL_ON = 1 << 7,
|
||||
|
||||
enum : u32
|
||||
{
|
||||
CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR = 0x300,
|
||||
CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR_NONE = 0 << 8,
|
||||
CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR_YES = 0 << 8,
|
||||
CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR_NO = 1 << 8,
|
||||
CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR_OK = 0 << 8,
|
||||
};
|
||||
|
||||
enum : u32
|
||||
{
|
||||
CELL_MSGDIALOG_TYPE_PROGRESSBAR = 0x3000,
|
||||
CELL_MSGDIALOG_TYPE_PROGRESSBAR_NONE = 0 << 12,
|
||||
CELL_MSGDIALOG_TYPE_PROGRESSBAR_SINGLE = 1 << 12,
|
||||
CELL_MSGDIALOG_TYPE_PROGRESSBAR_DOUBLE = 2 << 12,
|
||||
CELL_MSGDIALOG_TYPE_PROGRESSBAR_NONE = 0 << 12,
|
||||
CELL_MSGDIALOG_TYPE_PROGRESSBAR_SINGLE = 1 << 12,
|
||||
CELL_MSGDIALOG_TYPE_PROGRESSBAR_DOUBLE = 2 << 12,
|
||||
};
|
||||
|
||||
// MsgDialog Button Type
|
||||
@ -84,6 +49,19 @@ enum : s32
|
||||
|
||||
using CellMsgDialogCallback = void(s32 buttonType, vm::ptr<void> userData);
|
||||
|
||||
union MsgDialogType
|
||||
{
|
||||
u32 value;
|
||||
|
||||
bf_t<u32, 0, 1> se_normal;
|
||||
bf_t<u32, 1, 1> se_mute_on;
|
||||
bf_t<u32, 2, 1> bg_invisible;
|
||||
bf_t<u32, 4, 3> button_type;
|
||||
bf_t<u32, 7, 1> disable_cancel;
|
||||
bf_t<u32, 8, 2> default_cursor;
|
||||
bf_t<u32, 12, 2> progress_bar_count;
|
||||
};
|
||||
|
||||
enum class MsgDialogState
|
||||
{
|
||||
Open,
|
||||
@ -96,20 +74,12 @@ class MsgDialogBase
|
||||
public:
|
||||
atomic_t<MsgDialogState> state{ MsgDialogState::Open };
|
||||
|
||||
u32 type;
|
||||
u32 progress_bar_count;
|
||||
|
||||
vm::ptr<CellMsgDialogCallback> callback;
|
||||
vm::ptr<void> user_data;
|
||||
vm::ptr<void> extra_param;
|
||||
MsgDialogType type;
|
||||
|
||||
std::function<void(s32 status)> on_close;
|
||||
|
||||
void Close(s32 status);
|
||||
|
||||
virtual ~MsgDialogBase() = default;
|
||||
virtual void Create(u32 type, const std::string& msg) = 0;
|
||||
virtual void Destroy() = 0;
|
||||
virtual void Create(const 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;
|
||||
|
@ -120,20 +120,15 @@ s32 cellMusicInitialize2(s32 mode, s32 spuPriority, vm::ptr<CellMusic2Callback>
|
||||
return CELL_MUSIC2_ERROR_PARAM;
|
||||
}
|
||||
|
||||
named_thread_t(WRAP_EXPR("CellMusicInit"), [=]()
|
||||
{
|
||||
const auto music = fxm::make_always<music2_t>();
|
||||
music->func = func;
|
||||
music->userData = userData;
|
||||
const auto music = fxm::make_always<music2_t>();
|
||||
music->func = func;
|
||||
music->userData = userData;
|
||||
|
||||
Emu.GetCallbackManager().Register([=](CPUThread& CPU) -> s32
|
||||
{
|
||||
vm::var<u32> ret(CPU);
|
||||
*ret = CELL_OK;
|
||||
func(static_cast<PPUThread&>(CPU), CELL_MUSIC2_EVENT_INITIALIZE_RESULT, ret, userData);
|
||||
return CELL_OK;
|
||||
});
|
||||
}).detach();
|
||||
Emu.GetCallbackManager().Register([=](PPUThread& ppu) -> s32
|
||||
{
|
||||
func(ppu, CELL_MUSIC2_EVENT_INITIALIZE_RESULT, vm::make_var<s32>(CELL_OK), userData);
|
||||
return CELL_OK;
|
||||
});
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ enum
|
||||
};
|
||||
|
||||
using CellMusicCallback = void(u32 event, vm::ptr<void> param, vm::ptr<void> userData);
|
||||
using CellMusic2Callback = void(u32 event, vm::ptr<u32> param, vm::ptr<void> userData);
|
||||
using CellMusic2Callback = void(u32 event, vm::ptr<void> param, vm::ptr<void> userData);
|
||||
|
||||
struct CellMusicSelectionContext
|
||||
{
|
||||
|
@ -89,7 +89,7 @@ s32 pngDecOpen(PMainHandle dec, PPSubHandle subHandle, PSrc src, POpenInfo openI
|
||||
stream->fd = 0;
|
||||
stream->src = *src;
|
||||
|
||||
switch (src->srcSelect.value())
|
||||
switch (src->srcSelect)
|
||||
{
|
||||
case CELL_PNGDEC_BUFFER:
|
||||
stream->fileSize = src->streamSize;
|
||||
@ -150,7 +150,7 @@ s32 pngReadHeader(PSubHandle stream, vm::ptr<CellPngDecInfo> info, PExtInfo extI
|
||||
// Write the header to buffer
|
||||
u8 buffer[34]; be_t<u32>* buffer_32 = reinterpret_cast<be_t<u32>*>(buffer);
|
||||
|
||||
switch (stream->src.srcSelect.value())
|
||||
switch (stream->src.srcSelect)
|
||||
{
|
||||
case CELL_PNGDEC_BUFFER:
|
||||
std::memcpy(buffer, stream->src.streamPtr.get_ptr(), sizeof(buffer));
|
||||
@ -209,7 +209,7 @@ s32 pngDecSetParameter(PSubHandle stream, PInParam inParam, POutParam outParam,
|
||||
current_outParam.outputHeight = current_info.imageHeight;
|
||||
current_outParam.outputColorSpace = inParam->outputColorSpace;
|
||||
|
||||
switch (current_outParam.outputColorSpace.value())
|
||||
switch (current_outParam.outputColorSpace)
|
||||
{
|
||||
case CELL_PNGDEC_PALETTE:
|
||||
case CELL_PNGDEC_GRAYSCALE:
|
||||
@ -250,7 +250,7 @@ s32 pngDecodeData(PSubHandle stream, vm::ptr<u8> data, PDataCtrlParam dataCtrlPa
|
||||
// Copy the PNG file to a buffer
|
||||
std::unique_ptr<u8[]> png(new u8[fileSize]);
|
||||
|
||||
switch (stream->src.srcSelect.value())
|
||||
switch (stream->src.srcSelect)
|
||||
{
|
||||
case CELL_PNGDEC_BUFFER:
|
||||
std::memcpy(png.get(), stream->src.streamPtr.get_ptr(), fileSize);
|
||||
@ -282,7 +282,7 @@ s32 pngDecodeData(PSubHandle stream, vm::ptr<u8> data, PDataCtrlParam dataCtrlPa
|
||||
const int bytesPerLine = (u32)dataCtrlParam->outputBytesPerLine;
|
||||
uint image_size = width * height;
|
||||
|
||||
switch (current_outParam.outputColorSpace.value())
|
||||
switch (current_outParam.outputColorSpace)
|
||||
{
|
||||
case CELL_PNGDEC_RGB:
|
||||
case CELL_PNGDEC_RGBA:
|
||||
|
@ -708,7 +708,7 @@ void SetFlipHandler(vm::ptr<void(u32)> handler)
|
||||
}
|
||||
}
|
||||
|
||||
s32 cellRescSetDisplayMode(PPUThread& ppu, u32 displayMode)
|
||||
s32 cellRescSetDisplayMode(u32 displayMode)
|
||||
{
|
||||
cellResc.Warning("cellRescSetDisplayMode(displayMode=%d)", displayMode);
|
||||
|
||||
@ -759,7 +759,7 @@ s32 cellRescSetDisplayMode(PPUThread& ppu, u32 displayMode)
|
||||
else m_pCFragmentShader = m_pCFragmentShaderArray[RESC_SHADER_DEFAULT_BILINEAR];
|
||||
}*/
|
||||
|
||||
const vm::var<CellVideoOutConfiguration> videocfg(ppu);
|
||||
vm::var<CellVideoOutConfiguration> videocfg;
|
||||
videocfg->resolutionId = RescBufferMode2SysutilResolutionId(s_rescInternalInstance->m_dstMode);
|
||||
videocfg->format = RescDstFormat2SysutilFormat(s_rescInternalInstance->m_pRescDsts->format );
|
||||
videocfg->aspect = CELL_VIDEO_OUT_ASPECT_AUTO;
|
||||
@ -1024,7 +1024,7 @@ s32 cellRescSetWaitFlip()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellRescSetBufferAddress(PPUThread& ppu, vm::ptr<u32> colorBuffers, vm::ptr<u32> vertexArray, vm::ptr<u32> fragmentShader)
|
||||
s32 cellRescSetBufferAddress(vm::ptr<u32> colorBuffers, vm::ptr<u32> vertexArray, vm::ptr<u32> fragmentShader)
|
||||
{
|
||||
cellResc.Warning("cellRescSetBufferAddress(colorBuffers=*0x%x, vertexArray=*0x%x, fragmentShader=*0x%x)", colorBuffers, vertexArray, fragmentShader);
|
||||
|
||||
@ -1044,7 +1044,7 @@ s32 cellRescSetBufferAddress(PPUThread& ppu, vm::ptr<u32> colorBuffers, vm::ptr<
|
||||
s_rescInternalInstance->m_vertexArrayEA = vertexArray.addr();
|
||||
s_rescInternalInstance->m_fragmentUcodeEA = fragmentShader.addr();
|
||||
|
||||
const vm::var<u32> dstOffset(ppu);
|
||||
vm::var<u32> dstOffset;
|
||||
cellGcmAddressToOffset(s_rescInternalInstance->m_colorBuffersEA, dstOffset);
|
||||
|
||||
for (s32 i=0; i<GetNumColorBuffers(); i++)
|
||||
|
@ -12,23 +12,23 @@ extern Module<> cellSail;
|
||||
|
||||
void playerBoot(vm::ptr<CellSailPlayer> pSelf, u64 userParam)
|
||||
{
|
||||
Emu.GetCallbackManager().Async([=](CPUThread& cpu)
|
||||
Emu.GetCallbackManager().Async([=](PPUThread& ppu)
|
||||
{
|
||||
CellSailEvent event;
|
||||
event.u32x2.major = CELL_SAIL_EVENT_PLAYER_STATE_CHANGED;
|
||||
event.u32x2.minor = 0;
|
||||
pSelf->callback(static_cast<PPUThread&>(cpu), pSelf->callbackArg, event, CELL_SAIL_PLAYER_STATE_BOOT_TRANSITION, 0);
|
||||
pSelf->callback(ppu, pSelf->callbackArg, event, CELL_SAIL_PLAYER_STATE_BOOT_TRANSITION, 0);
|
||||
});
|
||||
|
||||
// TODO: Do stuff here
|
||||
pSelf->booted = true;
|
||||
|
||||
Emu.GetCallbackManager().Async([=](CPUThread& cpu)
|
||||
Emu.GetCallbackManager().Async([=](PPUThread& ppu)
|
||||
{
|
||||
CellSailEvent event;
|
||||
event.u32x2.major = CELL_SAIL_EVENT_PLAYER_CALL_COMPLETED;
|
||||
event.u32x2.minor = CELL_SAIL_PLAYER_CALL_BOOT;
|
||||
pSelf->callback(static_cast<PPUThread&>(cpu), pSelf->callbackArg, event, 0, 0);
|
||||
pSelf->callback(ppu, pSelf->callbackArg, event, 0, 0);
|
||||
});
|
||||
}
|
||||
|
||||
@ -633,12 +633,12 @@ s32 cellSailPlayerInitialize2(
|
||||
pSelf->booted = false;
|
||||
pSelf->paused = true;
|
||||
|
||||
Emu.GetCallbackManager().Async([=](CPUThread& cpu)
|
||||
Emu.GetCallbackManager().Async([=](PPUThread& ppu)
|
||||
{
|
||||
CellSailEvent event;
|
||||
event.u32x2.major = CELL_SAIL_EVENT_PLAYER_STATE_CHANGED;
|
||||
event.u32x2.minor = 0;
|
||||
pSelf->callback(static_cast<PPUThread&>(cpu), pSelf->callbackArg, event, CELL_SAIL_PLAYER_STATE_INITIALIZED, 0);
|
||||
pSelf->callback(ppu, pSelf->callbackArg, event, CELL_SAIL_PLAYER_STATE_INITIALIZED, 0);
|
||||
});
|
||||
|
||||
return CELL_OK;
|
||||
|
@ -668,7 +668,8 @@ union CellSailEvent
|
||||
{
|
||||
be_t<u32> major;
|
||||
be_t<u32> minor;
|
||||
} u32x2;
|
||||
}
|
||||
u32x2;
|
||||
|
||||
be_t<u64> value;
|
||||
};
|
||||
@ -677,7 +678,7 @@ template<typename T, bool is_enum> struct cast_ppu_gpr;
|
||||
|
||||
template<> struct cast_ppu_gpr<CellSailEvent, false>
|
||||
{
|
||||
inline static u64 to_gpr(const CellSailEvent& event)
|
||||
static inline u64 to_gpr(const CellSailEvent& event)
|
||||
{
|
||||
return event.value;
|
||||
}
|
||||
|
@ -50,28 +50,14 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt
|
||||
return CELL_SAVEDATA_ERROR_BUSY;
|
||||
}
|
||||
|
||||
struct _stack_t
|
||||
{
|
||||
CellSaveDataCBResult result;
|
||||
CellSaveDataListGet listGet;
|
||||
CellSaveDataListSet listSet;
|
||||
CellSaveDataFixedSet fixedSet;
|
||||
CellSaveDataStatGet statGet;
|
||||
CellSaveDataStatSet statSet;
|
||||
CellSaveDataFileGet fileGet;
|
||||
CellSaveDataFileSet fileSet;
|
||||
};
|
||||
|
||||
const vm::var<_stack_t> stack(ppu);
|
||||
|
||||
const auto result = stack.ptr(&_stack_t::result);
|
||||
const auto listGet = stack.ptr(&_stack_t::listGet);
|
||||
const auto listSet = stack.ptr(&_stack_t::listSet);
|
||||
const auto fixedSet = stack.ptr(&_stack_t::fixedSet);
|
||||
const auto statGet = stack.ptr(&_stack_t::statGet);
|
||||
const auto statSet = stack.ptr(&_stack_t::statSet);
|
||||
const auto fileGet = stack.ptr(&_stack_t::fileGet);
|
||||
const auto fileSet = stack.ptr(&_stack_t::fileSet);
|
||||
vm::var<CellSaveDataCBResult> result;
|
||||
vm::var<CellSaveDataListGet> listGet;
|
||||
vm::var<CellSaveDataListSet> listSet;
|
||||
vm::var<CellSaveDataFixedSet> fixedSet;
|
||||
vm::var<CellSaveDataStatGet> statGet;
|
||||
vm::var<CellSaveDataStatSet> statSet;
|
||||
vm::var<CellSaveDataFileGet> fileGet;
|
||||
vm::var<CellSaveDataFileSet> fileSet;
|
||||
|
||||
// path of the specified user (00000001 by default)
|
||||
const std::string base_dir = fmt::format("/dev_hdd0/home/%08u/savedata/", userId ? userId : 1u);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -88,7 +88,7 @@ void cellSpursModulePutTrace(CellSpursTracePacket * packet, u32 dmaTagId) {
|
||||
|
||||
/// Check for execution right requests
|
||||
u32 cellSpursModulePollStatus(SPUThread & spu, u32 * status) {
|
||||
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.offset + 0x100);
|
||||
auto ctxt = vm::_ptr<SpursKernelContext>(spu.offset + 0x100);
|
||||
|
||||
spu.gpr[3]._u32[3] = 1;
|
||||
if (ctxt->spurs->flags1 & SF1_32_WORKLOADS) {
|
||||
@ -108,7 +108,7 @@ u32 cellSpursModulePollStatus(SPUThread & spu, u32 * status) {
|
||||
|
||||
/// Exit current workload
|
||||
void cellSpursModuleExit(SPUThread & spu) {
|
||||
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.offset + 0x100);
|
||||
auto ctxt = vm::_ptr<SpursKernelContext>(spu.offset + 0x100);
|
||||
spu.pc = ctxt->exitToKernelAddr - 4;
|
||||
throw SpursModuleExit();
|
||||
}
|
||||
@ -159,7 +159,7 @@ void spursHalt(SPUThread & spu) {
|
||||
|
||||
/// Select a workload to run
|
||||
bool spursKernel1SelectWorkload(SPUThread & spu) {
|
||||
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.offset + 0x100);
|
||||
auto ctxt = vm::_ptr<SpursKernelContext>(spu.offset + 0x100);
|
||||
|
||||
// The first and only argument to this function is a boolean that is set to false if the function
|
||||
// is called by the SPURS kernel and set to true if called by cellSpursModulePollStatus.
|
||||
@ -171,7 +171,7 @@ bool spursKernel1SelectWorkload(SPUThread & spu) {
|
||||
|
||||
vm::reservation_op(VM_CAST(ctxt->spurs.addr()), 128, [&]() {
|
||||
// lock the first 0x80 bytes of spurs
|
||||
auto spurs = ctxt->spurs.priv_ptr();
|
||||
auto spurs = ctxt->spurs.get_ptr_priv();
|
||||
|
||||
// Calculate the contention (number of SPUs used) for each workload
|
||||
u8 contention[CELL_SPURS_MAX_WORKLOAD];
|
||||
@ -305,7 +305,7 @@ bool spursKernel1SelectWorkload(SPUThread & spu) {
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(vm::get_ptr(spu.offset + 0x100), spurs, 128);
|
||||
std::memcpy(vm::base(spu.offset + 0x100), spurs, 128);
|
||||
});
|
||||
|
||||
u64 result = (u64)wklSelectedId << 32;
|
||||
@ -316,7 +316,7 @@ bool spursKernel1SelectWorkload(SPUThread & spu) {
|
||||
|
||||
/// Select a workload to run
|
||||
bool spursKernel2SelectWorkload(SPUThread & spu) {
|
||||
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.offset + 0x100);
|
||||
auto ctxt = vm::_ptr<SpursKernelContext>(spu.offset + 0x100);
|
||||
|
||||
// The first and only argument to this function is a boolean that is set to false if the function
|
||||
// is called by the SPURS kernel and set to true if called by cellSpursModulePollStatus.
|
||||
@ -328,7 +328,7 @@ bool spursKernel2SelectWorkload(SPUThread & spu) {
|
||||
|
||||
vm::reservation_op(VM_CAST(ctxt->spurs.addr()), 128, [&]() {
|
||||
// lock the first 0x80 bytes of spurs
|
||||
auto spurs = ctxt->spurs.priv_ptr();
|
||||
auto spurs = ctxt->spurs.get_ptr_priv();
|
||||
|
||||
// Calculate the contention (number of SPUs used) for each workload
|
||||
u8 contention[CELL_SPURS_MAX_WORKLOAD2];
|
||||
@ -452,7 +452,7 @@ bool spursKernel2SelectWorkload(SPUThread & spu) {
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(vm::get_ptr(spu.offset + 0x100), spurs, 128);
|
||||
std::memcpy(vm::base(spu.offset + 0x100), spurs, 128);
|
||||
});
|
||||
|
||||
u64 result = (u64)wklSelectedId << 32;
|
||||
@ -463,7 +463,7 @@ bool spursKernel2SelectWorkload(SPUThread & spu) {
|
||||
|
||||
/// SPURS kernel dispatch workload
|
||||
void spursKernelDispatchWorkload(SPUThread & spu, u64 widAndPollStatus) {
|
||||
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.offset + 0x100);
|
||||
auto ctxt = vm::_ptr<SpursKernelContext>(spu.offset + 0x100);
|
||||
auto isKernel2 = ctxt->spurs->flags1 & SF1_32_WORKLOADS ? true : false;
|
||||
|
||||
auto pollStatus = (u32)widAndPollStatus;
|
||||
@ -474,12 +474,12 @@ void spursKernelDispatchWorkload(SPUThread & spu, u64 widAndPollStatus) {
|
||||
wid < CELL_SPURS_MAX_WORKLOAD2 && isKernel2 ? &ctxt->spurs->wklInfo2[wid & 0xf] :
|
||||
&ctxt->spurs->wklInfoSysSrv;
|
||||
|
||||
memcpy(vm::get_ptr(spu.offset + 0x3FFE0), wklInfoOffset, 0x20);
|
||||
std::memcpy(vm::base(spu.offset + 0x3FFE0), wklInfoOffset, 0x20);
|
||||
|
||||
// Load the workload to LS
|
||||
auto wklInfo = vm::get_ptr<CellSpurs::WorkloadInfo>(spu.offset + 0x3FFE0);
|
||||
auto wklInfo = vm::_ptr<CellSpurs::WorkloadInfo>(spu.offset + 0x3FFE0);
|
||||
if (ctxt->wklCurrentAddr != wklInfo->addr) {
|
||||
switch (wklInfo->addr.addr().value()) {
|
||||
switch (wklInfo->addr.addr()) {
|
||||
case SPURS_IMG_ADDR_SYS_SRV_WORKLOAD:
|
||||
spu.RegisterHleFunction(0xA00, spursSysServiceEntry);
|
||||
break;
|
||||
@ -487,7 +487,7 @@ void spursKernelDispatchWorkload(SPUThread & spu, u64 widAndPollStatus) {
|
||||
spu.RegisterHleFunction(0xA00, spursTasksetEntry);
|
||||
break;
|
||||
default:
|
||||
memcpy(vm::get_ptr(spu.offset + 0xA00), wklInfo->addr.get_ptr(), wklInfo->size);
|
||||
std::memcpy(vm::base(spu.offset + 0xA00), wklInfo->addr.get_ptr(), wklInfo->size);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -511,7 +511,7 @@ void spursKernelDispatchWorkload(SPUThread & spu, u64 widAndPollStatus) {
|
||||
|
||||
/// SPURS kernel workload exit
|
||||
bool spursKernelWorkloadExit(SPUThread & spu) {
|
||||
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.offset + 0x100);
|
||||
auto ctxt = vm::_ptr<SpursKernelContext>(spu.offset + 0x100);
|
||||
auto isKernel2 = ctxt->spurs->flags1 & SF1_32_WORKLOADS ? true : false;
|
||||
|
||||
// Select next workload to run
|
||||
@ -533,7 +533,7 @@ bool spursKernelEntry(SPUThread & spu) {
|
||||
CHECK_EMU_STATUS;
|
||||
}
|
||||
|
||||
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.offset + 0x100);
|
||||
auto ctxt = vm::_ptr<SpursKernelContext>(spu.offset + 0x100);
|
||||
memset(ctxt, 0, sizeof(SpursKernelContext));
|
||||
|
||||
// Save arguments
|
||||
@ -579,7 +579,7 @@ bool spursKernelEntry(SPUThread & spu) {
|
||||
|
||||
/// Entry point of the system service
|
||||
bool spursSysServiceEntry(SPUThread & spu) {
|
||||
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.offset + spu.gpr[3]._u32[3]);
|
||||
auto ctxt = vm::_ptr<SpursKernelContext>(spu.offset + spu.gpr[3]._u32[3]);
|
||||
auto arg = spu.gpr[4]._u64[1];
|
||||
auto pollStatus = spu.gpr[5]._u32[3];
|
||||
|
||||
@ -607,8 +607,8 @@ void spursSysServiceIdleHandler(SPUThread & spu, SpursKernelContext * ctxt) {
|
||||
std::unique_lock<std::mutex> lock(spu.mutex, std::defer_lock);
|
||||
|
||||
while (true) {
|
||||
vm::reservation_acquire(vm::get_ptr(spu.offset + 0x100), VM_CAST(ctxt->spurs.addr()), 128);
|
||||
auto spurs = vm::get_ptr<CellSpurs>(spu.offset + 0x100);
|
||||
vm::reservation_acquire(vm::base(spu.offset + 0x100), VM_CAST(ctxt->spurs.addr()), 128);
|
||||
auto spurs = vm::_ptr<CellSpurs>(spu.offset + 0x100);
|
||||
|
||||
// Find the number of SPUs that are idling in this SPURS instance
|
||||
u32 nIdlingSpus = 0;
|
||||
@ -680,7 +680,7 @@ void spursSysServiceIdleHandler(SPUThread & spu, SpursKernelContext * ctxt) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (vm::reservation_update(VM_CAST(ctxt->spurs.addr()), vm::get_ptr(spu.offset + 0x100), 128) && (shouldExit || foundReadyWorkload)) {
|
||||
if (vm::reservation_update(VM_CAST(ctxt->spurs.addr()), vm::base(spu.offset + 0x100), 128) && (shouldExit || foundReadyWorkload)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -692,7 +692,7 @@ void spursSysServiceIdleHandler(SPUThread & spu, SpursKernelContext * ctxt) {
|
||||
|
||||
/// Main function for the system service
|
||||
void spursSysServiceMain(SPUThread & spu, u32 pollStatus) {
|
||||
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.offset + 0x100);
|
||||
auto ctxt = vm::_ptr<SpursKernelContext>(spu.offset + 0x100);
|
||||
|
||||
if (!ctxt->spurs.aligned()) {
|
||||
assert(!"spursSysServiceMain(): invalid spurs alignment");
|
||||
@ -703,10 +703,10 @@ void spursSysServiceMain(SPUThread & spu, u32 pollStatus) {
|
||||
if (ctxt->sysSrvInitialised == 0) {
|
||||
ctxt->sysSrvInitialised = 1;
|
||||
|
||||
vm::reservation_acquire(vm::get_ptr(spu.offset + 0x100), VM_CAST(ctxt->spurs.addr()), 128);
|
||||
vm::reservation_acquire(vm::base(spu.offset + 0x100), VM_CAST(ctxt->spurs.addr()), 128);
|
||||
|
||||
vm::reservation_op(VM_CAST(ctxt->spurs.addr() + offsetof(CellSpurs, wklState1)), 128, [&]() {
|
||||
auto spurs = ctxt->spurs.priv_ptr();
|
||||
auto spurs = ctxt->spurs.get_ptr_priv();
|
||||
|
||||
// Halt if already initialised
|
||||
if (spurs->sysSrvOnSpu & (1 << ctxt->spuNum)) {
|
||||
@ -716,7 +716,7 @@ void spursSysServiceMain(SPUThread & spu, u32 pollStatus) {
|
||||
|
||||
spurs->sysSrvOnSpu |= 1 << ctxt->spuNum;
|
||||
|
||||
memcpy(vm::get_ptr(spu.offset + 0x2D80), spurs->wklState1, 128);
|
||||
std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128);
|
||||
});
|
||||
|
||||
ctxt->traceBuffer = 0;
|
||||
@ -796,7 +796,7 @@ void spursSysServiceProcessRequests(SPUThread & spu, SpursKernelContext * ctxt)
|
||||
bool terminate = false;
|
||||
|
||||
vm::reservation_op(VM_CAST(ctxt->spurs.addr() + offsetof(CellSpurs, wklState1)), 128, [&]() {
|
||||
auto spurs = ctxt->spurs.priv_ptr();
|
||||
auto spurs = ctxt->spurs.get_ptr_priv();
|
||||
|
||||
// Terminate request
|
||||
if (spurs->sysSrvMsgTerminate & (1 << ctxt->spuNum)) {
|
||||
@ -815,7 +815,7 @@ void spursSysServiceProcessRequests(SPUThread & spu, SpursKernelContext * ctxt)
|
||||
updateTrace = true;
|
||||
}
|
||||
|
||||
memcpy(vm::get_ptr(spu.offset + 0x2D80), spurs->wklState1, 128);
|
||||
std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128);
|
||||
});
|
||||
|
||||
// Process update workload message
|
||||
@ -836,24 +836,24 @@ void spursSysServiceProcessRequests(SPUThread & spu, SpursKernelContext * ctxt)
|
||||
|
||||
/// Activate a workload
|
||||
void spursSysServiceActivateWorkload(SPUThread & spu, SpursKernelContext * ctxt) {
|
||||
auto spurs = vm::get_ptr<CellSpurs>(spu.offset + 0x100);
|
||||
memcpy(vm::get_ptr(spu.offset + 0x30000), vm::get_ptr(VM_CAST(ctxt->spurs.addr() + offsetof(CellSpurs, wklInfo1))), 0x200);
|
||||
auto spurs = vm::_ptr<CellSpurs>(spu.offset + 0x100);
|
||||
std::memcpy(vm::base(spu.offset + 0x30000), ctxt->spurs->wklInfo1, 0x200);
|
||||
if (spurs->flags1 & SF1_32_WORKLOADS) {
|
||||
memcpy(vm::get_ptr(spu.offset + 0x30200), vm::get_ptr(VM_CAST(ctxt->spurs.addr() + offsetof(CellSpurs, wklInfo2))), 0x200);
|
||||
std::memcpy(vm::base(spu.offset + 0x30200), ctxt->spurs->wklInfo2, 0x200);
|
||||
}
|
||||
|
||||
u32 wklShutdownBitSet = 0;
|
||||
ctxt->wklRunnable1 = 0;
|
||||
ctxt->wklRunnable2 = 0;
|
||||
for (u32 i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) {
|
||||
auto wklInfo1 = vm::get_ptr<CellSpurs::WorkloadInfo>(spu.offset + 0x30000);
|
||||
auto wklInfo1 = vm::_ptr<CellSpurs::WorkloadInfo>(spu.offset + 0x30000);
|
||||
|
||||
// Copy the priority of the workload for this SPU and its unique id to the LS
|
||||
ctxt->priority[i] = wklInfo1[i].priority[ctxt->spuNum] == 0 ? 0 : 0x10 - wklInfo1[i].priority[ctxt->spuNum];
|
||||
ctxt->wklUniqueId[i] = wklInfo1[i].uniqueId;
|
||||
|
||||
if (spurs->flags1 & SF1_32_WORKLOADS) {
|
||||
auto wklInfo2 = vm::get_ptr<CellSpurs::WorkloadInfo>(spu.offset + 0x30200);
|
||||
auto wklInfo2 = vm::_ptr<CellSpurs::WorkloadInfo>(spu.offset + 0x30200);
|
||||
|
||||
// Copy the priority of the workload for this SPU to the LS
|
||||
if (wklInfo2[i].priority[ctxt->spuNum]) {
|
||||
@ -863,7 +863,7 @@ void spursSysServiceActivateWorkload(SPUThread & spu, SpursKernelContext * ctxt)
|
||||
}
|
||||
|
||||
vm::reservation_op(VM_CAST(ctxt->spurs.addr() + offsetof(CellSpurs, wklState1)), 128, [&]() {
|
||||
auto spurs = ctxt->spurs.priv_ptr();
|
||||
auto spurs = ctxt->spurs.get_ptr_priv();
|
||||
|
||||
for (u32 i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) {
|
||||
// Update workload status and runnable flag based on the workload state
|
||||
@ -905,7 +905,7 @@ void spursSysServiceActivateWorkload(SPUThread & spu, SpursKernelContext * ctxt)
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(vm::get_ptr(spu.offset + 0x2D80), spurs->wklState1, 128);
|
||||
std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128);
|
||||
});
|
||||
|
||||
if (wklShutdownBitSet) {
|
||||
@ -920,7 +920,7 @@ void spursSysServiceUpdateShutdownCompletionEvents(SPUThread & spu, SpursKernelC
|
||||
u32 wklNotifyBitSet;
|
||||
u8 spuPort;
|
||||
vm::reservation_op(VM_CAST(ctxt->spurs.addr() + offsetof(CellSpurs, wklState1)), 128, [&]() {
|
||||
auto spurs = ctxt->spurs.priv_ptr();
|
||||
auto spurs = ctxt->spurs.get_ptr_priv();
|
||||
|
||||
wklNotifyBitSet = 0;
|
||||
spuPort = spurs->spuPort;;
|
||||
@ -940,7 +940,7 @@ void spursSysServiceUpdateShutdownCompletionEvents(SPUThread & spu, SpursKernelC
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(vm::get_ptr(spu.offset + 0x2D80), spurs->wklState1, 128);
|
||||
std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128);
|
||||
});
|
||||
|
||||
if (wklNotifyBitSet) {
|
||||
@ -962,7 +962,7 @@ void spursSysServiceTraceUpdate(SPUThread & spu, SpursKernelContext * ctxt, u32
|
||||
|
||||
u8 sysSrvMsgUpdateTrace;
|
||||
vm::reservation_op(VM_CAST(ctxt->spurs.addr() + offsetof(CellSpurs, wklState1)), 128, [&]() {
|
||||
auto spurs = ctxt->spurs.priv_ptr();
|
||||
auto spurs = ctxt->spurs.get_ptr_priv();
|
||||
auto& trace = spurs->sysSrvTrace.raw();
|
||||
|
||||
sysSrvMsgUpdateTrace = trace.sysSrvMsgUpdateTrace;
|
||||
@ -981,19 +981,19 @@ void spursSysServiceTraceUpdate(SPUThread & spu, SpursKernelContext * ctxt, u32
|
||||
notify = true;
|
||||
}
|
||||
|
||||
memcpy(vm::get_ptr(spu.offset + 0x2D80), spurs->wklState1, 128);
|
||||
std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128);
|
||||
});
|
||||
|
||||
// Get trace parameters from CellSpurs and store them in the LS
|
||||
if (((sysSrvMsgUpdateTrace & (1 << ctxt->spuNum)) != 0) || (arg3 != 0)) {
|
||||
vm::reservation_acquire(vm::get_ptr(spu.offset + 0x80), VM_CAST(ctxt->spurs.addr() + offsetof(CellSpurs, traceBuffer)), 128);
|
||||
auto spurs = vm::get_ptr<CellSpurs>(spu.offset + 0x80 - offsetof(CellSpurs, traceBuffer));
|
||||
vm::reservation_acquire(vm::base(spu.offset + 0x80), VM_CAST(ctxt->spurs.addr() + offsetof(CellSpurs, traceBuffer)), 128);
|
||||
auto spurs = vm::_ptr<CellSpurs>(spu.offset + 0x80 - offsetof(CellSpurs, traceBuffer));
|
||||
|
||||
if (ctxt->traceMsgCount != 0xFF || spurs->traceBuffer.addr() == 0) {
|
||||
spursSysServiceTraceSaveCount(spu, ctxt);
|
||||
} else {
|
||||
memcpy(vm::get_ptr(spu.offset + 0x2C00), vm::get_ptr(spurs->traceBuffer.addr() & -0x4), 0x80);
|
||||
auto traceBuffer = vm::get_ptr<CellSpursTraceInfo>(spu.offset + 0x2C00);
|
||||
std::memcpy(vm::base(spu.offset + 0x2C00), vm::base(spurs->traceBuffer.addr() & -0x4), 0x80);
|
||||
auto traceBuffer = vm::_ptr<CellSpursTraceInfo>(spu.offset + 0x2C00);
|
||||
ctxt->traceMsgCount = traceBuffer->count[ctxt->spuNum];
|
||||
}
|
||||
|
||||
@ -1005,7 +1005,7 @@ void spursSysServiceTraceUpdate(SPUThread & spu, SpursKernelContext * ctxt, u32
|
||||
}
|
||||
|
||||
if (notify) {
|
||||
auto spurs = vm::get_ptr<CellSpurs>(spu.offset + 0x2D80 - offsetof(CellSpurs, wklState1));
|
||||
auto spurs = vm::_ptr<CellSpurs>(spu.offset + 0x2D80 - offsetof(CellSpurs, wklState1));
|
||||
sys_spu_thread_send_event(spu, spurs->spuPort, 2, 0);
|
||||
}
|
||||
}
|
||||
@ -1017,7 +1017,7 @@ void spursSysServiceCleanupAfterSystemWorkload(SPUThread & spu, SpursKernelConte
|
||||
bool do_return = false;
|
||||
|
||||
vm::reservation_op(VM_CAST(ctxt->spurs.addr() + offsetof(CellSpurs, wklState1)), 128, [&]() {
|
||||
auto spurs = ctxt->spurs.priv_ptr();
|
||||
auto spurs = ctxt->spurs.get_ptr_priv();
|
||||
|
||||
if (spurs->sysSrvPreemptWklId[ctxt->spuNum] == 0xFF) {
|
||||
do_return = true;
|
||||
@ -1027,7 +1027,7 @@ void spursSysServiceCleanupAfterSystemWorkload(SPUThread & spu, SpursKernelConte
|
||||
wklId = spurs->sysSrvPreemptWklId[ctxt->spuNum];
|
||||
spurs->sysSrvPreemptWklId[ctxt->spuNum] = 0xFF;
|
||||
|
||||
memcpy(vm::get_ptr(spu.offset + 0x2D80), spurs->wklState1, 128);
|
||||
std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128);
|
||||
});
|
||||
|
||||
if (do_return) return;
|
||||
@ -1035,7 +1035,7 @@ void spursSysServiceCleanupAfterSystemWorkload(SPUThread & spu, SpursKernelConte
|
||||
spursSysServiceActivateWorkload(spu, ctxt);
|
||||
|
||||
vm::reservation_op(VM_CAST(ctxt->spurs.addr()), 128, [&]() {
|
||||
auto spurs = ctxt->spurs.priv_ptr();
|
||||
auto spurs = ctxt->spurs.get_ptr_priv();
|
||||
|
||||
if (wklId >= CELL_SPURS_MAX_WORKLOAD) {
|
||||
spurs->wklCurrentContention[wklId & 0x0F] -= 0x10;
|
||||
@ -1045,7 +1045,7 @@ void spursSysServiceCleanupAfterSystemWorkload(SPUThread & spu, SpursKernelConte
|
||||
spurs->wklIdleSpuCountOrReadyCount2[wklId & 0x0F].raw() -= 1;
|
||||
}
|
||||
|
||||
memcpy(vm::get_ptr(spu.offset + 0x100), spurs, 128);
|
||||
std::memcpy(vm::base(spu.offset + 0x100), spurs, 128);
|
||||
});
|
||||
|
||||
// Set the current workload id to the id of the pre-empted workload since cellSpursModulePutTrace
|
||||
@ -1080,8 +1080,8 @@ enum SpursTasksetRequest {
|
||||
|
||||
/// Taskset PM entry point
|
||||
bool spursTasksetEntry(SPUThread & spu) {
|
||||
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||
auto kernelCtxt = vm::get_ptr<SpursKernelContext>(spu.offset + spu.gpr[3]._u32[3]);
|
||||
auto ctxt = vm::_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||
auto kernelCtxt = vm::_ptr<SpursKernelContext>(spu.offset + spu.gpr[3]._u32[3]);
|
||||
|
||||
auto arg = spu.gpr[4]._u64[1];
|
||||
auto pollStatus = spu.gpr[5]._u32[3];
|
||||
@ -1117,7 +1117,7 @@ bool spursTasksetEntry(SPUThread & spu) {
|
||||
|
||||
/// Entry point into the Taskset PM for task syscalls
|
||||
bool spursTasksetSyscallEntry(SPUThread & spu) {
|
||||
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||
auto ctxt = vm::_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||
|
||||
try {
|
||||
// Save task context
|
||||
@ -1145,7 +1145,7 @@ bool spursTasksetSyscallEntry(SPUThread & spu) {
|
||||
|
||||
/// Resume a task
|
||||
void spursTasksetResumeTask(SPUThread & spu) {
|
||||
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||
auto ctxt = vm::_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||
|
||||
// Restore task context
|
||||
spu.gpr[0] = ctxt->savedContextLr;
|
||||
@ -1159,8 +1159,8 @@ void spursTasksetResumeTask(SPUThread & spu) {
|
||||
|
||||
/// Start a task
|
||||
void spursTasksetStartTask(SPUThread & spu, CellSpursTaskArgument & taskArgs) {
|
||||
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||
auto taskset = vm::get_ptr<CellSpursTaskset>(spu.offset + 0x2700);
|
||||
auto ctxt = vm::_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||
auto taskset = vm::_ptr<CellSpursTaskset>(spu.offset + 0x2700);
|
||||
|
||||
spu.gpr[2].clear();
|
||||
spu.gpr[3] = v128::from64r(taskArgs._u64[0], taskArgs._u64[1]);
|
||||
@ -1175,13 +1175,13 @@ void spursTasksetStartTask(SPUThread & spu, CellSpursTaskArgument & taskArgs) {
|
||||
|
||||
/// Process a request and update the state of the taskset
|
||||
s32 spursTasksetProcessRequest(SPUThread & spu, s32 request, u32 * taskId, u32 * isWaiting) {
|
||||
auto kernelCtxt = vm::get_ptr<SpursKernelContext>(spu.offset + 0x100);
|
||||
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||
auto kernelCtxt = vm::_ptr<SpursKernelContext>(spu.offset + 0x100);
|
||||
auto ctxt = vm::_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||
|
||||
s32 rc = CELL_OK;
|
||||
s32 numNewlyReadyTasks;
|
||||
vm::reservation_op(VM_CAST(ctxt->taskset.addr()), 128, [&]() {
|
||||
auto taskset = ctxt->taskset.priv_ptr();
|
||||
auto taskset = ctxt->taskset.get_ptr_priv();
|
||||
|
||||
// Verify taskset state is valid
|
||||
be_t<v128> _0(v128::from32(0));
|
||||
@ -1315,12 +1315,12 @@ s32 spursTasksetProcessRequest(SPUThread & spu, s32 request, u32 * taskId, u32 *
|
||||
taskset->signalled = signalled;
|
||||
taskset->ready = ready;
|
||||
|
||||
memcpy(vm::get_ptr(spu.offset + 0x2700), taskset, 128);
|
||||
std::memcpy(vm::base(spu.offset + 0x2700), taskset, 128);
|
||||
});
|
||||
|
||||
// Increment the ready count of the workload by the number of tasks that have become ready
|
||||
vm::reservation_op(VM_CAST(kernelCtxt->spurs.addr()), 128, [&]() {
|
||||
auto spurs = kernelCtxt->spurs.priv_ptr();
|
||||
auto spurs = kernelCtxt->spurs.get_ptr_priv();
|
||||
|
||||
s32 readyCount = kernelCtxt->wklCurrentId < CELL_SPURS_MAX_WORKLOAD ? spurs->wklReadyCount1[kernelCtxt->wklCurrentId].load() : spurs->wklIdleSpuCountOrReadyCount2[kernelCtxt->wklCurrentId & 0x0F].load();
|
||||
readyCount += numNewlyReadyTasks;
|
||||
@ -1332,7 +1332,7 @@ s32 spursTasksetProcessRequest(SPUThread & spu, s32 request, u32 * taskId, u32 *
|
||||
spurs->wklIdleSpuCountOrReadyCount2[kernelCtxt->wklCurrentId & 0x0F] = readyCount;
|
||||
}
|
||||
|
||||
memcpy(vm::get_ptr(spu.offset + 0x100), spurs, 128);
|
||||
std::memcpy(vm::base(spu.offset + 0x100), spurs, 128);
|
||||
});
|
||||
|
||||
return rc;
|
||||
@ -1359,7 +1359,7 @@ bool spursTasksetPollStatus(SPUThread & spu) {
|
||||
|
||||
/// Exit the Taskset PM
|
||||
void spursTasksetExit(SPUThread & spu) {
|
||||
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||
auto ctxt = vm::_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||
|
||||
// Trace - STOP
|
||||
CellSpursTracePacket pkt;
|
||||
@ -1379,9 +1379,9 @@ void spursTasksetExit(SPUThread & spu) {
|
||||
|
||||
/// Invoked when a task exits
|
||||
void spursTasksetOnTaskExit(SPUThread & spu, u64 addr, u32 taskId, s32 exitCode, u64 args) {
|
||||
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||
auto ctxt = vm::_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||
|
||||
memcpy(vm::get_ptr(spu.offset + 0x10000), vm::get_ptr(addr & -0x80), (addr & 0x7F) << 11);
|
||||
std::memcpy(vm::base(spu.offset + 0x10000), vm::base(addr & -0x80), (addr & 0x7F) << 11);
|
||||
|
||||
spu.gpr[3]._u64[1] = ctxt->taskset.addr();
|
||||
spu.gpr[4]._u32[3] = taskId;
|
||||
@ -1392,8 +1392,8 @@ void spursTasksetOnTaskExit(SPUThread & spu, u64 addr, u32 taskId, s32 exitCode,
|
||||
|
||||
/// Save the context of a task
|
||||
s32 spursTasketSaveTaskContext(SPUThread & spu) {
|
||||
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||
auto taskInfo = vm::get_ptr<CellSpursTaskset::TaskInfo>(spu.offset + 0x2780);
|
||||
auto ctxt = vm::_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||
auto taskInfo = vm::_ptr<CellSpursTaskset::TaskInfo>(spu.offset + 0x2780);
|
||||
|
||||
//spursDmaWaitForCompletion(spu, 0xFFFFFFFF);
|
||||
|
||||
@ -1430,13 +1430,13 @@ s32 spursTasketSaveTaskContext(SPUThread & spu) {
|
||||
|
||||
// Store the processor context
|
||||
const u32 contextSaveStorage = VM_CAST(taskInfo->context_save_storage_and_alloc_ls_blocks & -0x80);
|
||||
memcpy(vm::get_ptr(contextSaveStorage), vm::get_ptr(spu.offset + 0x2C80), 0x380);
|
||||
std::memcpy(vm::base(contextSaveStorage), vm::base(spu.offset + 0x2C80), 0x380);
|
||||
|
||||
// Save LS context
|
||||
for (auto i = 6; i < 128; i++) {
|
||||
if (ls_pattern._bit[i]) {
|
||||
// TODO: Combine DMA requests for consecutive blocks into a single request
|
||||
memcpy(vm::get_ptr(contextSaveStorage + 0x400 + ((i - 6) << 11)), vm::get_ptr(spu.offset + CELL_SPURS_TASK_TOP + ((i - 6) << 11)), 0x800);
|
||||
std::memcpy(vm::base(contextSaveStorage + 0x400 + ((i - 6) << 11)), vm::base(spu.offset + CELL_SPURS_TASK_TOP + ((i - 6) << 11)), 0x800);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1446,8 +1446,8 @@ s32 spursTasketSaveTaskContext(SPUThread & spu) {
|
||||
|
||||
/// Taskset dispatcher
|
||||
void spursTasksetDispatch(SPUThread & spu) {
|
||||
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||
auto taskset = vm::get_ptr<CellSpursTaskset>(spu.offset + 0x2700);
|
||||
auto ctxt = vm::_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||
auto taskset = vm::_ptr<CellSpursTaskset>(spu.offset + 0x2700);
|
||||
|
||||
u32 taskId;
|
||||
u32 isWaiting;
|
||||
@ -1460,10 +1460,10 @@ void spursTasksetDispatch(SPUThread & spu) {
|
||||
ctxt->taskId = taskId;
|
||||
|
||||
// DMA in the task info for the selected task
|
||||
memcpy(vm::get_ptr(spu.offset + 0x2780), &ctxt->taskset->task_info[taskId], sizeof(CellSpursTaskset::TaskInfo));
|
||||
auto taskInfo = vm::get_ptr<CellSpursTaskset::TaskInfo>(spu.offset + 0x2780);
|
||||
std::memcpy(vm::base(spu.offset + 0x2780), &ctxt->taskset->task_info[taskId], sizeof(CellSpursTaskset::TaskInfo));
|
||||
auto taskInfo = vm::_ptr<CellSpursTaskset::TaskInfo>(spu.offset + 0x2780);
|
||||
auto elfAddr = taskInfo->elf.addr().value();
|
||||
taskInfo->elf.set(taskInfo->elf.addr() & 0xFFFFFFFFFFFFFFF8ull);
|
||||
taskInfo->elf.set(taskInfo->elf.addr() & 0xFFFFFFFFFFFFFFF8);
|
||||
|
||||
// Trace - Task: Incident=dispatch
|
||||
CellSpursTracePacket pkt;
|
||||
@ -1475,7 +1475,7 @@ void spursTasksetDispatch(SPUThread & spu) {
|
||||
|
||||
if (isWaiting == 0) {
|
||||
// If we reach here it means that the task is being started and not being resumed
|
||||
memset(vm::get_ptr<void>(spu.offset + CELL_SPURS_TASK_TOP), 0, CELL_SPURS_TASK_BOTTOM - CELL_SPURS_TASK_TOP);
|
||||
std::memset(vm::base(spu.offset + CELL_SPURS_TASK_TOP), 0, CELL_SPURS_TASK_BOTTOM - CELL_SPURS_TASK_TOP);
|
||||
ctxt->guidAddr = CELL_SPURS_TASK_TOP;
|
||||
|
||||
u32 entryPoint;
|
||||
@ -1495,7 +1495,7 @@ void spursTasksetDispatch(SPUThread & spu) {
|
||||
ctxt->x2FD4 = elfAddr & 5; // TODO: Figure this out
|
||||
|
||||
if ((elfAddr & 5) == 1) {
|
||||
memcpy(vm::get_ptr(spu.offset + 0x2FC0), &((CellSpursTaskset2*)(ctxt->taskset.get_ptr()))->task_exit_code[taskId], 0x10);
|
||||
std::memcpy(vm::base(spu.offset + 0x2FC0), &((CellSpursTaskset2*)(ctxt->taskset.get_ptr()))->task_exit_code[taskId], 0x10);
|
||||
}
|
||||
|
||||
// Trace - GUID
|
||||
@ -1513,7 +1513,7 @@ void spursTasksetDispatch(SPUThread & spu) {
|
||||
spursTasksetStartTask(spu, taskInfo->args);
|
||||
} else {
|
||||
if (taskset->enable_clear_ls) {
|
||||
memset(vm::get_ptr<void>(spu.offset + CELL_SPURS_TASK_TOP), 0, CELL_SPURS_TASK_BOTTOM - CELL_SPURS_TASK_TOP);
|
||||
std::memset(vm::base(spu.offset + CELL_SPURS_TASK_TOP), 0, CELL_SPURS_TASK_BOTTOM - CELL_SPURS_TASK_TOP);
|
||||
}
|
||||
|
||||
// If the entire LS is saved then there is no need to load the ELF as it will be be saved in the context save area as well
|
||||
@ -1529,11 +1529,11 @@ void spursTasksetDispatch(SPUThread & spu) {
|
||||
|
||||
// Load saved context from main memory to LS
|
||||
const u32 contextSaveStorage = VM_CAST(taskInfo->context_save_storage_and_alloc_ls_blocks & -0x80);
|
||||
memcpy(vm::get_ptr(spu.offset + 0x2C80), vm::get_ptr(contextSaveStorage), 0x380);
|
||||
std::memcpy(vm::base(spu.offset + 0x2C80), vm::base(contextSaveStorage), 0x380);
|
||||
for (auto i = 6; i < 128; i++) {
|
||||
if (ls_pattern._bit[i]) {
|
||||
// TODO: Combine DMA requests for consecutive blocks into a single request
|
||||
memcpy(vm::get_ptr(spu.offset + CELL_SPURS_TASK_TOP + ((i - 6) << 11)), vm::get_ptr(contextSaveStorage + 0x400 + ((i - 6) << 11)), 0x800);
|
||||
std::memcpy(vm::base(spu.offset + CELL_SPURS_TASK_TOP + ((i - 6) << 11)), vm::base(contextSaveStorage + 0x400 + ((i - 6) << 11)), 0x800);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1563,8 +1563,8 @@ void spursTasksetDispatch(SPUThread & spu) {
|
||||
|
||||
/// Process a syscall request
|
||||
s32 spursTasksetProcessSyscall(SPUThread & spu, u32 syscallNum, u32 args) {
|
||||
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||
auto taskset = vm::get_ptr<CellSpursTaskset>(spu.offset + 0x2700);
|
||||
auto ctxt = vm::_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||
auto taskset = vm::_ptr<CellSpursTaskset>(spu.offset + 0x2700);
|
||||
|
||||
// If the 0x10 bit is set in syscallNum then its the 2nd version of the
|
||||
// syscall (e.g. cellSpursYield2 instead of cellSpursYield) and so don't wait
|
||||
@ -1642,7 +1642,7 @@ s32 spursTasksetProcessSyscall(SPUThread & spu, u32 syscallNum, u32 args) {
|
||||
cellSpursModulePutTrace(&pkt, ctxt->dmaTagId);
|
||||
|
||||
// Clear the GUID of the task
|
||||
memset(vm::get_ptr<void>(spu.offset + ctxt->guidAddr), 0, 0x10);
|
||||
std::memset(vm::base(spu.offset + ctxt->guidAddr), 0, 0x10);
|
||||
|
||||
if (spursTasksetPollStatus(spu)) {
|
||||
spursTasksetExit(spu);
|
||||
@ -1656,8 +1656,8 @@ s32 spursTasksetProcessSyscall(SPUThread & spu, u32 syscallNum, u32 args) {
|
||||
|
||||
/// Initialise the Taskset PM
|
||||
void spursTasksetInit(SPUThread & spu, u32 pollStatus) {
|
||||
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||
auto kernelCtxt = vm::get_ptr<SpursKernelContext>(spu.offset + 0x100);
|
||||
auto ctxt = vm::_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||
auto kernelCtxt = vm::_ptr<SpursKernelContext>(spu.offset + 0x100);
|
||||
|
||||
kernelCtxt->moduleId[0] = 'T';
|
||||
kernelCtxt->moduleId[1] = 'K';
|
||||
|
@ -25,7 +25,7 @@ s32 cellSyncMutexInitialize(vm::ptr<CellSyncMutex> mutex)
|
||||
return CELL_SYNC_ERROR_ALIGN;
|
||||
}
|
||||
|
||||
mutex->exchange({});
|
||||
mutex->ctrl.exchange({ 0, 0 });
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -45,10 +45,10 @@ s32 cellSyncMutexLock(PPUThread& ppu, vm::ptr<CellSyncMutex> mutex)
|
||||
}
|
||||
|
||||
// increase acq value and remember its old value
|
||||
const auto order = mutex->atomic_op(&sync_mutex_t::acquire);
|
||||
const auto order = mutex->ctrl.atomic_op(_sync::mutex::acquire);
|
||||
|
||||
// wait until rel value is equal to old acq value
|
||||
vm::wait_op(ppu, mutex.addr(), 4, WRAP_EXPR(mutex->load().rel == order));
|
||||
vm::wait_op(ppu, mutex.addr(), 4, WRAP_EXPR(mutex->ctrl.load().rel == order));
|
||||
|
||||
_mm_mfence();
|
||||
|
||||
@ -69,7 +69,7 @@ s32 cellSyncMutexTryLock(vm::ptr<CellSyncMutex> mutex)
|
||||
return CELL_SYNC_ERROR_ALIGN;
|
||||
}
|
||||
|
||||
if (!mutex->atomic_op(&sync_mutex_t::try_lock))
|
||||
if (!mutex->ctrl.atomic_op(_sync::mutex::try_lock))
|
||||
{
|
||||
return CELL_SYNC_ERROR_BUSY;
|
||||
}
|
||||
@ -91,9 +91,9 @@ s32 cellSyncMutexUnlock(vm::ptr<CellSyncMutex> mutex)
|
||||
return CELL_SYNC_ERROR_ALIGN;
|
||||
}
|
||||
|
||||
mutex->atomic_op(&sync_mutex_t::unlock);
|
||||
mutex->ctrl.atomic_op(_sync::mutex::unlock);
|
||||
|
||||
vm::notify_at(mutex.addr(), 4);
|
||||
vm::notify_at(mutex);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -118,7 +118,7 @@ s32 cellSyncBarrierInitialize(vm::ptr<CellSyncBarrier> barrier, u16 total_count)
|
||||
}
|
||||
|
||||
// clear current value, write total_count and sync
|
||||
barrier->exchange({ 0, total_count });
|
||||
barrier->ctrl.exchange({ 0, total_count });
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -137,9 +137,9 @@ s32 cellSyncBarrierNotify(PPUThread& ppu, vm::ptr<CellSyncBarrier> barrier)
|
||||
return CELL_SYNC_ERROR_ALIGN;
|
||||
}
|
||||
|
||||
vm::wait_op(ppu, barrier.addr(), 4, WRAP_EXPR(barrier->atomic_op(&sync_barrier_t::try_notify)));
|
||||
vm::wait_op(ppu, barrier.addr(), 4, WRAP_EXPR(barrier->ctrl.atomic_op(_sync::barrier::try_notify)));
|
||||
|
||||
vm::notify_at(barrier.addr(), 4);
|
||||
vm::notify_at(barrier);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -160,12 +160,12 @@ s32 cellSyncBarrierTryNotify(vm::ptr<CellSyncBarrier> barrier)
|
||||
|
||||
_mm_mfence();
|
||||
|
||||
if (!barrier->atomic_op(&sync_barrier_t::try_notify))
|
||||
if (!barrier->ctrl.atomic_op(_sync::barrier::try_notify))
|
||||
{
|
||||
return CELL_SYNC_ERROR_BUSY;
|
||||
}
|
||||
|
||||
vm::notify_at(barrier.addr(), 4);
|
||||
vm::notify_at(barrier);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -186,9 +186,9 @@ s32 cellSyncBarrierWait(PPUThread& ppu, vm::ptr<CellSyncBarrier> barrier)
|
||||
|
||||
_mm_mfence();
|
||||
|
||||
vm::wait_op(ppu, barrier.addr(), 4, WRAP_EXPR(barrier->atomic_op(&sync_barrier_t::try_wait)));
|
||||
vm::wait_op(ppu, barrier.addr(), 4, WRAP_EXPR(barrier->ctrl.atomic_op(_sync::barrier::try_wait)));
|
||||
|
||||
vm::notify_at(barrier.addr(), 4);
|
||||
vm::notify_at(barrier);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -209,12 +209,12 @@ s32 cellSyncBarrierTryWait(vm::ptr<CellSyncBarrier> barrier)
|
||||
|
||||
_mm_mfence();
|
||||
|
||||
if (!barrier->atomic_op(&sync_barrier_t::try_wait))
|
||||
if (!barrier->ctrl.atomic_op(_sync::barrier::try_wait))
|
||||
{
|
||||
return CELL_SYNC_ERROR_BUSY;
|
||||
}
|
||||
|
||||
vm::notify_at(barrier.addr(), 4);
|
||||
vm::notify_at(barrier);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -239,7 +239,7 @@ s32 cellSyncRwmInitialize(vm::ptr<CellSyncRwm> rwm, vm::ptr<void> buffer, u32 bu
|
||||
}
|
||||
|
||||
// clear readers and writers, write buffer_size, buffer addr and sync
|
||||
rwm->ctrl.store({});
|
||||
rwm->ctrl.store({ 0, 0 });
|
||||
rwm->size = buffer_size;
|
||||
rwm->buffer = buffer;
|
||||
|
||||
@ -263,18 +263,18 @@ s32 cellSyncRwmRead(PPUThread& ppu, vm::ptr<CellSyncRwm> rwm, vm::ptr<void> buff
|
||||
}
|
||||
|
||||
// wait until `writers` is zero, increase `readers`
|
||||
vm::wait_op(ppu, rwm.addr(), 4, WRAP_EXPR(rwm->ctrl.atomic_op(&sync_rwm_t::try_read_begin)));
|
||||
vm::wait_op(ppu, rwm.addr(), 8, WRAP_EXPR(rwm->ctrl.atomic_op(_sync::rwlock::try_read_begin)));
|
||||
|
||||
// copy data to buffer
|
||||
std::memcpy(buffer.get_ptr(), rwm->buffer.get_ptr(), rwm->size);
|
||||
|
||||
// decrease `readers`, return error if already zero
|
||||
if (!rwm->ctrl.atomic_op(&sync_rwm_t::try_read_end))
|
||||
if (!rwm->ctrl.atomic_op(_sync::rwlock::try_read_end))
|
||||
{
|
||||
return CELL_SYNC_ERROR_ABORT;
|
||||
}
|
||||
|
||||
vm::notify_at(rwm.addr(), 4);
|
||||
vm::notify_at(rwm.ptr(&CellSyncRwm::ctrl));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -294,7 +294,7 @@ s32 cellSyncRwmTryRead(vm::ptr<CellSyncRwm> rwm, vm::ptr<void> buffer)
|
||||
}
|
||||
|
||||
// increase `readers` if `writers` is zero
|
||||
if (!rwm->ctrl.atomic_op(&sync_rwm_t::try_read_begin))
|
||||
if (!rwm->ctrl.atomic_op(_sync::rwlock::try_read_begin))
|
||||
{
|
||||
return CELL_SYNC_ERROR_BUSY;
|
||||
}
|
||||
@ -303,12 +303,12 @@ s32 cellSyncRwmTryRead(vm::ptr<CellSyncRwm> rwm, vm::ptr<void> buffer)
|
||||
std::memcpy(buffer.get_ptr(), rwm->buffer.get_ptr(), rwm->size);
|
||||
|
||||
// decrease `readers`, return error if already zero
|
||||
if (!rwm->ctrl.atomic_op(&sync_rwm_t::try_read_end))
|
||||
if (!rwm->ctrl.atomic_op(_sync::rwlock::try_read_end))
|
||||
{
|
||||
return CELL_SYNC_ERROR_ABORT;
|
||||
}
|
||||
|
||||
vm::notify_at(rwm.addr(), 4);
|
||||
vm::notify_at(rwm.ptr(&CellSyncRwm::ctrl));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -328,18 +328,18 @@ s32 cellSyncRwmWrite(PPUThread& ppu, vm::ptr<CellSyncRwm> rwm, vm::cptr<void> bu
|
||||
}
|
||||
|
||||
// wait until `writers` is zero, set to 1
|
||||
vm::wait_op(ppu, rwm.addr(), 4, WRAP_EXPR(rwm->ctrl.atomic_op(&sync_rwm_t::try_write_begin)));
|
||||
vm::wait_op(ppu, rwm.addr(), 8, WRAP_EXPR(rwm->ctrl.atomic_op(_sync::rwlock::try_write_begin)));
|
||||
|
||||
// wait until `readers` is zero
|
||||
vm::wait_op(ppu, rwm.addr(), 4, WRAP_EXPR(!rwm->ctrl.load().readers));
|
||||
vm::wait_op(ppu, rwm.addr(), 8, WRAP_EXPR(!rwm->ctrl.load().readers));
|
||||
|
||||
// copy data from buffer
|
||||
std::memcpy(rwm->buffer.get_ptr(), buffer.get_ptr(), rwm->size);
|
||||
|
||||
// sync and clear `readers` and `writers`
|
||||
rwm->ctrl.exchange({});
|
||||
rwm->ctrl.exchange({ 0, 0 });
|
||||
|
||||
vm::notify_at(rwm.addr(), 4);
|
||||
vm::notify_at(rwm.ptr(&CellSyncRwm::ctrl));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -368,9 +368,9 @@ s32 cellSyncRwmTryWrite(vm::ptr<CellSyncRwm> rwm, vm::cptr<void> buffer)
|
||||
std::memcpy(rwm->buffer.get_ptr(), buffer.get_ptr(), rwm->size);
|
||||
|
||||
// sync and clear `readers` and `writers`
|
||||
rwm->ctrl.exchange({});
|
||||
rwm->ctrl.exchange({ 0, 0 });
|
||||
|
||||
vm::notify_at(rwm.addr(), 4);
|
||||
vm::notify_at(rwm.ptr(&CellSyncRwm::ctrl));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -400,7 +400,7 @@ s32 cellSyncQueueInitialize(vm::ptr<CellSyncQueue> queue, vm::ptr<u8> buffer, u3
|
||||
}
|
||||
|
||||
// clear sync var, write size, depth, buffer addr and sync
|
||||
queue->ctrl.store({});
|
||||
queue->ctrl.store({ 0, 0 });
|
||||
queue->size = size;
|
||||
queue->depth = depth;
|
||||
queue->buffer = buffer;
|
||||
@ -428,15 +428,15 @@ s32 cellSyncQueuePush(PPUThread& ppu, vm::ptr<CellSyncQueue> queue, vm::cptr<voi
|
||||
|
||||
u32 position;
|
||||
|
||||
vm::wait_op(ppu, queue.addr(), 8, WRAP_EXPR(queue->ctrl.atomic_op(&sync_queue_t::try_push_begin, depth, position)));
|
||||
vm::wait_op(ppu, queue.addr(), 8, WRAP_EXPR(queue->ctrl.atomic_op(_sync::queue::try_push_begin, depth, position)));
|
||||
|
||||
// copy data from the buffer at the position
|
||||
std::memcpy(&queue->buffer[position * queue->size], buffer.get_ptr(), queue->size);
|
||||
|
||||
// clear 5th byte
|
||||
queue->ctrl &= { 0xffffffff, 0x00ffffff };
|
||||
// ...push_end
|
||||
queue->ctrl._and_not({ 0, 0xff000000 });
|
||||
|
||||
vm::notify_at(queue.addr(), 8);
|
||||
vm::notify_at(queue.ptr(&CellSyncQueue::ctrl));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -459,7 +459,7 @@ s32 cellSyncQueueTryPush(vm::ptr<CellSyncQueue> queue, vm::cptr<void> buffer)
|
||||
|
||||
u32 position;
|
||||
|
||||
if (!queue->ctrl.atomic_op(&sync_queue_t::try_push_begin, depth, position))
|
||||
if (!queue->ctrl.atomic_op(_sync::queue::try_push_begin, depth, position))
|
||||
{
|
||||
return CELL_SYNC_ERROR_BUSY;
|
||||
}
|
||||
@ -467,10 +467,10 @@ s32 cellSyncQueueTryPush(vm::ptr<CellSyncQueue> queue, vm::cptr<void> buffer)
|
||||
// copy data from the buffer at the position
|
||||
std::memcpy(&queue->buffer[position * queue->size], buffer.get_ptr(), queue->size);
|
||||
|
||||
// clear 5th byte
|
||||
queue->ctrl &= { 0xffffffff, 0x00ffffff };
|
||||
// ...push_end
|
||||
queue->ctrl._and_not({ 0, 0xff000000 });
|
||||
|
||||
vm::notify_at(queue.addr(), 8);
|
||||
vm::notify_at(queue.ptr(&CellSyncQueue::ctrl));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -493,15 +493,15 @@ s32 cellSyncQueuePop(PPUThread& ppu, vm::ptr<CellSyncQueue> queue, vm::ptr<void>
|
||||
|
||||
u32 position;
|
||||
|
||||
vm::wait_op(ppu, queue.addr(), 8, WRAP_EXPR(queue->ctrl.atomic_op(&sync_queue_t::try_pop_begin, depth, position)));
|
||||
vm::wait_op(ppu, queue.addr(), 8, WRAP_EXPR(queue->ctrl.atomic_op(_sync::queue::try_pop_begin, depth, position)));
|
||||
|
||||
// copy data at the position to the buffer
|
||||
std::memcpy(buffer.get_ptr(), &queue->buffer[position * queue->size], queue->size);
|
||||
std::memcpy(buffer.get_ptr(), &queue->buffer[position % depth * queue->size], queue->size);
|
||||
|
||||
// clear first byte
|
||||
queue->ctrl &= { 0x00ffffff, 0xffffffffu };
|
||||
// ...pop_end
|
||||
queue->ctrl._and_not({ 0xff000000, 0 });
|
||||
|
||||
vm::notify_at(queue.addr(), 8);
|
||||
vm::notify_at(queue.ptr(&CellSyncQueue::ctrl));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -524,18 +524,18 @@ s32 cellSyncQueueTryPop(vm::ptr<CellSyncQueue> queue, vm::ptr<void> buffer)
|
||||
|
||||
u32 position;
|
||||
|
||||
if (!queue->ctrl.atomic_op(&sync_queue_t::try_pop_begin, depth, position))
|
||||
if (!queue->ctrl.atomic_op(_sync::queue::try_pop_begin, depth, position))
|
||||
{
|
||||
return CELL_SYNC_ERROR_BUSY;
|
||||
}
|
||||
|
||||
// copy data at the position to the buffer
|
||||
std::memcpy(buffer.get_ptr(), &queue->buffer[position * queue->size], queue->size);
|
||||
std::memcpy(buffer.get_ptr(), &queue->buffer[position % depth * queue->size], queue->size);
|
||||
|
||||
// clear first byte
|
||||
queue->ctrl &= { 0x00ffffff, 0xffffffffu };
|
||||
// ...pop_end
|
||||
queue->ctrl._and_not({ 0xff000000, 0 });
|
||||
|
||||
vm::notify_at(queue.addr(), 8);
|
||||
vm::notify_at(queue.ptr(&CellSyncQueue::ctrl));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -558,15 +558,15 @@ s32 cellSyncQueuePeek(PPUThread& ppu, vm::ptr<CellSyncQueue> queue, vm::ptr<void
|
||||
|
||||
u32 position;
|
||||
|
||||
vm::wait_op(ppu, queue.addr(), 8, WRAP_EXPR(queue->ctrl.atomic_op(&sync_queue_t::try_peek_begin, depth, position)));
|
||||
vm::wait_op(ppu, queue.addr(), 8, WRAP_EXPR(queue->ctrl.atomic_op(_sync::queue::try_peek_begin, depth, position)));
|
||||
|
||||
// copy data at the position to the buffer
|
||||
std::memcpy(buffer.get_ptr(), &queue->buffer[position * queue->size], queue->size);
|
||||
std::memcpy(buffer.get_ptr(), &queue->buffer[position % depth * queue->size], queue->size);
|
||||
|
||||
// clear first byte
|
||||
queue->ctrl &= { 0x00ffffff, 0xffffffffu };
|
||||
// ...peek_end
|
||||
queue->ctrl._and_not({ 0xff000000, 0 });
|
||||
|
||||
vm::notify_at(queue.addr(), 8);
|
||||
vm::notify_at(queue.ptr(&CellSyncQueue::ctrl));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -589,18 +589,18 @@ s32 cellSyncQueueTryPeek(vm::ptr<CellSyncQueue> queue, vm::ptr<void> buffer)
|
||||
|
||||
u32 position;
|
||||
|
||||
if (!queue->ctrl.atomic_op(&sync_queue_t::try_peek_begin, depth, position))
|
||||
if (!queue->ctrl.atomic_op(_sync::queue::try_peek_begin, depth, position))
|
||||
{
|
||||
return CELL_SYNC_ERROR_BUSY;
|
||||
}
|
||||
|
||||
// copy data at the position to the buffer
|
||||
std::memcpy(buffer.get_ptr(), &queue->buffer[position * queue->size], queue->size);
|
||||
std::memcpy(buffer.get_ptr(), &queue->buffer[position % depth * queue->size], queue->size);
|
||||
|
||||
// clear first byte
|
||||
queue->ctrl &= { 0x00ffffff, 0xffffffffu };
|
||||
// ...peek_end
|
||||
queue->ctrl._and_not({ 0xff000000, 0 });
|
||||
|
||||
vm::notify_at(queue.addr(), 8);
|
||||
vm::notify_at(queue.ptr(&CellSyncQueue::ctrl));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -619,9 +619,9 @@ s32 cellSyncQueueSize(vm::ptr<CellSyncQueue> queue)
|
||||
return CELL_SYNC_ERROR_ALIGN;
|
||||
}
|
||||
|
||||
queue->check_depth();
|
||||
const u32 depth = queue->check_depth();
|
||||
|
||||
return queue->ctrl.load().m_v2 & 0xffffff;
|
||||
return queue->ctrl.load().count & 0xffffff;
|
||||
}
|
||||
|
||||
s32 cellSyncQueueClear(PPUThread& ppu, vm::ptr<CellSyncQueue> queue)
|
||||
@ -638,15 +638,14 @@ s32 cellSyncQueueClear(PPUThread& ppu, vm::ptr<CellSyncQueue> queue)
|
||||
return CELL_SYNC_ERROR_ALIGN;
|
||||
}
|
||||
|
||||
queue->check_depth();
|
||||
const u32 depth = queue->check_depth();
|
||||
|
||||
vm::wait_op(ppu, queue.addr(), 8, WRAP_EXPR(queue->ctrl.atomic_op(&sync_queue_t::try_clear_begin_1)));
|
||||
vm::wait_op(ppu, queue.addr(), 8, WRAP_EXPR(queue->ctrl.atomic_op(_sync::queue::try_clear_begin_1)));
|
||||
vm::wait_op(ppu, queue.addr(), 8, WRAP_EXPR(queue->ctrl.atomic_op(_sync::queue::try_clear_begin_2)));
|
||||
|
||||
vm::wait_op(ppu, queue.addr(), 8, WRAP_EXPR(queue->ctrl.atomic_op(&sync_queue_t::try_clear_begin_2)));
|
||||
queue->ctrl.exchange({ 0, 0 });
|
||||
|
||||
queue->ctrl.exchange({});
|
||||
|
||||
vm::notify_at(queue.addr(), 8);
|
||||
vm::notify_at(queue.ptr(&CellSyncQueue::ctrl));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -715,7 +714,7 @@ s32 cellSyncLFQueueInitialize(vm::ptr<CellSyncLFQueue> queue, vm::cptr<void> buf
|
||||
}
|
||||
}
|
||||
|
||||
if (!depth || (depth >> 15) || direction > 3)
|
||||
if (!depth || depth > 0x7fff || direction > 3)
|
||||
{
|
||||
return CELL_SYNC_ERROR_INVAL;
|
||||
}
|
||||
@ -759,11 +758,9 @@ s32 cellSyncLFQueueInitialize(vm::ptr<CellSyncLFQueue> queue, vm::cptr<void> buf
|
||||
{
|
||||
if (sdk_ver > 0x17ffff)
|
||||
{
|
||||
auto data = vm::get_ptr<u64>(queue.addr());
|
||||
|
||||
for (u32 i = 0; i < sizeof(CellSyncLFQueue) / sizeof(u64); i++)
|
||||
for (const auto& data : vm::_ref<u64[16]>(queue.addr()))
|
||||
{
|
||||
if (data[i])
|
||||
if (data)
|
||||
{
|
||||
return CELL_SYNC_ERROR_STAT;
|
||||
}
|
||||
@ -798,7 +795,7 @@ s32 cellSyncLFQueueInitialize(vm::ptr<CellSyncLFQueue> queue, vm::cptr<void> buf
|
||||
{
|
||||
syncLFQueueInitialize(queue, buffer, size, depth, direction, eaSignal);
|
||||
|
||||
queue->init.exchange({});
|
||||
queue->init.exchange(0);
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
@ -1067,7 +1064,7 @@ s32 _cellSyncLFQueuePushBody(PPUThread& ppu, vm::ptr<CellSyncLFQueue> queue, vm:
|
||||
return CELL_SYNC_ERROR_ALIGN;
|
||||
}
|
||||
|
||||
const vm::var<s32> position(ppu);
|
||||
vm::var<s32> position;
|
||||
|
||||
while (true)
|
||||
{
|
||||
@ -1098,7 +1095,7 @@ s32 _cellSyncLFQueuePushBody(PPUThread& ppu, vm::ptr<CellSyncLFQueue> queue, vm:
|
||||
const s32 size = queue->m_size;
|
||||
const s32 pos = *position;
|
||||
const u32 addr = VM_CAST((u64)((queue->m_buffer.addr() & ~1ull) + size * (pos >= depth ? pos - depth : pos)));
|
||||
std::memcpy(vm::get_ptr<void>(addr), buffer.get_ptr(), size);
|
||||
std::memcpy(vm::base(addr), buffer.get_ptr(), size);
|
||||
|
||||
if (queue->m_direction != CELL_SYNC_QUEUE_ANY2ANY)
|
||||
{
|
||||
@ -1373,7 +1370,7 @@ s32 _cellSyncLFQueuePopBody(PPUThread& ppu, vm::ptr<CellSyncLFQueue> queue, vm::
|
||||
return CELL_SYNC_ERROR_ALIGN;
|
||||
}
|
||||
|
||||
const vm::var<s32> position(ppu);
|
||||
vm::var<s32> position;
|
||||
|
||||
while (true)
|
||||
{
|
||||
@ -1404,7 +1401,7 @@ s32 _cellSyncLFQueuePopBody(PPUThread& ppu, vm::ptr<CellSyncLFQueue> queue, vm::
|
||||
const s32 size = queue->m_size;
|
||||
const s32 pos = *position;
|
||||
const u32 addr = VM_CAST((u64)((queue->m_buffer.addr() & ~1) + size * (pos >= depth ? pos - depth : pos)));
|
||||
std::memcpy(buffer.get_ptr(), vm::get_ptr<void>(addr), size);
|
||||
std::memcpy(buffer.get_ptr(), vm::base(addr), size);
|
||||
|
||||
if (queue->m_direction != CELL_SYNC_QUEUE_ANY2ANY)
|
||||
{
|
||||
|
@ -29,123 +29,128 @@ enum
|
||||
CELL_SYNC_ERROR_NO_SPU_CONTEXT_STORAGE = 0x80410114,
|
||||
};
|
||||
|
||||
struct alignas(4) sync_mutex_t // CellSyncMutex sync var
|
||||
namespace _sync
|
||||
{
|
||||
be_t<u16> rel;
|
||||
be_t<u16> acq;
|
||||
|
||||
be_t<u16> acquire()
|
||||
struct alignas(4) mutex // CellSyncMutex control variable
|
||||
{
|
||||
return acq++;
|
||||
}
|
||||
be_t<u16> rel;
|
||||
be_t<u16> acq;
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
return acq++ == rel;
|
||||
}
|
||||
static inline be_t<u16> acquire(mutex& ctrl)
|
||||
{
|
||||
return ctrl.acq++;
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
rel++;
|
||||
}
|
||||
static inline bool try_lock(mutex& ctrl)
|
||||
{
|
||||
return ctrl.acq++ == ctrl.rel;
|
||||
}
|
||||
|
||||
static inline void unlock(mutex& ctrl)
|
||||
{
|
||||
ctrl.rel++;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
struct CellSyncMutex
|
||||
{
|
||||
atomic_t<_sync::mutex> ctrl;
|
||||
};
|
||||
|
||||
using CellSyncMutex = atomic_t<sync_mutex_t>;
|
||||
|
||||
CHECK_SIZE_ALIGN(CellSyncMutex, 4, 4);
|
||||
|
||||
struct alignas(4) sync_barrier_t // CellSyncBarrier sync var
|
||||
namespace _sync
|
||||
{
|
||||
be_t<s16> value;
|
||||
be_t<u16> count;
|
||||
|
||||
bool try_notify()
|
||||
struct alignas(4) barrier // CellSyncBarrier control variable
|
||||
{
|
||||
// extract m_value (repeat if < 0), increase, compare with second s16, set sign bit if equal, insert it back
|
||||
s16 v = value;
|
||||
be_t<s16> value;
|
||||
be_t<u16> count;
|
||||
|
||||
if (v < 0)
|
||||
static inline bool try_notify(barrier& ctrl)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (ctrl.value & 0x8000)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (++v == count)
|
||||
if (++ctrl.value == ctrl.count)
|
||||
{
|
||||
ctrl.value |= 0x8000;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
static inline bool try_wait(barrier& ctrl)
|
||||
{
|
||||
v |= 0x8000;
|
||||
if ((ctrl.value & 0x8000) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (--ctrl.value == -0x8000)
|
||||
{
|
||||
ctrl.value = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
value = v;
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
bool try_wait()
|
||||
{
|
||||
// extract m_value (repeat if >= 0), decrease it, set 0 if == 0x8000, insert it back
|
||||
s16 v = value;
|
||||
|
||||
if (v >= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (--v == -0x8000)
|
||||
{
|
||||
v = 0;
|
||||
}
|
||||
|
||||
value = v;
|
||||
|
||||
return true;
|
||||
}
|
||||
struct CellSyncBarrier
|
||||
{
|
||||
atomic_t<_sync::barrier> ctrl;
|
||||
};
|
||||
|
||||
using CellSyncBarrier = atomic_t<sync_barrier_t>;
|
||||
|
||||
CHECK_SIZE_ALIGN(CellSyncBarrier, 4, 4);
|
||||
|
||||
struct sync_rwm_t // CellSyncRwm sync var
|
||||
namespace _sync
|
||||
{
|
||||
be_t<u16> readers;
|
||||
be_t<u16> writers;
|
||||
|
||||
bool try_read_begin()
|
||||
struct rwlock // CellSyncRwm control variable
|
||||
{
|
||||
if (writers)
|
||||
be_t<u16> readers;
|
||||
be_t<u16> writers;
|
||||
|
||||
static inline bool try_read_begin(rwlock& ctrl)
|
||||
{
|
||||
return false;
|
||||
if (ctrl.writers)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ctrl.readers++;
|
||||
return true;
|
||||
}
|
||||
|
||||
readers++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool try_read_end()
|
||||
{
|
||||
if (!readers)
|
||||
static inline bool try_read_end(rwlock& ctrl)
|
||||
{
|
||||
return false;
|
||||
if (ctrl.readers == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ctrl.readers--;
|
||||
return true;
|
||||
}
|
||||
|
||||
readers--;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool try_write_begin()
|
||||
{
|
||||
if (writers)
|
||||
static inline bool try_write_begin(rwlock& ctrl)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (ctrl.writers)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
writers = 1;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
ctrl.writers = 1;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
struct alignas(16) CellSyncRwm
|
||||
{
|
||||
atomic_t<sync_rwm_t> ctrl; // sync var
|
||||
atomic_t<_sync::rwlock> ctrl;
|
||||
|
||||
be_t<u32> size;
|
||||
vm::bptr<void, u64> buffer;
|
||||
@ -153,110 +158,109 @@ struct alignas(16) CellSyncRwm
|
||||
|
||||
CHECK_SIZE_ALIGN(CellSyncRwm, 16, 16);
|
||||
|
||||
struct sync_queue_t // CellSyncQueue sync var
|
||||
namespace _sync
|
||||
{
|
||||
be_t<u32> m_v1;
|
||||
be_t<u32> m_v2;
|
||||
|
||||
bool try_push_begin(u32 depth, u32& position)
|
||||
struct queue // CellSyncQueue control variable
|
||||
{
|
||||
const u32 v1 = m_v1;
|
||||
const u32 v2 = m_v2;
|
||||
|
||||
// compare 5th byte with zero (break if not zero)
|
||||
// compare (second u32 (u24) + first byte) with depth (break if greater or equal)
|
||||
if ((v2 >> 24) || ((v2 & 0xffffff) + (v1 >> 24)) >= depth)
|
||||
union
|
||||
{
|
||||
return false;
|
||||
be_t<u32> x0;
|
||||
|
||||
bf_be_t<u32, 0, 24> next;
|
||||
bf_be_t<u32, 24, 8> _pop;
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
be_t<u32> x4;
|
||||
|
||||
bf_be_t<u32, 0, 24> count;
|
||||
bf_be_t<u32, 24, 8> _push;
|
||||
};
|
||||
|
||||
static inline bool try_push_begin(queue& ctrl, u32 depth, u32& position)
|
||||
{
|
||||
const u32 count = ctrl.count;
|
||||
|
||||
if (ctrl._push || count + ctrl._pop >= depth)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
position = ctrl.next;
|
||||
ctrl.next = position + 1 != depth ? position + 1 : 0;
|
||||
ctrl.count = count + 1;
|
||||
ctrl._push = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
// extract first u32 (u24) (-> position), calculate (position + 1) % depth, insert it back
|
||||
// insert 1 in 5th u8
|
||||
// extract second u32 (u24), increase it, insert it back
|
||||
position = (v1 & 0xffffff);
|
||||
m_v1 = (v1 & 0xff000000) | ((position + 1) % depth);
|
||||
m_v2 = (1 << 24) | ((v2 & 0xffffff) + 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool try_pop_begin(u32 depth, u32& position)
|
||||
{
|
||||
const u32 v1 = m_v1;
|
||||
const u32 v2 = m_v2;
|
||||
|
||||
// extract first u8, repeat if not zero
|
||||
// extract second u32 (u24), subtract 5th u8, compare with zero, repeat if less or equal
|
||||
if ((v1 >> 24) || ((v2 & 0xffffff) <= (v2 >> 24)))
|
||||
static inline bool try_pop_begin(queue& ctrl, u32 depth, u32& position)
|
||||
{
|
||||
return false;
|
||||
const u32 count = ctrl.count;
|
||||
|
||||
if (ctrl._pop || count <= ctrl._push)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ctrl._pop = 1;
|
||||
position = ctrl.next + depth - count;
|
||||
ctrl.count = count - 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
// insert 1 in first u8
|
||||
// extract first u32 (u24), add depth, subtract second u32 (u24), calculate (% depth), save to position
|
||||
// extract second u32 (u24), decrease it, insert it back
|
||||
m_v1 = 0x1000000 | v1;
|
||||
position = ((v1 & 0xffffff) + depth - (v2 & 0xffffff)) % depth;
|
||||
m_v2 = (v2 & 0xff000000) | ((v2 & 0xffffff) - 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool try_peek_begin(u32 depth, u32& position)
|
||||
{
|
||||
const u32 v1 = m_v1;
|
||||
const u32 v2 = m_v2;
|
||||
|
||||
if ((v1 >> 24) || ((v2 & 0xffffff) <= (v2 >> 24)))
|
||||
static inline bool try_peek_begin(queue& ctrl, u32 depth, u32& position)
|
||||
{
|
||||
return false;
|
||||
const u32 count = ctrl.count;
|
||||
|
||||
if (ctrl._pop || count <= ctrl._push)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ctrl._pop = 1;
|
||||
position = ctrl.next + depth - count;
|
||||
return true;
|
||||
}
|
||||
|
||||
m_v1 = 0x1000000 | v1;
|
||||
position = ((v1 & 0xffffff) + depth - (v2 & 0xffffff)) % depth;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool try_clear_begin_1()
|
||||
{
|
||||
if (m_v1 & 0xff000000)
|
||||
static inline bool try_clear_begin_1(queue& ctrl)
|
||||
{
|
||||
return false;
|
||||
if (ctrl._pop)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ctrl._pop = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
m_v1 |= 0x1000000;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool try_clear_begin_2()
|
||||
{
|
||||
if (m_v2 & 0xff000000)
|
||||
static inline bool try_clear_begin_2(queue& ctrl)
|
||||
{
|
||||
return false;
|
||||
if (ctrl._push)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ctrl._push = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
m_v2 |= 0x1000000;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
struct alignas(32) CellSyncQueue
|
||||
{
|
||||
atomic_t<sync_queue_t> ctrl;
|
||||
atomic_t<_sync::queue> ctrl;
|
||||
|
||||
be_t<u32> size;
|
||||
be_t<u32> depth;
|
||||
vm::bptr<u8, u64> buffer;
|
||||
be_t<u64> reserved;
|
||||
|
||||
u32 check_depth()
|
||||
u32 check_depth() const
|
||||
{
|
||||
const auto data = ctrl.load();
|
||||
|
||||
if ((data.m_v1 & 0xffffff) > depth || (data.m_v2 & 0xffffff) > depth)
|
||||
if (data.next > depth || data.count > depth)
|
||||
{
|
||||
throw EXCEPTION("Invalid queue pointers");
|
||||
}
|
||||
|
@ -148,9 +148,9 @@ void sysutilSendSystemCommand(u64 status, u64 param)
|
||||
{
|
||||
if (cb.func)
|
||||
{
|
||||
Emu.GetCallbackManager().Register([=](CPUThread& CPU) -> s32
|
||||
Emu.GetCallbackManager().Register([=](PPUThread& ppu) -> s32
|
||||
{
|
||||
cb.func(static_cast<PPUThread&>(CPU), status, param, cb.arg);
|
||||
cb.func(ppu, status, param, cb.arg);
|
||||
return CELL_OK;
|
||||
});
|
||||
}
|
||||
|
@ -138,7 +138,7 @@ next:
|
||||
|
||||
case vdecDecodeAu:
|
||||
{
|
||||
memcpy(buf, vm::get_ptr<void>(vdec.reader.addr), vdec.reader.size);
|
||||
std::memcpy(buf, vm::base(vdec.reader.addr), vdec.reader.size);
|
||||
|
||||
buf += vdec.reader.size;
|
||||
buf_size -= vdec.reader.size;
|
||||
@ -176,7 +176,7 @@ next:
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(buf, vm::get_ptr<void>(vdec.reader.addr), buf_size);
|
||||
std::memcpy(buf, vm::base(vdec.reader.addr), buf_size);
|
||||
|
||||
vdec.reader.addr += buf_size;
|
||||
vdec.reader.size -= buf_size;
|
||||
@ -767,7 +767,7 @@ s32 cellVdecGetPicture(u32 handle, vm::cptr<CellVdecPicFormat> format, vm::ptr<u
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellVdecGetPictureExt(PPUThread& ppu, u32 handle, vm::cptr<CellVdecPicFormat2> format2, vm::ptr<u8> outBuff, u32 arg4)
|
||||
s32 cellVdecGetPictureExt(u32 handle, vm::cptr<CellVdecPicFormat2> format2, vm::ptr<u8> outBuff, u32 arg4)
|
||||
{
|
||||
cellVdec.Warning("cellVdecGetPictureExt(handle=0x%x, format2=*0x%x, outBuff=*0x%x, arg4=*0x%x)", handle, format2, outBuff, arg4);
|
||||
|
||||
@ -776,7 +776,7 @@ s32 cellVdecGetPictureExt(PPUThread& ppu, u32 handle, vm::cptr<CellVdecPicFormat
|
||||
throw EXCEPTION("Unknown arguments (arg4=*0x%x, unk0=0x%x, unk1=0x%x)", arg4, format2->unk0, format2->unk1);
|
||||
}
|
||||
|
||||
const vm::var<CellVdecPicFormat> format(ppu);
|
||||
vm::var<CellVdecPicFormat> format;
|
||||
format->formatType = format2->formatType;
|
||||
format->colorMatrixType = format2->colorMatrixType;
|
||||
format->alpha = format2->alpha;
|
||||
@ -804,7 +804,7 @@ s32 cellVdecGetPicItem(u32 handle, vm::pptr<CellVdecPicItem> picItem)
|
||||
|
||||
AVFrame& frame = *vf.data;
|
||||
|
||||
const auto info = vm::ptr<CellVdecPicItem>::make(vdec->memAddr + vdec->memBias);
|
||||
const vm::ptr<CellVdecPicItem> info{ vdec->memAddr + vdec->memBias, vm::addr };
|
||||
|
||||
vdec->memBias += 512;
|
||||
if (vdec->memBias + 512 > vdec->memSize)
|
||||
@ -832,7 +832,7 @@ s32 cellVdecGetPicItem(u32 handle, vm::pptr<CellVdecPicItem> picItem)
|
||||
|
||||
if (vdec->type == CELL_VDEC_CODEC_TYPE_AVC)
|
||||
{
|
||||
auto avc = vm::ptr<CellVdecAvcInfo>::make(info.addr() + sizeof32(CellVdecPicItem));
|
||||
const vm::ptr<CellVdecAvcInfo> avc{ info.addr() + sizeof32(CellVdecPicItem), vm::addr };
|
||||
|
||||
avc->horizontalSize = frame.width;
|
||||
avc->verticalSize = frame.height;
|
||||
|
@ -429,7 +429,7 @@ s32 cellSurMixerCreate(vm::cptr<CellSurMixerConfig> config)
|
||||
|
||||
//u64 stamp2 = get_system_time();
|
||||
|
||||
auto buf = vm::get_ptr<be_t<float>>(port.addr + (g_surmx.mixcount % port.block) * port.channel * AUDIO_SAMPLES * sizeof(float));
|
||||
auto buf = vm::_ptr<f32>(port.addr + (g_surmx.mixcount % port.block) * port.channel * AUDIO_SAMPLES * sizeof(float));
|
||||
|
||||
for (auto& mixdata : g_surmx.mixdata)
|
||||
{
|
||||
|
@ -54,9 +54,9 @@ u32 ppu_get_tls(u32 thread)
|
||||
if (g_tls_owners[i].compare_exchange_strong(old, thread))
|
||||
{
|
||||
const u32 addr = g_tls_start + i * g_tls_size + TLS_SYS; // get TLS address
|
||||
memset(vm::get_ptr(addr - TLS_SYS), 0, TLS_SYS); // initialize system area with zeros
|
||||
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::memset(vm::base(addr - TLS_SYS), 0, TLS_SYS); // initialize system area with zeros
|
||||
std::memcpy(vm::base(addr), vm::base(Emu.GetTLSAddr()), Emu.GetTLSFilesz()); // initialize from TLS image
|
||||
std::memset(vm::base(addr + Emu.GetTLSFilesz()), 0, Emu.GetTLSMemsz() - Emu.GetTLSFilesz()); // fill the rest with zeros
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
@ -101,7 +101,7 @@ s32 sys_interrupt_thread_disestablish(PPUThread& ppu, u32 ih)
|
||||
{
|
||||
sysPrxForUser.Todo("sys_interrupt_thread_disestablish(ih=0x%x)", ih);
|
||||
|
||||
return _sys_interrupt_thread_disestablish(ppu, ih, vm::var<u64>(ppu));
|
||||
return _sys_interrupt_thread_disestablish(ppu, ih, vm::var<u64>{});
|
||||
}
|
||||
|
||||
s32 sys_process_is_stack(u32 p)
|
||||
|
@ -15,7 +15,7 @@ s32 sys_lwcond_create(vm::ptr<sys_lwcond_t> lwcond, vm::ptr<sys_lwmutex_t> lwmut
|
||||
{
|
||||
sysPrxForUser.Warning("sys_lwcond_create(lwcond=*0x%x, lwmutex=*0x%x, attr=*0x%x)", lwcond, lwmutex, attr);
|
||||
|
||||
lwcond->lwcond_queue = idm::make<lv2_lwcond_t>(attr->name_u64);
|
||||
lwcond->lwcond_queue = idm::make<lv2_lwcond_t>(reinterpret_cast<u64&>(attr->name));
|
||||
lwcond->lwmutex = lwmutex;
|
||||
|
||||
return CELL_OK;
|
||||
|
@ -35,7 +35,7 @@ s32 sys_lwmutex_create(vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwmutex_attri
|
||||
lwmutex->lock_var.store({ lwmutex_free, 0 });
|
||||
lwmutex->attribute = attr->recursive | attr->protocol;
|
||||
lwmutex->recursive_count = 0;
|
||||
lwmutex->sleep_queue = idm::make<lv2_lwmutex_t>(protocol, attr->name_u64);
|
||||
lwmutex->sleep_queue = idm::make<lv2_lwmutex_t>(protocol, reinterpret_cast<u64&>(attr->name));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
@ -121,7 +121,7 @@ namespace sys_net
|
||||
// TODO
|
||||
thread_local vm::ptr<_tls_data_t> g_tls_net_data{};
|
||||
|
||||
inline void initialize_tls()
|
||||
static void initialize_tls()
|
||||
{
|
||||
// allocate if not initialized
|
||||
if (!g_tls_net_data)
|
||||
@ -521,7 +521,7 @@ namespace sys_net
|
||||
{
|
||||
libnet.Warning("_sys_net_errno_loc()");
|
||||
|
||||
return &get_errno();
|
||||
return get_errno().ptr();
|
||||
}
|
||||
|
||||
s32 sys_net_set_resolver_configurations()
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
extern Module<> sysPrxForUser;
|
||||
|
||||
s32 sys_ppu_thread_create(PPUThread& ppu, vm::ptr<u64> thread_id, u32 entry, u64 arg, s32 prio, u32 stacksize, u64 flags, vm::cptr<char> threadname)
|
||||
s32 sys_ppu_thread_create(vm::ptr<u64> thread_id, u32 entry, u64 arg, s32 prio, u32 stacksize, u64 flags, vm::cptr<char> threadname)
|
||||
{
|
||||
sysPrxForUser.Warning("sys_ppu_thread_create(thread_id=*0x%x, entry=0x%x, arg=0x%llx, prio=%d, stacksize=0x%x, flags=0x%llx, threadname=*0x%x)", thread_id, entry, arg, prio, stacksize, flags, threadname);
|
||||
|
||||
@ -16,13 +16,8 @@ s32 sys_ppu_thread_create(PPUThread& ppu, vm::ptr<u64> thread_id, u32 entry, u64
|
||||
// (return CELL_ENOMEM if failed)
|
||||
// ...
|
||||
|
||||
const vm::var<ppu_thread_param_t> attr(ppu);
|
||||
|
||||
attr->entry = entry;
|
||||
attr->tls = 0;
|
||||
|
||||
// call the syscall
|
||||
if (s32 res = _sys_ppu_thread_create(thread_id, attr, arg, 0, prio, stacksize, flags, threadname))
|
||||
if (s32 res = _sys_ppu_thread_create(thread_id, vm::make_var(ppu_thread_param_t{ entry, 0 }), arg, 0, prio, stacksize, flags, threadname))
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ s32 sys_raw_spu_image_load(PPUThread& ppu, s32 id, vm::ptr<sys_spu_image> img)
|
||||
|
||||
const auto stamp0 = get_system_time();
|
||||
|
||||
memcpy(vm::get_ptr<void>(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id), vm::get_ptr<void>(img->addr), 256 * 1024);
|
||||
std::memcpy(vm::base(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id), vm::base(img->addr), 256 * 1024);
|
||||
|
||||
const auto stamp1 = get_system_time();
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "ErrorCodes.h"
|
||||
#include "LogBase.h"
|
||||
|
||||
|
@ -98,7 +98,7 @@ s32 sys_event_queue_create(vm::ptr<u32> equeue_id, vm::ptr<sys_event_queue_attri
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
const auto queue = Emu.GetEventManager().MakeEventQueue(event_queue_key, protocol, type, attr->name_u64, event_queue_key, size);
|
||||
const auto queue = Emu.GetEventManager().MakeEventQueue(event_queue_key, protocol, type, reinterpret_cast<u64&>(attr->name), event_queue_key, size);
|
||||
|
||||
if (!queue)
|
||||
{
|
||||
|
@ -54,12 +54,7 @@ struct sys_event_queue_attribute_t
|
||||
{
|
||||
be_t<u32> protocol; // SYS_SYNC_PRIORITY or SYS_SYNC_FIFO
|
||||
be_t<s32> type; // SYS_PPU_QUEUE or SYS_SPU_QUEUE
|
||||
|
||||
union
|
||||
{
|
||||
char name[8];
|
||||
u64 name_u64;
|
||||
};
|
||||
char name[8];
|
||||
};
|
||||
|
||||
struct sys_event_t
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user