vm::var improved, cleanup

Mostly vm::var initialization introduced.
Added vm::make_var function.
This commit is contained in:
Nekotekina 2015-09-26 23:46:04 +03:00
parent cc02a147d3
commit a974ee009e
116 changed files with 2763 additions and 3019 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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), &reg_value, d_size);
std::memcpy(vm::base_priv(addr), &reg_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();
}
}

View File

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

View File

@ -38,4 +38,4 @@ namespace memory_helper
munmap(pointer, size);
#endif
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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:
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,5 @@
#pragma once
#include "ErrorCodes.h"
#include "LogBase.h"

View File

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

View File

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